一.Storm spout的nextTuple以及bolt的execute
Storm的API非常丰富,但是记住,本文介绍的ACK机制需要特殊的支持。也就是说,本文所说的ACK的机制只是Storm的一种可选机制,你完全可以无视它去选择一种轻量的无确认的Best effort方式去使用Storm,本文之所以单独介绍ACK机制,是因为其优雅。
在编写spout的nextTuple时,最终你必须要emit一个Tuple,记住,要这么做:
this.collector.emit(new Values(...), msgID);
一定要有msgID这个参数,一定要有!否则Storm便不会跟踪这个Tuple。这句话的意思是在Storm执行完spout的emit之后,会在系统内部创建一个类似下面的映射:
msgID-Tuple:ACKvalue
其ACKvalue的初始值为一个随机的数字,该数字由spout为该被emit的msg生成,显然,如果spout一次emit了多个msg,那么该ACKvalue便是所有这些数值的异或的结果。这个后面会详述。
此外,在后续的bolt的execute方法中emit新的msg时,记住,一定要携带tuple参数,不然后续的拓扑便会丢失针对该tuple的追踪,要写成:
collector.emit(tuple, new Values(...));
而不是:
collector.emit(new Values(...));
当然如果你想故意不再跟踪某个Tuple在后续拓扑中的结果(比如你只是希望保证特定几个步骤的执行成功),你完全可以在特定的bolt的execute的emit方法中不再携带tuple参数,一切由你决定。
二.ACK原理进化脉络
如果发送者发出一个消息,希望确认接收者是否收到,最简单的方案就是下面的了:
这里能说很多很多,比如TCP就是这么实现的,TCP这种老掉牙的东西真的不想在多说,所以一句话总结吧,这种方式是采用了带内ACK的方法进行可靠性保证的。推广到接力流水线的方式,就变成了下面的样子: