一、简介

  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的重要接口:

   

  一、消息的生命

    1. 首先, Storm 使用 spout 实例的 nextTuple()方法从 spout 请求 一个消息(tuple) 。
    2. 收到请求以后,spout 使用 open 方法中提供的 SpoutOutputCollector 向它的输出流发送一个或多个消息。每发送 一个消息,Spout 会给这个消息提供一个 message ID,它将会被用来 标识这个消息。SpoutOutputCollector 中发送消息格式如下: collector.emit(new Values(sentence), "messageId")。
    3. 接来下, 这些消息会被发送到后续业务处理的 bolts,并且 Storm 会跟踪由此消息产生出来的新消息。
    4. 当检测到一个消息衍生出来的 tuple tree 被完整处理后,Storm 会调用 Spout 中的 ack 方法,并将 此消息的 messageID 作为参数传入。
    5. 同理,如果某消息处理超时或失败, 则 此消息对应的 Spout 的 fail 方法会被调用,调用时此消息的 messageID 会被作为参数传入

  二、消息’被处理‘的细节——重要

    1. 当 KestrelSpout 从 kestrel 队列中读取一个消息, 表示它 “打开 ” 了队列中某个消息。这意味着,此消息并未从队列中真正的删除, 而 是将此消息设置为“pending”状态,它等待来自客户端的应答,被 应答以后,此消息才会被真正的从队列中删除。
    2. 处于“pending”状 态的消息不会被其他的客户端看到。另外,如果一个客户端意外的断 开连接, 则由此客户端 “打开” 的所有消息都会被重新加入到队列中 。
    3. 当消息被“打开”的时候,kestrel 队列同时会为这个消息提供一个 唯一的标识。
    4. 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的可靠性的更多相关文章

  1. storm中的一些概念

    1.topology 一个topolgy是spouts和bolts组成的图,通过stream groupings将图中的spout和bolts连接起来:如图所示: 一个topology会一直运行知道你 ...

  2. Storm中遇到的日志多次重写问题(一)

    业务描述: 统计从kafka spout中读取的数据条数,以及写入redis的数据的条数,写入hdfs的数据条数,写入kafaka的数据条数.并且每过5秒将数据按照json文件的形式写入日志.其中保存 ...

  3. Storm中Spout使用注意事项小结

    Storm中Spout用于读取并向计算拓扑中发送数据源,最近在调试一个topology时遇到了系统qps低,处理速度达不到要求的问题,经过排查后发现是由于对Spout的使用模式不当导致的多线程同步等待 ...

  4. 【Storm篇】--Storm中的同步服务DRPC

    一.前述 Drpc(分布式远程过程调用)是一种同步服务实现的机制,在Storm中客户端提交数据请求之后,立刻取得计算结果并返回给客户端.同时充分利用Storm的计算能力实现高密度的并行实时计算. 二. ...

  5. 2、Storm中的一些概念理解

    1.Tuple,Value,Field Tuple官方解释: "A tuple is a named of values where each value can be any type.& ...

  6. storm中的基本概念

    Storm是一个流计算框架,处理的数据是实时消息队列中的,所以需要我们写好一个topology逻辑放在那,接收进来的数据来处理,所以是通过移动数据平均分配到机器资源来获得高效率. Storm的优点是全 ...

  7. storm中的topology-worker-executor-task

    调度角色 调度方法 自定义调度 1 调度角色   任务角色结构 上图是JStorm中一个topology对应的任务执行结构,其中worker是进程,executor对应于线程,task对应着spout ...

  8. storm源码之理解Storm中Worker、Executor、Task关系 + 并发度详解

    本文导读: 1 Worker.Executor.task详解 2 配置拓扑的并发度 3 拓扑示例 4 动态配置拓扑并发度 Worker.Executor.Task详解: Storm在集群上运行一个To ...

  9. Storm中并发程度的理解

    Storm中涉及到了很多组件,例如nimbus,supervisor等等,在参考了这两篇文章之后,对这个有了更好的理解. Understanding the parallelism of a Stor ...

随机推荐

  1. JavaScript语言基础知识点图示(转)

    一位牛人归纳的JavaScript 语言基础知识点图示. 1.JavaScript 数据类型 2.JavaScript 变量 3.Javascript 运算符 4.JavaScript 数组 5.Ja ...

  2. Python并发与并行的新手指南

    点这里 在批评Python的讨论中,常常说起Python多线程是多么的难用.还有人对 global interpreter lock(也被亲切的称为“GIL”)指指点点,说它阻碍了Python的多线程 ...

  3. Asp.net最基本的文件上传功能代码

    aspx前台页面代码 <form id="form1" action="File.aspx" runat="server" encty ...

  4. Ajax的进阶学习(二)

    JSON和JSONP 如果在同一个域下,$.ajax()方法只要设置dataType属性即可加载JSON文件.而在非同域下,可以使用JSONP,但也是有条件的. Ajax进阶.html: <!D ...

  5. 解决xshell连接linux总是异常断开的问题?

    找到etc下面的profile文件,可以看到有下面一行: TMOUT=;export TMOUT 注释掉即可解决. #TMOUT=;export TMOUT

  6. 程序空间(Program memory)

    The computer program memory is organized into the following: Data Segment (Data + BSS + Heap) Stack ...

  7. IOS底层数据结构--class

    一.类的数据结构 Class(指针) typedef struct objc_class *Class; /* 这是由编译器为每个类产生的数据结构,这个结构定义了一个类.这个结构是通过编译器在执行时产 ...

  8. eclipse 代码格式化 行宽设置

    windows--preferences--java--code style--formatter--edit--line wrapping--maximum line width

  9. 为什么要关闭360云盘:新来的美工嫌我们logo太丑,所以就决定关闭了。这个理由怎么样

    新来的美工嫌我们logo太丑,所以就决定关闭了.这个理由怎么样曾经拥有的不要忘记:不能得到的更要珍惜:属于自己的不要放弃:已经失去的留作回忆.我刚来~~~嘿嘿~~ 久经考验的,忠诚的国际宅男主义战士, ...

  10. Gravitational Teleport 是一个先进的 SSH 服务器,基于 Golang SSH 构建,完全兼容 OpenSSH

    Gravitational Teleport 是一个先进的 SSH 服务器,可通过 SSH 或者 HTTPS 远程访问 Linux 服务器.其目的是为了替代 sshd.Teleport 可以轻松让团队 ...