Storm
Storm的主线主要包括4条:nimbus, supervisor, worker和task。
Nimbus
要了解nimbus的具体做的操作,可以从提交一个topology的流程开始。
1.1 Prepare
Nimbus启动时候,运行了一个Thrift Server。它会在topology提交之前做以下四个工作。
(1) 清理一些中断了的topology(nimbus目录下/storm.local.dir/stormdist下存在,zk中 storms/topologyid中不存在的topology): 删除ZK上相关信息(清理tasks/topologyid; storms/topologyid; assignments/topologyid这个三个目录)。
(2) 将storms/下所有的topology设置为启动状态: 能转换成startup状态的两种状态分别是:killed和rebalancing。nimbus的状态转换是很有意思的事情,killed状态的topology在nimbus启动的时候会被干掉;rebalancing状态的topology在nimbus启动的时候会重新分发任务,状态会变成rebalancing的上一个状态。
举例: 当某个topology提交的时候,会被设置成active状态,假设storm集群增加机器了,你希望重新分发任务,可以将状态转换成rebalance状态,转换成这个状态要做这几件事:
首先,启动一个延迟TOPOLOGY-MESSAGE-TIMEOUT-SECS秒执行的事件,将当前状态转换成do-rebalance状态,在这之前会将当前topology的状态设置成rebalancing状态(注意设置和转换的区别,设置就是指将ZK上存储的topology的状态进行重新设置)。
然后,将rebalancing的状态转换成do-rebalance, 也就是将任务重新分发。
最后将状态设置成rebalancing的上一个状态active。
(3) 每间隔NIMBUS-MONITOR-FREQ-SECS长时间将ZK上/storms 下所有的topology状态转换成monitor状态,并且将不活跃的storm清理掉。只有当状态为active和inactive的时候,才能转换成monitor状态,转换成该状态就是将任务重新分发,监控是否与上一次的分配情况不同,如果存在不同,则替换,这个过程ZK上存储的topology的状态是不会被设置的。
(4) 删除过期的jar包: 过期时间为NIMBUS-INBOX-JAR-EXPIRATION-SECS。每间隔NIMBUS-CLEANUP-INBOX-FREQ-SECS长时间进行一次清理。
1.2 Submit topology
1.2.1 Submit
以下是提交一个topology的执行流程概述
(1) 检查:检查所提交的topology是否已经是active状态,如果是,抛出异常。
(2) 计数器:计数器+1,用来计算共提交了多少topology。
(3) 为这个topology生一个id。
(4) 计算要启动的acker的相关信息,每个acker都是一个bolt。根据配置的信息获取并发数等。
(5) 获取topology的code和config。
(6) 为该topology建立心跳目录(ZK:storm-zk-root/taskbeats/topologyid)。
(7) 为该topology分配任务。
(8) 设置storm状态为active。
1.2.2 Task assigned
这个是nimbus的重点,分配任务的流程:
(1) 获取所有的node+port:分配任务的目的就是将tasks分配到具体的node+port。
2) 获取该topology已经分配了的任务(如果是新提交的topology,则为空)。
(3) 为每个需要分配的task分配到具体node+port。合并(1)和(2)中所有的node和port。具体为什么要这样,还不是很清楚。因为通过(1)应该是可以获取所有的node+port。
(4) 将2)中需要重新分配的task的启动时间不变,其他新分配的任务的时间设置为当前时间。
(5) 将以上的信息Assignment写入到ZK中。
1.2.3 scratch?
分配任务主要分为两种情况,代码中用scratch?来标识两种不同的情况(正常的分配任务和rebalance状态转换)。1.2.2中所说的需要分配的任务暗指此处的两种任务分配情况。
(1) rebalance状态转换
这种原因导致的重新分发任务,与正常的分配任务的区别在于两点:
第一:所有的任务都认为是活跃任务,即认为任务心跳都未超时。
第二:所有的任务都需要重新分配,即认为所有端口都是空闲的端口,允许被分配任务。
举例说明:
假设:提交的topology确定有10个task, taskid分别为1,2,3,…10。有两个supervisor(n
ode1和node2),每个supervisor可用的端口号为{6001, 6002, 6003}。
分配任务的目标是尽可能负载均衡,即每个node均衡,每个端口均衡, rebalance情况
下分配的结果为:
tasked |
node+port |
1、7 |
node1:6001 |
3、9 |
node1:6002 |
5 |
node1:6003 |
2、8 |
node2:6001 |
4、10 |
node2:6002 |
6 |
node2:6003 |
(2) 正常分配任务:
正常分配任务比rebalance多考虑两个问题,考虑task的心跳是否超时和哪些端口上分配的任务是符合负载均衡的,可以不需要重新分发。所以要重新分发的task是那些心跳超时和所在端口没有分配均衡的那些任务。
nimbus用了一个叫task-heartbeat-cache来存储task的心跳时间,而不是直接用写入到zk上的心跳时间,这么做的目的是防止各个node上面的时间不同步。
举例说明:
假设提交的topology,跟上个例子相同。确定有10个task, taskid分别为1,2,3,…10。有两个supervisor(node1和node2),每个supervisor可用的端口号为{6001, 6002, 6003}。
首先,重新分配任务时,会先判断心跳超时的task,假设task1和task6心跳超时,task1和task6需要重新分配。
然后,判断哪些端口的分配是符合负载均衡的要求。 判断过程是这样的:共10个task,6个端口,按照负载均衡原则,应该是4个端口上分配两个task,2个端口上分配1个task。依次判断哪些端口不符合要求。如果按顺序来判断,node1:6001和node2:6002是不符合要求的,他们应该要被分别分配2个任务。所以两个端口的任务也需要重新分发。
最后,确定要重新分发的任务是1、4、7和10,可用的端口号是node1:6001和node2:6002。
按照每个node均衡,每个端口均衡的分配原则,分配结果如下:
tasked |
node+port |
1、7 |
node1:6001 |
4、10 |
node2:6002 |