【Flink】第四篇:【迷思】对update语义拆解D-、I 后造成update原子性丢失
【Flink】第五篇:checkpoint【1】
【Flink】第五篇:checkpoint【2】 【Flink】第八篇:Flink 内存管理
【Flink】第九篇:Flink SQL 性能优化实战
【Flink】第十篇:join 之 regular join
【Flink】第十三篇:JVM思维导图
【Flink】第十四篇:LSM-Tree一般性总结
【Flink】第十五篇:Redis Connector 数据保序思考
【Flink】第十六篇:源码角度分析 sink 端的数据一致性
【Flink】第十七篇:记一次牛轰轰的OOM故障排查
【Flink】第十八篇:Direct Memory 一箩筐
最近,在用Flink SQL批量写HBase,做调度。主要遇到了三个大坑,在接下来的三篇文章中逐个记录。三个大坑分别是,
- HBase 写热点
- HBase gc 调优
- HBase Canary报警,Slow Read
这篇文章记录一下【HBase Canary报警,Slow Read】这个问题。整个过程及思路如下(我喜欢记录自己的思维过程,总觉得这个才是最值得我们练习的,而且对大家帮助相对于只记录一些程序或者命令要更大),
- 凯哥让瞅瞅 HBase Canary 警报
- CM(Cloudera Manager)发现原因:慢查询 Slow Read
- 问题归因:报警时间和Flink调度跑批基本一致
- 进一步分析:跑批写HBase为什么会影响其他HBase表的读?
- 批量写挤掉了同一个RS(RegionServer)上的BlockCache内存
- 批量写的网络IO吃掉了太多的带宽
- 批量写的磁盘IO吃掉了太多的磁盘IO资源
- HBase UI BlockCache 的配置分析:cache on write = false排除第一个原因
- CM分析慢查询数据所在RS的磁盘及网络IO:磁盘IO写峰值基本和报警时间一致
- 得出结论:磁盘IO导致慢查询
- 优化措施:批量写入无需WAL预写磁盘日志,需要修改HBase Connector源码中在HBase API层面的实现:Mutation.writeToWAL(false).
- 反手就是一个Flink issue(new feature)
下面说说其中的一些重要细节。
HBase Region Health Canary报告明细
CM(Cloudera Manager)发现原因:慢查询 Slow Read,HBaseCanary会周期性的抽样查询各个表的数据,以此监控HBase集群的Region的Read性能。
批量写HBase为什么会影响其他HBase表的读
参考之前写的 【Flink】第十四篇:LSM-Tree一般性总结 中的框架图:
在HBase中无非就是磁盘(WAL、StoreFile)、读缓存(BlockCache)、写缓存(memStore)存着我们的数据,注意这里说是写缓存,只是说主要功能是写缓存,但是HBase的读也是会从写缓存中去取数据的,而读缓存是同样,写数据时同样有可能写入BlockCache。
这个也是排除我们分析的可能原因的关键。
分析BlockCache的对于批量写的影响
我们知道BlockCache是RS层面的,一个RS只有一个BlockCache,而如果这个RS上有表的Region正在被批量写,如果BlockCache会被写时存入,那么也一定会影响其他表的数据放入BlockCache,影响了BlockCache的命中率。
基于这样一种思路,又分析了HBase的配置,发现cache on write配置为false,
分析慢查询发生的RS的磁盘IO及网络IO
从CM里分析IO延迟情况如下,
IO延迟的峰值在凌晨3点左右,和报警的时间是一致的,得出结论:批量入数,导致磁盘IO资源紧张,进而导致慢查询。
优化措施
我们知道写HBase会先写WAL,批量这种可re-run的任务如果能用上取消WAL磁盘预写日志那真是很妙了。
查阅HBase官网,看来我的思路没有跑偏:
70.6.10. Disabling the WAL
It is possible to disable the WAL, to improve performance in certain specific situations. However, disabling the WAL puts your data at risk. The only situation where this is recommended is during a bulk load. This is because, in the event of a problem, the bulk load can be re-run with no risk of data loss. The WAL is disabled by calling the HBase client field Mutation.writeToWAL(false). Use the Mutation.setDurability(Durability.SKIP_WAL) and Mutation.getDurability() methods to set and get the field’s value. There is no way to disable the WAL for only a specific table.
http://hbase.apache.org/2.3/book.html#hbase_default_configurations
但是HBase只在API层面允许对每一个Mutation进行控制是否预写日志WAL,所以我们只能修改Flink Hbase Connector或者提issue,于是就有了这个JIRA:
https://issues.apache.org/jira/browse/FLINK-23719