Storm批处理事务原理详解

事务:Storm容错机制通过一个系统级别的组件acker,结合xor校验机制判断一个tuple是否发送成功,进而spout可以重发该tuple ,保证一个tuple在出错的情况下至少被重发一次。

在需要精确统计tuple的数量如销售金额场景时,希望每个tuple”被且仅被处理一次” 。Storm 0.7.0引入了Transactional Topology, 它可以保证每个tuple”被且仅被处理一次”, 这样我们就可以实现一种非常准确,且高度容错方式来实现计数类应用。


批处理:
事务处理单个tuple效率比较低,逐个处理单个tuple,增加很多开销,如写库、输出结果频率过高因此storm中引入batch处理,批处理是一次性处理一批(batch)tuple,事务可确保该批次要么全部处理成功,如果有处理失败的则全部不计,Storm会对失败的批次重新发送,且确保每个batch被且仅被处理一次。


事务机制原理:Storm事务处理中,把一个batch的计算分成了两个阶段processing和commit阶段:Processing 阶段:多个batch可以并行计算;Commiting阶段:batch之间强制按照顺序进行提交

举例:

Processing 阶段:多个batch可以并行计算,上面例子中bolt2是普通的batchbolt(实现IBatchBolt),那么多个batch在 bolt2的task之间可以并行执行.

Commiting阶段:batch之间强制按照顺序进行提交,上图中Bolt3实现IBatchBolt并且标记需要事务处理的(实现了ICommitter接口或者通过TransactionalTopologyBuilder的setCommitterBolt方法把BatchBolt添加到topology里面),那么在Storm认为可以提交batch的时候调用 finishbatch,在finishBatch做txid的比较以及状态保存工作。例子中batch2必须等待batch1提交后,才可以进行提交。


对于只处理一次的需要:从原理上来讲,需要在发送tuple的时候带上txid,在需要事务处理的时候,根据该txid是否以前已经处理成功来决定是否进行处理,当然需要把txid和处理结果一起做保存。
在事务batch处理中:一批tuple赋予一个txid,为了提高batch之间处理的并行度,storm采用了pipeline(管道)处理模型,这样多个事务可以并行执行,但是commit的是严格按照顺序的。



事务Topology 实现
1、事务spout实现

事务性的spout需要实现ITransactionalSpout,这个接口包含两个内部接口类Coordinator和Emitter。在topology运行的时候,事务性的spout内部包含一个子Topology,结构图如下:


这里面有两种类型的tuple,一种是事务性的tuple,一种是batch中的tuple;
   coordinator 开启一个事务准备发射一个batch时候,进入一个事务的processing阶段,会发射一个事务性 tuple(transactionAttempt & metadata)到”batch emit”流
   Emitter以all grouping(广播)的方式订阅coordinator的”batch emit”流,负责为每个batch实际发射tuple。发送的tuple都必须以TransactionAttempt作为第一个field,storm根据这个field来判断tuple属于哪一个batch。
coordinator只有一个,emitter根据并行度可以有多个实例


TransactionAttempt 和 元数据
 TransactionAttempt包含两个值:一个transaction id,一个attempt id。transaction id的作用就是我们上面介绍的对于每个batch中的tuple是唯一的,而且不管这个batch    replay多少次都是一样的。
attempt id是对于每个batch唯一的一个id, 但是对于同一个batch,它replay之后的attempt id跟replay之前就不一样了,我们可以把attempt id理解成replay-times, storm利用这个id来区别一个batch发射的tuple的不同版本

  metadata(元数据)中包含当前事务可以从哪个point进行重放数据,存放在zookeeper中的,spout可以通过Kryo从zookeeper中序列化和反序列化该元数据。

事务内部处理流程图



2、事务性Bolt
BaseTransactionalBolt
处理batch在一起的tuples,对于每一个tuple调用调用execute方 法,而在整个batch处理(processing)完成的时候调用finishBatch方法。如果BatchBolt被标记成Committer,则 只能在commit阶段调用finishBatch方法。一个batch的commit阶段由storm保证只在前一个batch成功提交之后才会执行。并且它会重试直到topology里面的所有bolt在commit完成提交。那么如何知道batch的processing完成了,也就是bolt是否接收处理了batch里面所有的tuple;在bolt内部,有一个 CoordinatedBolt的模型。

CoordinateBolt具体原理如下:

每个CoordinateBolt记录两个值:有哪些task给我发送了tuple(根据topology的grouping信息);我要给哪些task发送信息(同样根据groping信息)。

等所有的tuple都发送完了之后,CoordinateBolt通过另外一个特殊的stream以emitDirect的方式告诉所有它发送过 tuple的task,它发送了多少tuple给这个task。下游task会将这个数字和自己已经接收到的tuple数量做对比,如果相等,则说明处理 完了所有的tuple。

下游CoordinateBolt会重复上面的步骤,通知其下游。







猜你喜欢

转载自javafu.iteye.com/blog/2375165
今日推荐