一、为什么用Storm
storm是一个分布式开源的实时计算系统。可以用来做实时分析、在线机器学习、etl等。
计算速度快,每个节点每秒能处理百万个 tuples。并且很稳定,容错性很好保证数据被处理。并且容易设置和操作。
拓扑结构
Nimbus: 主控节点,用于提交任务,分发任务,集群监控等。利用zk进行master选举,防止单点故障。
supervisor: 负责接收Nimbus提交的任务,分配对应的worker进程。
在物理机上,图中的 nimbus和suervisor节点一般会对应机器进行部署。
二、基础概念
Stream
是strom里的数据流的抽象,是一个没有边界的tuple队列
Tuple
storm里数据流的最小单元
Spout
表示storm里数据处理的源头
Bolt
对stream进行加工处理的逻辑单元,也会经过加工之后发射出一些新的stream
bolt stream里处理可以有多个
Topology
spout和bolt组成的一个逻辑网络会被打包成topology,topology是storm里的一个逻辑抽象,可以认为是一个job,然后提交到storm集群进行处理。
三、storm topology的并行度
在一个 Storm 集群中,Storm 主要通过以下三个部件来运行拓扑:
工作进程(worker processes)
worker是一个服务进程,从属于一个特定的topology,一个topology可以设置多个worker执行器(executors)
executor是worker进程分配的一个线程任务(tasks)
executor 执行的内容就是task,task是实际执行过程中数据处理的最小单元,我们程序写的spout和bolt都会在集群中运行很多个task。
一个supervisor里可以分批多个work,一个work是一个服务进程,work内会启用多个executor执行task.
一个storm集群会有一个或者多个worker进程来处理各种topology。但是一个worker进程只会运行特定的topology。
一个或者多个executor运行在一个worker下,然后一个executor下会运行多个task,task运行就是spout或者bolt。
图中是一个包含有两个 worker 进程的拓扑。其中,蓝色的 BlueSpout 有两个 executor,每个 executor 中有一个 task,并行度为 2;绿色的 GreenBolt 有两个 executor,每个 executor 有两个 task,并行度也为2;而黄色的YellowBolt 有 6 个 executor,每个 executor 中有一个 task,并行度为 6,因此,这个拓扑的总并行度就是 2 + 2 + 6 = 10。具体分配到每个 worker 就有 10 / 2 = 5 个 executor。
四、Ack机制
在数据流处理的过程中,strom 如何得知所有bolt都执行成功了,或者说消息可靠性如何保证?
Bolt是可以多个的,从spout输送tupe开始,到bolt进行处理,产生加工后的新tuple,依次下传,每级bolt的tuple会对上一个tupe进行锚定,可以简单的认为记录下自己的上级tuple,最后会形成一个tupe逻辑树。
Storm的消息确认机制极为成功,一般的方案会维护系统里的所有tuple树,并维护着每个tuple的消费状态,但是成千上万个tuple树的存储空间也是极为庞大的,并且占用的是内存资源。storm它避免了tuple树的存储维护,利用异或算法解决了这个问题,节省了内存资源(最多耗费20字节的内存)。
AckerBolt,一个特殊的bolt,用来确认tuple 树是否成功执行。在一个新的 tuple 树生成的时候,spout 为每个 tuple 发送一个用于异或的固有 id,acker 会将这些 id 记录在它的挂起队列中。每次 executor ack 一个 tuple 的时候,acker 会接收到一个部分校验和,这个校验和是 tuple 自身的 id(将其从挂起队列中清除)和 executor 发送的每个下游 tuple 的 id(放入挂起队列中)的异或值。
文字看的比较蛋疼,我们直接看下面的图,用图说话
步骤细节
tuple树生成后,AckerBolt 为其维护着一个ackVal, 初始值是 0
- spout 发射消息 T1
- spout 发射消息 T2
- 调用ack方法,告诉AckerBolt T1,T2发送完成,传递参数就是其需要确认的消息异或值 param =
T1 ^ T2
,然后AckVal
=T1^T2
(T1^T2 = 0 ^ T1^T2) - bolt1 发射消息 T3,T4,T5
- bolt2 处理完之后,告诉AckerBolt T2 已经处理完毕,传递参数
T2
,这时更新AckVal
=(T1^T2) ^ T2
- Bolt-1 调用 AckerBolt 告诉它 T1已经消费成功并成功发送 T3,T4,T5。传递参数
T1^T3^T4^T5
,更新AckVal
=(T1^T2) ^ T2^(T1^T3^T4^T5)
- Bolt3 调用 AckerBolt 告诉他 T3,T4,T5已经成功消费,传递参数
0^T3^T4^T5
,更新AckVal
=(T1^T2) ^ T2^(T1^T3^T4^T5)^T3^T4^T5
- 计算最终结果
AckVal
=0,该tuple树,消费完毕。
每个节点要ack的时候,传递的ackVal就是自己要确认的消息id之间的异或值
五、storm的容错性
工作进程(worker)死亡时会发生什么?
工作进程死亡的时候,supervisor 会重新启动这个进程。如果在启动过程中仍然一直失败,并且无法向 Nimbus 发送心跳,Nimbus 就会将这个 worker 重新分配到其他机器上去。
supervisor节点故障
一个节点(集群中的工作节点,非 Nimbus 所在服务器)故障时,该节点上所有的任务(tasks)都会超时,然后 Nimbus 在检测到超时后会将所有的这些任务重新分配到其他机器上去。
Nimbus节点故障:
nimbus节点用来分发任务,监控集群,当nimbus节点故障的时候,supervisor还会继续执行接收到任务,对正在执行的任务没有影响,但是接收不到新的任务,另外当supervisor也出现故障,没有nimbus能够进行感知
参考文档
https://www.cnblogs.com/wuxiang/p/5629138.html
http://ifeve.com/storm-understanding-the-parallelism-of-a-storm-topology/