Storm将每个节点分为主控节点和工作节点两种,其中主控节点只有一个,工作节点可以有多个。
主控节点运行Nimbus守护进程,类似于Hadoop中的jobtracker,负责在集群中分发代码,对节点分配任务,并监视主机故障。
每个工作节点运行Supervisor守护进程,负责监听工作节点上已经分配的主机作业,启动和停止Nimbus已经分配的工作进程。
supervisor会定时从zookeeper获取拓补信息topologies、任务分配信息assignments及各类心跳信息,以此为依据进行任务分配。
在supervisor同步时,会根据新的任务分配情况来启动新的worker或者关闭旧的worker并进行负载均衡。
Worker是具体处理Spout/Bolt逻辑的进程,根据提交的拓扑中conf.setNumWorkers(3);定义分配每个拓扑对应的worker数量,Storm会在每个Worker上均匀分配任务,一个Worker只能执行一个topology,但是可以执行其中的多个任务线程。
任务是指Worker中每个Spout/Bolt线程,每个Spout和Bolt在集群中会执行许多任务,每个任务对应一个线程执行,可以通过TopologyBuilder类的setSpout()和setBolt()方法来设置每个Spout或者Bolt的并行度。
当仅有Worker进程死亡时,其主机上的Supervisor会尝试重启Worker进程,如果连续重启都失败,当超过一定的失败次数之后,Nimbus会在其他主机上重启Worker。
当Supervisor死亡时,如果某个主机上的Worker死亡了,由于没有Supervisor,所以无法在本机重启Worker,但会在其他主机上重启Worker,当Supervisor重启以后,会将本机的Worker重启,而之间在其他主机上重启的Worker则会消失,例如之前node2有三个Worker,node3有三个Worker,当node2的Supervisor死亡并且kill掉一个Worker之后,node3出现四个Worker,重启node2的Supervisor之后,node2会重启一个Worker,恢复成三个Worker,node3kill掉多余的一个Worker,也恢复成三个Worker。
当Nimbus死亡时,Worker也会继续执行,但是某个Worker死亡时不会像Supervisor死亡时安排到其他主机上执行,因此如果Worker全部死亡,则任务执行失败。
集群中的Worker是均匀分配到各节点上的,例如一个作业有三个Worker时,会在一个节点(例如node2)分配两个Worker,在一个节点(例如node3)分配一个Worker,当再启动一个需要三个Worker的作业时,会在node2分配一个Worker,在node3分配两个Worker。
Nimbus和Supervisor被设计成是快速失败且无状态的,他们的状态都保存在ZooKeeper或者磁盘上,如果这两个进程死亡,它们不会像Worker一样自动重启,但是集群上的作业仍然可以在Worker中运行,并且他们重启之后会像什么都没发生一样正常工作。
ZooKeeper的停止同样不会影响已有的作业运行,此时kill掉Worker以后过段时间仍会在本机重启一个Worker。
综上所述,只有Nimbus失败并且所有Worker都失败之后才会影响集群上的作业运行,除此之外Storm集群的容错机制可以保证作业运行的可靠性。