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 ...
随机推荐
- JavaScript语言基础知识点图示(转)
一位牛人归纳的JavaScript 语言基础知识点图示. 1.JavaScript 数据类型 2.JavaScript 变量 3.Javascript 运算符 4.JavaScript 数组 5.Ja ...
- Python并发与并行的新手指南
点这里 在批评Python的讨论中,常常说起Python多线程是多么的难用.还有人对 global interpreter lock(也被亲切的称为“GIL”)指指点点,说它阻碍了Python的多线程 ...
- Asp.net最基本的文件上传功能代码
aspx前台页面代码 <form id="form1" action="File.aspx" runat="server" encty ...
- Ajax的进阶学习(二)
JSON和JSONP 如果在同一个域下,$.ajax()方法只要设置dataType属性即可加载JSON文件.而在非同域下,可以使用JSONP,但也是有条件的. Ajax进阶.html: <!D ...
- 解决xshell连接linux总是异常断开的问题?
找到etc下面的profile文件,可以看到有下面一行: TMOUT=;export TMOUT 注释掉即可解决. #TMOUT=;export TMOUT
- 程序空间(Program memory)
The computer program memory is organized into the following: Data Segment (Data + BSS + Heap) Stack ...
- IOS底层数据结构--class
一.类的数据结构 Class(指针) typedef struct objc_class *Class; /* 这是由编译器为每个类产生的数据结构,这个结构定义了一个类.这个结构是通过编译器在执行时产 ...
- eclipse 代码格式化 行宽设置
windows--preferences--java--code style--formatter--edit--line wrapping--maximum line width
- 为什么要关闭360云盘:新来的美工嫌我们logo太丑,所以就决定关闭了。这个理由怎么样
新来的美工嫌我们logo太丑,所以就决定关闭了.这个理由怎么样曾经拥有的不要忘记:不能得到的更要珍惜:属于自己的不要放弃:已经失去的留作回忆.我刚来~~~嘿嘿~~ 久经考验的,忠诚的国际宅男主义战士, ...
- Gravitational Teleport 是一个先进的 SSH 服务器,基于 Golang SSH 构建,完全兼容 OpenSSH
Gravitational Teleport 是一个先进的 SSH 服务器,可通过 SSH 或者 HTTPS 远程访问 Linux 服务器.其目的是为了替代 sshd.Teleport 可以轻松让团队 ...