一次spark写入hbase延时问题的排查

来源:互联网 发布:关系图算法 编辑:程序博客网 时间:2024/06/04 01:22

总结一下工作中遇到一次spark写入hbase的超时问题。

业务场景是将kafka等数据源采集上来的用户日志数据经spark汇聚到hbase,然后再读出来供排序、算法评分等业务使用。先前使用时并未出现超时问题,但最近突然就出现了写入超时,下图中是spark任务调度ui页面,可以看出多个写入任务的时延明显增长。



最一开始是怀疑hbase集群出现问题,于是查找各个regionserver上的日志,但并没有发现任何异常。接着查看客户端日志,也没有异常出现。

接着怀疑随着数据写入的增多,region中残留大量的storeFile文件,造成了写延时的增高,于是对表进行了major_compact操作,但效果并不明显,任务重启后依然延时。

那会不会是数据量增多,而并发数没有相应的提高,造成写延时提高呢。基于如上的考虑,我们对表进行了split,将表的region个数扩充到2倍,表的region增多了,实际上提高了表对请求的吞吐量。而后,又提高了spark任务的并发量。我们期待着经过上述的改造,写延时能够得到缓解,但可惜。。。涛声依旧。

继续找吧,接下来我们先后怀疑了机器间网络连接的时延,集群gc等等方面的原因,但最终证明了并非上述原因所导致。

正当我们对问题一筹莫展的时候,我们想到了会不会是业务方的写入姿势不对造成了写延时的提高。

业务方的写入程序调用的是spark包装好的API,我们在测试集群中新建了一张表,将spark的写入任务重定向到这张新表中,下面是测试表的写入结果。


可以看出在新表中并未出现写延时提高的问题。

新表和老表的不同是什么,集群的配置都一样的,唯一的不同就是表本身。新表的region只有一个,而老表的region有将近400个,难道是region增多了反而降低了数据的写入性能。

val hbaseConf = HBaseConfiguration.create()val jobConf = new JobConf(hbaseConf, this.getClass)jobConf.setOutputFormat(classOf[TableOutputFormat])val hbaserdd = rdd.map(m=>{     val thePut = new Put(Bytes.toBytes(m._1))     thePut.add(Bytes.toBytes("familyname"),Bytes.toBytes("columnname"),Bytes.toByte(m._2))(new ImuutableBytesWriteable,ThePut)})new PairRDDFunctions(hbaserdd).saveAsHadoopDataset(jobConf)

m是一组数据片段,表示的一次写入的数据量的多少,这里面有个问题就是,m中的数据随机排列毫无顺序,如果直接调用saveAsHadoopDataset写入hbase,那么每次写入一个数据都需要重新定位该数据所在的region,那么整个批处理的大量时间就耗费在了region的重定位上。这也就是为什么新表一个region反而没有出现写延时的原因。因为随着写入量的增大,region的增多,重定位region的开销也在快速增长。

定位了原因,解决问题就很简单了,再将一批数据直接写入hbase前调用sort首先对其排序,排序后的相邻数据落在同一个region的概率大大增加。修改代码再次运行后,问题再未出现。

总结这次问题排查,最看似复杂的问题最后的原因往往非常简单明显。其次,数据库的问题不仅仅在于服务端本身参数调整,客户端的不合适使用方式同样会导致各种延时问题的出现。


0 0
原创粉丝点击