Storm中tuple的可靠性
一、简介
Storm 可以保证 spout 发出的每条消息都能被“完全处理” ,这也是直接区别于其他实时系统的地方,如 S4。
请注意,spout 发出的消息后续可能会触发产生成千上万条消息 ,可以形象的理解为一棵消息树, 其中 spout 发出的消息为树根, Storm会跟踪这棵消息树的处理情况, 只有当这棵消息树中的所有消息都被处理了,Storm 才会认为 spout 发出的这个消息已经被“完全处理” 。如果这棵消息树中的任何一个消息处理失败了, 或者整棵消息树在限定的时间内没有“完全处理” ,那么 spout 发出的消息就会重发。
二、理解消息被完整处理
一个消息(tuple)从 spout 发送出来, 可能会导致成百上千的消息 基于此消息被创建
以“单词统计”为例:它的消息可分裂为多个消息,这些消息构成一个树状结构,被称为“tuple tree”,如图
当下面的条件同时被满足,Storm 才会认为一个从 spout 发送出来的消息被完整处理.
- tuple tree 不再生长
- 树中的任何消息被标识为“已处理”
如果在指定的时间内,一个消息衍生出来的 tuple tree 未被完全 处理成功,则认为此消息未被完整处理。这个超时值可以通过任务级 参数Config.TOPOLOGY_MESSAGE_TIMEOUT_SECS 进行配置,默认超时 值为30秒。
考虑到尽可能减少对内存的消耗,Storm 并不会跟踪消息树中的每个消息,而是采用了一些特殊的策略,它把消息树当作一个整体来跟踪,对消息树中所有消息的唯一 id 进行异或计算,通过是否为零来判定 spout 发出的消息是否被“完全处理” ,这极大的节约了内存和简化了判定逻辑。
上面所说的,Storm 保证了每个消息至少被处理一次,但是对于有些计算场合,会严格要求每个消息只被处理一次,幸而 Storm 的0.7.0引入了事务性拓扑,解决了这个问题,后面会有详述。
三、消息的生命周期
要理解消息的可靠性,就要理解消息的生命周期,因为消息是在几个生命状态中切换。
Spout的重要接口:
一、消息的生命
- 首先, Storm 使用 spout 实例的 nextTuple()方法从 spout 请求 一个消息(tuple) 。
- 收到请求以后,spout 使用 open 方法中提供的 SpoutOutputCollector 向它的输出流发送一个或多个消息。每发送 一个消息,Spout 会给这个消息提供一个 message ID,它将会被用来 标识这个消息。SpoutOutputCollector 中发送消息格式如下: collector.emit(new Values(sentence), "messageId")。
- 接来下, 这些消息会被发送到后续业务处理的 bolts,并且 Storm 会跟踪由此消息产生出来的新消息。
- 当检测到一个消息衍生出来的 tuple tree 被完整处理后,Storm 会调用 Spout 中的 ack 方法,并将 此消息的 messageID 作为参数传入。
- 同理,如果某消息处理超时或失败, 则 此消息对应的 Spout 的 fail 方法会被调用,调用时此消息的 messageID 会被作为参数传入
二、消息’被处理‘的细节——重要
- 当 KestrelSpout 从 kestrel 队列中读取一个消息, 表示它 “打开 ” 了队列中某个消息。这意味着,此消息并未从队列中真正的删除, 而 是将此消息设置为“pending”状态,它等待来自客户端的应答,被 应答以后,此消息才会被真正的从队列中删除。
- 处于“pending”状 态的消息不会被其他的客户端看到。另外,如果一个客户端意外的断 开连接, 则由此客户端 “打开” 的所有消息都会被重新加入到队列中 。
- 当消息被“打开”的时候,kestrel 队列同时会为这个消息提供一个 唯一的标识。
- KestrelSpout 就是使用这个唯一的标识作为这个 tuple 的 messageID 的。稍后当 ack 或 fail 被调用的时候,KestrelSpout 会 把 ack 或者 fail 连同 messageID 一起发送给 kestrel 队列, kestrel 会将消息从队列中真正删除或者将它重新放回队列中。
四、可靠相关的 api
为了使用 Storm 提供的可靠处理特性,我们需要做两件事情:
- 无论何时在 tuple tree 中创建了一个新的节点,我们需要明确的 通知 Storm:collector.emit(tuple,new Values(word));
- 当处理完一个单独的消息时,我们需要告诉 Storm 这棵 tuple tree 的变化状态:collector.ack(tuple);
五、acker
Storm 系统中有一组叫做“acker”的特殊的任务,它们负责跟踪 DAG(有向无环图)中的每个消息。每当发现一个 DAG 被完全处理, 它就向创建这个根消息的 spout 任务发送一个信号。 拓扑中 acker 任 务的并行度可以通过配置参数 Config.TOPOLOGY_ACKERS 来设置。默 认的 acker 任务并行度为1,当系统中有大量的消息时,应该适当提 高 acker 任务的并发度。
每当 bolt 新生成一个消息,对应 tuple tree 中的根消息的 messageId 就拷贝到这个消息中。当这个消息被应答的时候,它就把 关于 tuple tree 变化的信息发送给跟踪这棵树的 acker。例如,他 会告诉 acker: 本消息已经处理完毕, 但是我派生出了一些新的消息 , 帮忙跟踪一下吧。
举个例子,假设消息 D 和 E 是由消息 C 派生出来的,这里演示了 消息 C 被应答时,tuple tree 是如何变化的。因为在 C 被从树中移除的同时 D 和 E 会被加入到 tuple tree 中 , 因此 tuple tree 不会被过早的认为已完全处理。
当 spout 发送一个消息的时候,它就通知对应的 acker 一个新的 根消息产生了,这时 acker 就会创建一个新的 tuple tree。当 acker 发现这棵树被完全处理之后,他就会通知对应的spout 任务。
Acker 任务是轻量级的,所以在拓扑中并不需要太多的 acker 存 在。可以通过 Storm UI 来观察 acker 任务的吞吐量,如果看上去吞 吐量不够的话,说明需要添加额外的 acker——config.setNumAckers(num)
关闭可靠性(任意一个即可):
- 将 参 数 Config.TOPOLOGY_ACKERS 设 置 为 0( config.setNumAckers(0) ),通过此方法,当 Spout 发送一个消 息的时候,它的 ack 方法将立刻被调用,这样就不能保证消息的 可靠性;
- Spout 发送一个消息时,不指定此消息的 messageID。这样 spout 中的 ack 和 fail 方法将不会被调用,即使 acker 参数不为0,但 这样就不能控制失败后是否重发消息。即在 spout 的 nextTuple 方法中这样发射数据:collector.emit(new Values(l));
- 如果你不在意某个消息派生出来的子孙消息的可靠性,则此消息 派生出来的子消息在发送时不要做锚定, 即在 emit 方法中不指定 输入消息。因为这些子孙消息没有被锚定在任何tuple tree 中 , 因此他们的失败不会引起任何 spout 重新发送消息。
开启使用可靠性(同时满足):
- 设置 Ackers 的数量为非0;conf.setNumAckers(1);
- 在 spout 发射消息时,绑定 messageId;collector.emit(new Values(l), messageId);
- 在 bolt 中 发 射 消 息 时 , 需 要 锚 定 到 上 一 个 消 息 上 ; collector.emit(input, new Values(word));
六、注意
这种模式,每发送一个消息,都会同步发送一个ack/fail,对于网络的带宽会有一定的消耗,如果对于可靠性要求不高,可通过使用不同的 emit 接口关闭该模式。
Storm中tuple的可靠性的更多相关文章
- storm中的一些概念
1.topology 一个topolgy是spouts和bolts组成的图,通过stream groupings将图中的spout和bolts连接起来:如图所示: 一个topology会一直运行知道你 ...
- Storm中遇到的日志多次重写问题(一)
业务描述: 统计从kafka spout中读取的数据条数,以及写入redis的数据的条数,写入hdfs的数据条数,写入kafaka的数据条数.并且每过5秒将数据按照json文件的形式写入日志.其中保存 ...
- Storm中Spout使用注意事项小结
Storm中Spout用于读取并向计算拓扑中发送数据源,最近在调试一个topology时遇到了系统qps低,处理速度达不到要求的问题,经过排查后发现是由于对Spout的使用模式不当导致的多线程同步等待 ...
- 【Storm篇】--Storm中的同步服务DRPC
一.前述 Drpc(分布式远程过程调用)是一种同步服务实现的机制,在Storm中客户端提交数据请求之后,立刻取得计算结果并返回给客户端.同时充分利用Storm的计算能力实现高密度的并行实时计算. 二. ...
- 2、Storm中的一些概念理解
1.Tuple,Value,Field Tuple官方解释: "A tuple is a named of values where each value can be any type.& ...
- storm中的基本概念
Storm是一个流计算框架,处理的数据是实时消息队列中的,所以需要我们写好一个topology逻辑放在那,接收进来的数据来处理,所以是通过移动数据平均分配到机器资源来获得高效率. Storm的优点是全 ...
- storm中的topology-worker-executor-task
调度角色 调度方法 自定义调度 1 调度角色 任务角色结构 上图是JStorm中一个topology对应的任务执行结构,其中worker是进程,executor对应于线程,task对应着spout ...
- storm源码之理解Storm中Worker、Executor、Task关系 + 并发度详解
本文导读: 1 Worker.Executor.task详解 2 配置拓扑的并发度 3 拓扑示例 4 动态配置拓扑并发度 Worker.Executor.Task详解: Storm在集群上运行一个To ...
- Storm中并发程度的理解
Storm中涉及到了很多组件,例如nimbus,supervisor等等,在参考了这两篇文章之后,对这个有了更好的理解. Understanding the parallelism of a Stor ...
随机推荐
- pyhton Chapter3 读文件
使用内置函数open()打开文件,data=open("1.txt").利用data.close()关闭文件.利用data.readline()读取文件中的一行数据,然后指示读取文 ...
- Grid行编辑插件
//操作列不显示应该就是autoLoad的问题. Ext.onReady(function () { Ext.BLANK_IMAGE_URL = "E ...
- Delphi美化界面 转载
手头的项目做的差不多了,交给客户,结果给出的结论是界面太难看了,至少要做成像QQ类似的界面.(目前是QQ2009界面确实还是不错的,本人也非常喜欢). 1.透明问题. 要重新调整界面确实很麻烦,以前用 ...
- ZOJ3554 A Miser Boss(dp)
给你n个工件,然后有A,B,C三个工厂,然后它们加工第i个工件所需要的时间分别为a[i],b[i],c[i],然后现在要你利用三间工厂加工所有的零件,要求是任何时间工厂都不能停工,而且一定要三间同时做 ...
- 同一网站不同和二级域名和不同子目录的cookie
1.cookie二级域名的实现: 用户其中一个站点登录,而且可以各个子频道间切换,保持登录状态设置Cookie时,使用如下代码即可:setcookie(name,value,expire,path,& ...
- iOS获取手机相关信息
iOS具体的设备型号: #include <sys/types.h> #include <sys/sysctl.h> - (void)test { //手机型号. size_t ...
- [STL]deque和stack、queue
怎么说呢,deque是一种双向开口的连续线性空间,至少逻辑上看上去是这样.然而事实上却没有那么简单,准确来说deque其实是一种分段连续空间,因此其实现以及各种操作比vector复杂的多. 一.deq ...
- 广播接收者BroadcastReceiver
BroadcastReceiver与activity,service有完整的生命周期不同,BroadcastReceiver本质上是一系统级别的监听器,专门负责监听各程序发出的broadcast.与程 ...
- ASP 中调用函数关于Call使用注意的问题
Function TestFun(Tstr) TStr = "Fun2" End Function Sub TestSub(TStr) Tstr = "Sub2" ...
- Android 中建立一个OpenGL ES的开发环境
转自: http://wiki.eoe.cn/page/Building_an_OpenGL_ES_Environment.html 负责人:zhangql原文链接:http://docs.eoean ...