转--Storm的ack机制

原文可参见:
http://www.tuicool.com/articles/jeqYryJ

http://blog.csdn.net/endlu/article/details/52151967


一、Storm消息可靠性

Tuple树

在Storm的一个Topology中,Spout通过 SpoutOutputCollector 的emit()方法发射一个tuple(源)即消息。而后经过在该Topology中定义的多个Bolt处理时,可能会产生一个或多个新的Tuple。源Tuple和新产生的Tuple便构成了一个Tuple树。当整棵树被处理完成,才算一个Tuple被完全处理,其中任何一个节点的Tuple处理失败或超时,则整棵树失败。

关于消息在storm中的超时默认为30秒,具体参看 defaults.yaml 中的 topology.message.timeout.secs: 30 的配置。同时,你也可以在定义topology时,通过conf.setMessageTimeoutSecs方法指定超时时间。

可靠性reliability

storm所谓的消息可靠性指的是storm保证每个tuple都能被toplology完全处理。而且处理的结果要么成功要么失败。出现失败的原因可能有两种即节点处理失败或者处理超时。

可靠性调整

acker task是非常轻量级的, 所以一个topology里面不需要很多acker。你可以通过Strom UI来跟踪它的性能。 如果它的吞吐量看起来不正常,那么你就需要多加点acker了。如果可靠性对你来说不是那么重要 — 你不太在意在一些失败的情况下损失一些数据, 那么你可以通过不跟踪这些tuple树来获取更好的性能。不去跟踪消息的话会使得系统里面的消息数量减少一半, 因为对于每一个tuple都要发送一个ack消息。并且它需要更少的id来保存下游的tuple, 减少带宽占用。

有三种方法可以去掉可靠性:

  • 第一是把Config.TOPOLOGY_ACKERS 设置成 0. 在这种情况下, storm会在spout发射一个tuple之后马上调用spout的ack方法。也就是说这个tuple树不会被跟踪。
  • 第二个方法是在tuple层面去掉可靠性。 你可以在发射tuple的时候不指定messageid来达到不跟粽某个特定的spout tuple的目的。
  • 最后一个方法是如果你对于一个tuple树里面的某一部分到底成不成功不是很关心,那么可以在发射这些tuple的时候unanchor它们。 这样这些tuple就不在tuple树里面, 也就不会被跟踪了。

注:所谓的 锚定 (anchoring)是指为 tupleTree 中增加一个新的节点。在bolt中你可以通过 _collector.emit(tuple,new Values(xx)) 将该tuple发送到下个bolt,此时 new Value 就被锚定在该 tuple 上了。你可以认为 tuple tree 之间link的建立称为锚定。

二、ack机制

通过上面所述的可靠性可知,storm会保证每个tuple被完全处理。那么storm是如何实现这种可靠性的呢?storm对于这个问题的解决方式设计的非常巧妙,也就是storm的acker机制。strom是通过Acker(一种特殊的Blot Task)来监控你的tuple树,最终它通过调用Spout中的ack或者fail方法来告诉Spout消息的最终情况。

具体流程:

  • 在1、2中,spout产生了两条消息T1、T2分别发送至Bolt-1、Bolt-2两个Bolt组件中
  • 在3中,spout发送出消息T1、T2的同时,在Acker Bolt中注册了一条记录
  • 在4中Bolt-1接收T1,发送T3,T4,T5。Bolt-1先进行T1^T3^T4^T5,再将结果与Acker Bolt中的AckVal即T1^T2进行异或即第6步,此时Acker Bolt中的记录为
  • 在5中Bolt-2对接收的T2进行异或,它没有产生新的消息,因此发送到Acker Bolt的记录是T2,此时Acker Bolt中的记录为
  • 在7中,对接收的T3,T4,T5进行异或,而后再发送至Acker Bolt,此时Acker Bolt中的记录为
  • 在第7步中可以看到此时Acker Bolt中的ackVal值已经为0了,此时消息已经处理结束。Acker Bolt也认为消息已经被完全处理了,于是便向最初发送消息的spout发送消息,接着该spout将调用ack方法进行确认!

三、ack机制的其他问题

当有多个acker的时候, 一个tuple被acked的时候, 如果知道给哪一个acker发送message?

由spout产生的spout-tuple-id会被当做tuple tree的root id。这个root id会一级级的通过tuple tree传递下去。因此,每个新产生的tuple都能知道产生它的源tuple id即root id。同时storm acker框架,通过对spout-tuple-id进行mod hash以确定由哪个acker处理这个spout,因此当某一个tuple被acked的时候, 只要通过hash就能找到相应的acker。

如果有多个spout task的时候, storm在最终ack spout tuple的时候, 如何知道对应于哪个spout task, 因为必须在产生tuple的那个spout task进行ack?

spout task在emit一个新的tuple的时候, 会发message告诉相应的acker它的task id, 所以acker是知道tupleid和taskid的map的。

四、总结

本文的核心其实就是storm的acker工作机制。storm的acker框架设计非常巧妙,对于一个tuple tree的状态跟踪使用的内存最多也就20 bytes。但同时要注意storm为了保证可靠性,其会在task memory中记录你汇报的tuple tree结构和运行情况,而只有当某个tuple被ack或fail时才会被内存中删除,所以如果你总是不去ack或fail(bolt或spout中进行),那么可能会导致task的outOfMemory。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值