Storm可靠性总结

  1. 本文主要参考了Storm的可靠性文档
  2. Storm的可靠性是通过一个叫做Acker的模块来实现的,它会跟踪Spout、Bolt发送tuple时所形成的tuple树,看tuple树是成功处理(tuple叶子是否被都被处理)还是失败(只要一个tuple叶子失败了)了。
  3. 除了Acker要跟踪tuple树的处理状态外,当然还需要Spout和Bolt来配合,才能达到Storm的可靠性。那么如何来配合呢?
  4. 针对Spout,它在发送tuple时,必须给定给每个tuple指定一个唯一的msgid。相当于确定了tuple树的根。
  5. 针对Bolt,它在发送tuple时,需要做一次锚定(anchoring),通过它接收到的tuple以及发送的新tuple之间建立一个关系来达到。相当于确定了tuple树的树枝(link)。
  6. 通过以上两步,Acker就能确定了一个tuple树。最后Acker还需要知道每个tuple树上的每个tuple的处理结果。是成功还是失败?结果的通知也是需要Bolt来告知Acker的。
  7. 具体到编写Spout和Bolt代码时,有如下的API调用分别来完成以上三个步骤:
    1. 对于Spout:collector.emit(new Values("xxx", "yyy"), msgid);如果Spout需要从消息队列中读取消息,那么这个msgid一般会来自于消息队列中间件。
    2. 对于Bolt的锚定:collector.emit(srctuple, newtuple);其中srctuple是Bolt收到的源tuple,newtuple是Bolt基于源tuple生成的新的tuple
    3. 对于Bolt的结果通知:处理成功了则调用collector.ack(srctuple);处理失败了则调用collector.fail(srctuple);其中srctuple都是Bolt收到的源tuple。
  8. 当Acker确定了tuple树被成功处理了,那么Storm会调用Spout的ack方法;如果Acker确定tuple树被失败处理了(包括超时),那么Storm会调用Spout的fail方法。
  9. Storm为了简化编程,它提供了BaseBasicBolt,这个类提供的collector不是一般的OutputCollector,而是BasicOutputCollector,通过BasciOutputCollector,已经实现了锚定和结果通知。我们只要继承BaseBasicBolt来定义Bolt就可以了。
    1. 发送消息的时候,只要collector.emit(newtuple); 只要指定新产生的tuple就以了,无需指定源tuple。
    2. 发送结果的时候,如果成功了,可以不需要写任何代码;如果失败了,则抛出一个FailedException异常。
  10. Spout的可靠性要求还是需要自己来写的。
  11. 如果要Acker来跟踪每个tuple树,那么会消耗很多的内存,是无法满足实现条件的。这时Storm采用了一个非常巧妙的算法,通过给每个tuple分配一个64bit的随机数,生成tuple的时候会和之前的结果做一次异或xor,Bolt响应的时候也会和之前的结果做一次异或xor,我们知道相同的两个数做异或,结果一定为0,那么当tuple树上的所有tuple都做了两次异或后,结果一定会为0,那么Acker就可以通过异或xor的结果是否为0,能判断整个tuple树的处理结果了。当然这种算法需要的内存可以很少,也可能会出现误判的情况,但出现误判的概率几乎为0。
  12. 可靠性还是需要一些额外的计算和网络开销的,如果你的应用不需要可靠性支持,可以通过下面的几种方法取消可靠性支持:
    1. 整个topology都取消:通过设置Acker的并发度为0:Config.TOPOLOGY_ACKERS = 0,那么这时候,Spout发送完tuple后,Spout的ack方法立即被调用。
    2. 某个Bolt发送的tuple都取消:此Bolt不需要做锚定就可以了。(按道理也不需要调用ack)
    3. 某个tuple取消:在Spout发送Spout时,不指定msgid就可以了。

你可能感兴趣的:(storm,storm可靠性,Acker)