在做流式计算过程中,最复杂最难做的莫过于数据幂等性修改操作的设计。先解释一下概念【幂等性操作】,幂等性概念来源于数学专业表示对一个表达式做多次相同的操作,表达式不会改变。例如:逻辑回归中的Sigmod函数,n次求导之后依然坚挺。在流式计算中容错设计也要求工程设计有数据幂等性设计,特别针对流式计算中对第三方存储平台的修改操作。以及更加逆天的场景:在一个业务线有多个点有批量的数值修改操作,只要有一个点没有修改完成,而此时流式计算崩溃,下次重启都要做所有点的数据恢复操作。
说到幂等性,不得不说一下spark中的一个优化操作---推测执行。推测执行设计的初衷是提高作业的执行效率,避免某一个任务因为硬件问题卡死而拖慢整个计算任务。大致设计思想时,在任务完成达到某个百分比,开始检查任务完成情况,如果发现某任务执行时间超过其他任务耗时均值的阈值倍数,就在其他节点重启相同的计算任务,这样可以有效避免因硬件问题造成的卡死现象。但是在流式计算中对于修改数值的操作或者在mappartion/foreachPartition中自定义数据持久化到非主键约束的平台时,就会出现灾难性后果。一旦出现数据倾斜,启动备用线程执行当前任务,就会出现数据加倍等脏数据。所以在以上场景,无法保证操作幂等性的前提下,不要开启推测执行。
今天着重分享对于hbase的幂等性修改的设计
因为hbase数据有rowKey这种类似唯一主键的约束,数据覆盖写这种操作很很容易就能实现。即使出现一批数据没有完全写完,出现流式计算崩溃,这种场景也没有问题,下次重启再写一次覆盖就可以了,不会出现脏数据。但是对于修改操作,多个线程并行修改,只要有一个没有完成,系统挂掉,在重启之前需要将上个批次没有修改完成的数据回复到最后一次修改完成的状态。
这个主要设计方案是:
1.在流式计算中设置并持久化 批次号(从0开始,每个批次完成是批次号加一)
2.在写hbase时,除了正常修改的数据外,再写一列附属列用来保存当前批次号和当前批次修改的字段名称
3.优化操作:(每个批次在修改hbase之前,将当前使用批次使用的所有rowkey持久化(hdfs或者kafka=>hdfs(为了尽量减少直接写hdfs影响执行速度)),写成功后删除上次保存的rowkey(如果通过kafka写,rowkey+批次号,删除小于当前批次号的数据)
4. 重启流式计算前,读取最后一次保存的rowkey。按照rowkey到hbase中查询出相关的数据,根据附属列中记录的上一次批次修改的列,将相关的cell用上一个版本(hbase cell默认保存三个版本)的数据覆盖当前的数据。这个操作可以和流式计算分开,也可以和流式计算写到一起
5.然后开始开始启动流式计算(接着从上次保存的offset+1的位置),接着处理数据
————————————————
版权声明:本文为CSDN博主「sunkl_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010990043/java/article/details/83144345