4.写优化
4.1增大MemStore的内存
面对「写多读少」的场景, 可以考虑调高MemStore 的内存占比,降低BlockCache的内存占比,跟读优化3.1的思路正好相反。
具体可以根据读写比例来评估。
4.2适当增加HFile产生
本条与3.2并不冲突,需要权衡
数据写入过程中,MemStore在满足一定条件时会flush刷写到磁盘,生成一个HFile文件。当一个Store下的HFile文件数量大于某个阈值时,就会引起写入或更新阻塞。
RS日志中会有类似 “has too many store files...” 的信息。当出现这种情况时,需要等待Compaction合并以减少HFile数量,这里主要是Minor Compaction即小合并。
所以我们尽量调大这个阈值,减少compaction。
核心参数:
- hbase.hstore.blockingStoreFiles = 100
如果写很快,很容易带来大量的HFile,因为此时HFile合并的速度还没有写入的速度快。
需要在业务低峰期做major compaction,充分利用系统资源。如果HFile降低不下来,则需要添加节点。
4.3适当增大Memstore阻塞倍数
当MemStore大小达到刷写阈值(
hbase.hregion.memstore.flush.size,默认128M)时,就会flush刷写到磁盘,这个操作基本没有阻塞。但当一个Region的所有MemStore大小达到一个阻塞倍数(hbase.hregion.memstore.block.multiplier,默认值为4,即4倍的刷写阈值 默认4*128=512M)时,就会阻塞该Region所有的更新请求,并强制flush。客户端可能会抛出RegionTooBusyException异常。
为了尽量避免写入阻塞,可以适当调整这两个参数
核心参数包括:
- hbase.hregion.memstore.flush.size = 128 - hbase.hregion.memstore.block.multiplier = 4
5.IO优化
HBase利用compaction机制,通过大量的读延迟毛刺和一定的写阻塞,来换取整体上的读取延迟的平稳。
为了综合权衡 性能 与 稳定性,需要对compation做限速处理。
核心调整参数如下:
- hbase.offpeak.end.hour = 6 //允许不限速compact的结束时间 - hbase.offpeak.start.hour = 22 //允许不限速compact的开始时间 - hbase.hstore.compaction.throughput.higher.bound = 15728640 //限速compact最大为15M - hbase.hstore.compaction.throughput.lower.bound = 10485760 //限速compact最小为10M - hbase.hregion.majorcompactio = 0 //关闭定时major compaction - hbase.regionserver.thread.compaction.large = 1 //compation线程 - hbase.regionserver.thread.compaction.small = 1//compaction线程 - hbase.hstore.compaction.max = 3 //一次Minor Compaction最多合并的HFile文件数
需要注意的是,白天compaction限速,并且关闭了定时major compaction后,可能会导致HFile合并不足,因此,可以考虑外部控制(如java api)定时在夜间做major compaction来减少HFile数量。
6.故障恢复优化
引起RegionServer宕机的原因各种各样,有因为Full GC导致、网络异常导致、官方Bug导致(close wait端口未关闭)以及DataNode异常导致等等。
这些场景下一旦RegionServer发生宕机,HBase都会马上检测到这种宕机,并且在检测到宕机之后会将宕机RegionServer上的所有Region重新分配到集群中其他正常RegionServer上去,再根据HLog进行丢失数据恢复,恢复完成之后就可以对外提供服务,整个过程都是自动完成的,并不需要人工介入。基本原理如下图所示:
当datanode异常时,如果读取超时设置过大(dfs.client.socket-timeout和dfs.socket.timeout),region无法正常读取WAL日志,就会导致恢复耗时增加。
核心参数如下:
- dfs.client.socket-timeout = 60000 - dfs.datanode.socket.write.timeout = 480000 - dfs.socket.timeout = 60000
7.其他优化
7.1split策略
HBase 2.0.0 以上版本采用的 split 策略是 SteppingSplitPolicy。
SteppingSplitPolicy 在初期 region 数量较少的时候,split 的阈值较低,会比较频繁地触发 split。
我们已经给表做了预分区,所以可以将split策略设置为固定大小(大小由参数
hbase.hregion.max.filesize 决定)
核心参数:
- hbase.regionserver.region.split.policy = org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy
7.2开启rsgroup
rsgroup对于扩缩容等运维操作有很大的帮助,可以很好的控制region移动造成的影响。move_servers_rsgroup 命令的 for 循环里会将 region 逐个移动。
- hbase.coprocessor.master.classes = org.apache.hadoop.hbase.rsgroup.RSGroupAdminEndpointhbase.master.loadbalancer.class = org.apache.hadoop.hbase.rsgroup.RSGroupBasedLoadBalancer
另外,为了避免rs故障导致的meta表的「重试风暴」,region漂移失败(异常opening状态),可以给meta表设置独立的rsgroup,与业务rsgroup进行隔离。同时,增大meta表的handler数量。
- hbase.regionserver.metahandler.count = 400 //建议根据客户端数量进行评估设置
8.小结
本文从HBase「基础架构」出发,梳理各个组件、读写流程的参数调优,期望能满足「在线业务」的 高可用、低抖动 的需求。
如果你有其他优化经验,欢迎留言评论。