storm的acker机制

1、简介:

storm中有一个很重要的特性:
保证发出的每一个tuple都会被完整处理。一个tuple被彻底处理的意思是: 这个tuple以及由这个tuple所产生的全部的子tuple都被成功处理。若是任一个消息在timeout所指定的时间内没有完成处理,那这个tuple就失败了。算法

2、原理:

acker并不会为每一个tuple都分配内存空间来完成跟踪,而是利用了一个很是巧妙的算法,这个算法只需使用恒定的20字节就能够完成整个tuple树的跟踪数据结构

具体原理:

acker对于每一个spout-tuple保存一个ack-val的校验值,它的初始值是0, 而后每发射一个tuple/ack一个tuple,那么tuple的id都要跟这个校验值异或一下,
而且把获得的值更新为ack-val的新值。那么假设每一个发射出去的tuple都被ack了, 那么最后ack-val必定是0(由于一个数字跟本身异或获得的值是0)。 spa

通俗理解:

1. 在spout产生一条tuple时,会向acker发送一条信息,让ack来进行跟踪orm

消息内容:{spout-tuple-id {:spout-task task-id :val ack-val}}
spout-tuple-id:这条tuple的id,每条tuple都会产生一个随机的MessageId
task-id:产生这条tuple的id,spout可能有多个task,每一个task都会被分配一个惟一的taskId
ack-val:默认值为0,用来跟踪tuple队列

2. acker会在本身的map(类型为TimeCacheMap)里保存这条记录。 这就是acker对spout-tuple进行跟踪的核心数据结构, 对于每一个spout-tuple所产生的tuple树的跟踪
都只须要保存上面这条记录。acker后面会检查:val何时变成0,变成0, 说明这个spout-tuple产生的tuple都处理完成了。内存

3. spout在发送完消息给acker后会将该tuple和MessageId发送到boltTask。boltTask在建立子tuple时并不会向acker发送消息让其跟踪,而是很巧妙的省略了这一步。
bolt在发射一个新的bolt的时候会把这个新tuple跟它的父tuple的关系保存起来(strom称之为anchoring)。而后在ack tuple的时候,storm会把要ack的tuple的id, 以及这个tuple新建立的全部的tuple的id的异或值发送给acker。消息格式是:(spout-tuple-id,tmp-ack-val)执行完这一步后,ack-val的值就变成了全部子tuple的id的异或值
ps:storm使用一致性哈希来把一个spout-tuple-id对应到acker, 由于每个tuple知道它全部的祖宗的tuple-id, 因此它天然能够算出要通知哪一个acker来ack。it

4. 当全部子tuple都被ack以后,val会被异或成0,OK 整个tuple树执行跟踪完成。 原理

场景分析:

1. 因为对应的task挂掉了,一个tuple没有被ack: storm的超时机制在超时以后会把这个tuple标记为失败,从而能够从新处理。 map

2. Acker挂掉了: 这种状况下由这个acker所跟踪的全部spout tuple都会超时,也就会被从新处理。 im

3. Spout挂掉了: 在这种状况下给spout发送消息的消息源负责从新发送这些消息。好比Kestrel和RabbitMQ在一个客户端断开以后会把全部”处理中“的消息放回队列。 因而可知storm的高度容错性。

相关文章
相关标签/搜索