几个优化问题
设计原则
设置预分区
HBase默认新建的表中只有一个
HRegion
,而且这个HRegion
是没有边界的,也就是没有[startRowKey, endRowKey)
的存在,所有的读写都集中在这个HRegion
上。当
HRegion
大小超过预定的阈值时,HRegion
会进行分裂(Split
)。所以
读写热点
问题和分裂时的I/O
问题都会影响HBase的性能。因此,可以在建表时创建多个空的
HRegion
,并确定每个HRegion
的起点和终点。只要RowKey
设计合理,就能让数据均匀地分布在HRegion
之中,解决上面的两个问题。这种预先创建空
HRegion
的方式,就叫预分区
。
# 定义5个预分区:0~100,100~200,200~300,300~400,400~
hbase:001:0> create 'user', 'info', SPLITS=>['100','200','300','400']
预分区信息可以在HBase Web UI Table Regions中看到。
RowKey的设计
RowKey
长度原则:越短越好,不要超过16个字节,建议设计为定长。因为它的长度直接决定HFile
、MemStore
的存储和查询效率。RowKey
散列原则:为避免数据热点问题,最好将RowKey
数据转换成Hash
值。例如,如果RowKey
为手机号,那么可以这样保存。将手机号反转,将最后一位作为
RowKey
的第一位,这样就可以让RowKey
比较均匀地分布在0
~9
开头的HRegion
中。取手机号全部位数或者后4位做取模运算,然后将余数作为
RowKey
。需要能够通过这个余数反推出手机号,否则找不到数据。
RowKey
唯一原则:如果RowKey
相同,数据会被直接覆盖,而不是像MySQL那样报错。RowKey
设计得是否合理可以通过HBase Web UI Table Regions中表头的ReadRequests
和WriteRequests
数据观察到。设计不合理的
RowKey
,它的每个HRegion
的ReadRequests
(或者WriteRequests
)之间的数据必然相差巨大,也就是会出现数据热点问题,否则这些数据会是比较均匀的,数值都相差不大。ReadRequests
和WriteRequests
只在当次HBase集群运行时有效,一旦HBase集群重启,ReadRequests
和WriteRequests
的数值会被清零。
列族的设计
把经常读取的字段存储到一个列族中,不经常读取的存到另一个列族中。
列族名避免过长或包含特殊字符。
限制列族的数量。
列族只保留必要的版本,过多的版本会占用更多的存储空间,并降低读取性能。
批量处理
当数据量不大而想要导入、导出或删除的时候,除了可以利用之前的代码和HBase自带的工具类外,还可以这样做。
调用
Table.get(List<Get>)
方法,一次性读取一批数据。调用
Table.put(List<Put>)
方法,一次性写入一批数据。调用
Table.delete(List<Delete>)
方法,一次性删除一批数据。
核心参数优化
hbase.hregion.majorcompaction
:设置HFile
大合并的间隔时间,默认为604800000毫秒(7天)
,可设置为0,禁止自动大合并,因为大合并的执行过程可能会持续数小 时。为减少对业务的影响,建议在业务低谷期手动,或者通过脚本,或者API定期执行。hbase.hregion.max.filesize
: 默认值为10737418240 Byte(10G)
,当HRegion
达到这个阈值时,会自动分裂。HRegion
分裂时会有短暂的下线时间(通常在5秒 以内)。为减少对业务端的影响,建议调大该值,并在业务低谷期定时手动执行分裂。hbase.regionserver.handler.count
:handler
用于实现底层数据的发送,默认每批次发送30条。对于大量数据的Put
(达到了百万级别)操作或是大范围的Scan
操作,handler
数目不要过大,否则容易造成OOM(内存溢出)
。而对于小负载的put
、get
,delete
等操作,handler
则可以适当调大。hbase.hregion.memstore.flush.size
: 默认134217728 Byte(128MB)
,这个参数是MemStore
数据持久化到HStoreFile
的时机,超过该阈值,则会触发数据持久化操作。如果HRegionServer
的内存充足,则可以适当调大该值,这样可以减少MemStore
的数据溢写文件的次数。hbase.hregion.memstore.block.multiplier
: 默认值为4,如果一个MemStore
的内存大小已经超过hbase.hregion.memstore.flush.size
×hbase.hregion.memstore.block.multiplier
,则 会阻塞该MemStore
的写操作。为避免阻塞,可以适当调大,例如6~8。但如果太大,则又有OOM
的风险。如果在HRegionServer
日志中出现"Blocking updates for ‘’ on region :memstoresize <?M> is >= than blocking <?M> size"
的信息时,说明这个值该调整了。hbase.hstore.compaction.min
:默认值为3,如果任何一个Store
里的HStoreFile
总数超过该值,就会触发合并操作,可以设置为5~8,并在手动的定期大合并中进行HStoreFile
文件的合并,减少合并的次数,不过这会延长合并的时间。hbase.rpc.timeout
:Scan
大表时的超时时间,可以适当调大。
这些参数都可以在${HBASE_HOME}/conf/hbase-site.xml
中修改。
其他问题
统一各个系统的字符集,非
utf8
都要统一成utf8
。HBase第一次执行查询时会很慢,建议提前初始化链接。
每日全量数据入库,数据实际发生变化的条数不多,可以用
day2
的数据和day1
的数据做对比,只入库发生变化的数据。对表做预分区,同时
RowKey
做MD5 Hash
取余。
感谢支持
更多内容,请移步《超级个体》。