Storm 是如何跟踪一条消息以及它衍生出来的消息都被成功处理的
2012·2郑昀汇总
我们做 Notify Server 时可以间接借鉴这个解决方案的思路。
Storm 是一个分布式的、容错的实时计算系统,由 Twitter 开源。
先不介绍术语和背景知识,直接来一些吸引眼球的内容:
一,Tuple Tree
spout 发射一个消息(tuple),可能会导致成百上千的消息基于此消息被创建。这些消息构成一个树状结构,我们称之为“tuple tree”。
tuple 是如何被跟踪的呢?系统中有成千上万的消息,如果为每个 spout 发送的消息都构建一棵树的话,很快内存就会耗尽。所以,必须采用不同的策略来跟踪每个消息。
二,Acker 跟踪 Tuple
acker 对于 tuple 的跟踪算法是 storm 最大的突破。这个算法使得对于任意大的一个 tuple tree, 它只需要恒定的20字节就可以进行跟踪了。
Storm 系统中有一组叫做“acker”的特殊任务,它们负责跟踪 DAG(有向无环图)中的每个消息。每当发现一个 DAG 被完全处理,它就向创建这个根消息的 spout 任务发送一个信号。
原理很简单:
1)当一个消息被创建的时候(无论是在 spout 还是 bolt 中),系统都为该消息分配一个 64bit 的随机值作为id。这些 messageid 是 acker 用来跟踪由 spout 消息派生出来的 tuple tree 的。
2)acker 对于每个 tuple 保存一个 ack-val 的校验值(一个64 bit数字),它的初始值是0。 然后每发射一个 tuple (即消息的创建),或者 ack 一个 tuple (即消息的被应答),那么 tuple 的 id 都要跟 ack-val 异或一下,并且把得到的值更新为 ack-val 的新值。假设每个发射出去的 tuple 都被 ack 了, 那么最后 ack-val 一定是0(因为一个数字跟自己异或得到的值是0)。
总的来说,ack-val 是这棵树上所有创建的 tuple-id 以及 ack 的 tuple-id 一起异或(XOR)。ack-val 表示了整棵树的的状态,无论这棵树多大,只需要这个固定大小的数字就可以跟踪整棵树。
每当 acker 发现一棵树的 ack val 值为0时,它就知道这棵树已经被完全处理了。
因为消息的随机ID是一个64bit的值,因此ack val在树处理完之前被置为0的概率非常小。
三,Acker 有很多,选择哪一个呢?
当一个 tuple 需要 ack 的时候,它到底选择哪个 acker 来发送这个信息呢?
storm 用一致性哈希来把一个 tuple-message-id 对应到 acker , 因为每一个 tuple 知道它所有的祖宗的 tuple-message-id, 所以它自然可以算出要通知哪个 acker 来 ack。
参考资源:
1)2011,徐明明,Storm翻译稿系列;
3)2011,徐明明,Storm 如何保证消息不丢失;
赠图一枚: