前言
本系列接【HBase入门】系列文章后实战案例的学习。
学习目标
能够掌握HBase表结构设计(表设计、ROWKEY设计、预分区)
能够安装部署Apache Phoenix
能够掌握Phoenix的基本操作
能够掌握使用Phoenix建立二级索引提升性能
能够基于Phoenix JDBC API编写Java代码操作HBase
1. 案例介绍
在陌陌中,每天都有数千万的用户聊天消息需要存储。而且,这些消息都是需要进行大量地保存,而读取会少很多。想想:我们在使用微信的时候,大多数时候,我们都是在发消息,而不是每时每刻查询历史消息。要存储这样海量的数据,HBase就非常适合了,HBase本身也非常适合存储这种写多读少的应用场景。本案例,将结合陌陌聊天业务背景,以HBase来存储海量的数据。
通过本案例,我们能学习到以下知识点:
- HBase表的设计——涵盖HBase表预分区、ROWKEY设计
- HBase调优
- 使用Apache Phoenix SQL查询引擎
- 基于HBase的分页查询
- 数据查询接口开发
2. 打招呼消息数据集介绍
字段名 | 说明 |
---|---|
msg_time | 消息时间 |
sender_nickyname | 发件人昵称 |
sender_account | 发件人账号 |
sender_sex | 发件人性别 |
sender_ip | 发件人IP |
sender_os | 发件人系统 |
sender_phone_type | 发件人手机型号 |
sender_network | 发件人网络制式 |
sender_gps | 发件人GPS |
receiver_nickyname | 收件人昵称 |
receiver_ip | 收件人IP |
receiver_account | 收件人账号 |
receiver_os | 收件人系统 |
receiver_phone_type | 收件人手机型号 |
receiver_network | 收件人网络制式 |
receiver_gps | 收件人GPS |
receiver_sex | 收件人性别 |
msg_type | 消息类型 |
distance | 双方距离 |
message | 消息 |
3. 准备工作
创建IDEA Maven项目
groupId | cn.itcast |
---|---|
artifactId | momo_chat_app |
在项目中创建存放hbase shell脚本目录
在项目下创建名为 hbase_shell 的目录,再创建一个 readme.md 文件。
readme.md中写入如下:
# 陌陌海量消息存储说明文档
## 1. 项目结构说明
* hbase_shell:用于存放hbase shell操作脚本
* momo_chat_app:Java API数据接口
创建脚本文件
在hbase_shell下创建名为 create_ns_table.rb 文件,用于编写Hbase相关脚本,并使用VSCode打开项目文件夹。
4. 陌陌消息HBase表结构设计
4.1 名称空间
说明
- 在一个项目中,需要使用HBase保存多张表,这些表会按照业务域来划分
- 为了方便管理,不同的业务域以名称空间(namespace)来划分,这样管理起来会更加容易
- 类似于Hive中的数据库,不同的数据库下可以放不同类型的表
- HBase默认的名称空间是「default」,默认情况下,创建表时表都将创建在 default 名称空间下
- HBase中还有一个命名空间「hbase」,用于存放系统的内建表(namespace、meta)
语法- 创建命名空间
create_namespace 'MOMO_CHAT'
- 查看命名空间列表
list_namespace
- 查看命名空间
describe_namespace 'MOMO_CHAT'
- 命名空间创建表
在命令MOMO_CHAT命名空间下创建名为:MSG的表,该表包含一个名为C1的列蔟。
注意:带有命名空间的表,使用冒号将命名空间和表名连接到一起。
create 'MOMO_CHAT:MSG','C1'
- 删除命名空间
删除命名空间,命名空间中必须没有表,如果命名空间中有表,是无法删除的
drop_namespace 'MOMO_CHAT'
- 创建命名空间
4.2 列蔟设计
- HBase列蔟的数量应该越少越好
- 两个及以上的列蔟HBase性能并不是很好
- 一个列蔟所存储的数据达到flush的阈值时,表中所有列蔟将同时进行flush操作
- 这将带来不必要的I/O开销,列蔟越多,对性能影响越大
- 本次项目中我们只设计一个列蔟:C1
4.3 版本设计
说明
此处,我们需要保存的历史聊天记录是不会更新的,一旦数据保存到HBase中,就不会再更新
无需考虑版本问题
本次项目中只保留一个版本即可,这样可以节省大量空间
HBase默认创建表的版本为1,故此处保持默认即可
查看表
通过以下输出可以看到:
版本是相对于列蔟而言
默认列蔟的版本数为1
hbase(main):015:0> describe "MOMO_CHAT:MSG"
Table MOMO_CHAT:MSG is ENABLED
MOMO_CHAT:MSG
COLUMN FAMILIES DESCRIPTION
{NAME => 'C1', VERSIONS => '1', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_BEHAVIOR => 'false', KEEP_DELETED_CELLS => 'FALSE', CACHE_DATA_ON_WRITE => 'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', REPLI
CATION_SCOPE => '0', BLOOMFILTER => 'ROW', CACHE_INDEX_ON_WRITE => 'false', IN_MEMORY => 'false', CACHE_BLOOMS_ON_WRITE => 'false', PREFETCH_BLOCKS_ON_OPEN => 'false', COMPRESSION => 'NONE', BLOCKCACHE => 'true', BLOCKSIZE => '65536'}
1 row(s)
4.4 数据压缩
压缩算法
在HBase可以使用多种压缩编码,包括LZO、SNAPPY、GZIP。只在硬盘压缩,内存中或者网络传输中没有压缩。
压缩算法 | 压缩后占比 | 压缩 | 解压缩 |
---|---|---|---|
GZIP | 13.4% | 21 MB/s | 118 MB/s |
LZO | 20.5% | 135 MB/s | 410 MB/s |
Zippy/Snappy | 22.2% | 172 MB/s | 409 MB/s |
- GZIP的压缩率最高,但是其实CPU密集型的,对CPU的消耗比其他算法要多,压缩和解压速度也慢;
- LZO的压缩率居中,比GZIP要低一些,但是压缩和解压速度明显要比GZIP快很多,其中解压速度快的更多;
- Zippy/Snappy的压缩率最低,而压缩和解压速度要稍微比LZO要快一些
本案例采用GZ算法,这样可以确保的压缩比最大化,更加节省空间
查看表数据压缩方式
通过以下输出可以看出,HBase创建表默认是没有指定压缩算法的
hbase(main):015:0> describe "MOMO_CHAT:MSG"
Table MOMO_CHAT:MSG is ENABLED
MOMO_CHAT:MSG
COLUMN FAMILIES DESCRIPTION
{NAME => 'C1', VERSIONS => '1', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_BEHAVIOR => 'false', KEEP_DELETED_CELLS => 'FALSE', CACHE_DATA_ON_WRITE => 'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', REPLI
CATION_SCOPE => '0', BLOOMFILTER => 'ROW', CACHE_INDEX_ON_WRITE => 'false', IN_MEMORY => 'false', CACHE_BLOOMS_ON_WRITE => 'false', PREFETCH_BLOCKS_ON_OPEN => 'false', COMPRESSION => 'NONE', BLOCKCACHE => 'true', BLOCKSIZE => '65536'}
1 row(s)
设置数据压缩
本案例中,我们使用GZ压缩算法,语法如下:
- 创建新的表,并指定数据压缩算法
create "MOMO_CHAT:MSG", {NAME => "C1", COMPRESSION => "GZ"}
- 修改已有的表,并指定数据压缩算法
alter "MOMO_CHAT:MSG", {NAME => "C1", COMPRESSION => "GZ"}