Apache Storm 简介和编程模型

1.简介

    Storm是由Twitter公司开源的一个实时分布式流处理系统,被广泛应用在实时分析、在线机器学习连续计算(continuous computation)、分布式RPCETL等场景。Storm支持水平扩展、具有高容错性,保证数据能被处理,而且处理速度很快。Storm还支持多种编程语言,易于部署和管理,是目前广泛使用的流处理系统之一。

2.系统架构


 5.17 Storm系统架构[4]

 

    图5.17是整个Storm系统的架构,Storm运行在一个分布式的集群上。Storm集群采用的是主从架构方式,Storm的集群有两类节点:主控节点和工作节点,集群的各个组件如下:

(1) Nimbus

       运行Nimbus的节点是Storm集群的主控节点,Nimbus类似HadoopJobTracker的角色,是用户和Storm系统之间的交互点。Nimbus主要的工作是用于用户提交任务、分配集群任务、集群监控等。

(2) Supervisor

每个工作节点上都运行着一个SupervisorSupervisor用于接收Nimbus分配的任务,并根据分配产生worker进程。同时它还会监视worker的健康状况,在必要的情况下会重启worker进程。

(3) ZooKeeper

    NimbusSupervisor之间的所有协调工作都是通过ZooKeeper集群完成的。另外,NimbusSupervisor进程都是快速失败(fail-fast)和无状态(stateless)的,所有的状态要么在本地磁盘上要么在ZooKeeper上。这就是说,如果Nimbus服务失败了,所有的worker还是会继续执行完成当前的拓扑;如果worker失败了,那么Supervisor会重启它们,这样的设计保证了Storm的可靠性。但是这样的设计上依然存在一些问题,比如 Nimbus的机器宕机会造成用户就不能再提交拓扑;运行拓扑的机器宕机了,在Nimbus进程恢复之前,这些机器上task将不会被重新分配到其他机器。因此,在Storm1.0.0之后Nimbus就被设计成高可用(HA)。

3. 一致性语义

Storm支持三种计算语义,at-most-onceat-least-onceexactly-once

at-most-once:每个tuple最多被处理一次,即编程时不需要实现failack方法,每个spout针对相同的tuple只发送一次。

at-least-once:保证每个tuple至少会被拓扑完整执行一次,Storm通过acker机制追踪每个tuple所产生的tuple树可以确定tuple是否已经完成处理。而且拓扑会有一个消息超时时间的设置,如果在规定时间内tuple树没有被执行成功,那么拓扑会将这个tuple标记为执行失败,然后重发这个tuple。这样可以保证每个tuple至少被处理一次,但是这样可能会出现一个tuple会被多次处理的情况。

exactly-once:保证每个tuple有且只被处理一次,效率不高。Storm提供了一套事务性组件TransactionalTopology来解决这个问题,目前这个组件已经不再维护,现在由Trident来实现Topology,但是原理是一样的。具体的原理和使用可以参考官网的文档。

Storm并不像Spark Streaming那样考虑了慢节点问题,因此无法保证强一致性(参考Spark Streaming那章)。

4. Apache Storm编程模型

4.1 数据模型

      流(Stream)是Storm的一个重要抽象概念。一个Stream是一个无边界的tuple序列,而这些tuple序列是以分布式的方式创建和处理的。tuple是消息传递中的基本单元,数据结构如下图所示:


5.19 tuple数据结构

一个tuple可以包含多个field,每个field表示一个属性,tuple字段名称已经事先预定好了,因此tuple就是一个值列表。一个没有边界、源源不断的tuple序列就组成了Stream

4.2 计算模型

         其计算模型,主要由以下概念:

(1) Topology

Storm中,用户提交的应用被表示为一个Topology(拓扑),类似于MapReduce中的一个job,但区别在于这个拓扑会永远运行(或者直到手动结束)。用户通过Streaming GroupingSpoutBolt连接起来构成一个拓扑。

(2) Spout

消息源Spout是拓扑中消息流的来源。通常Spout会从外部源读取数据并将其发送到拓扑中。Spout可以是可靠的也可以是不可靠的,可靠的Spout可以在一个tuple没有被Storm成功处理时重发这个tuple,以确保tuple至少会被处理一次,但是不可靠的Spout一旦发送完一个tuple就不能重发了。

(3) Bolt

所有对消息流的处理都是在Bolt中实现的,Bolt可以做很多事情:过滤、聚合、join操作等等。Bolt每处理完一个tuple后,可以发送0个或多个tuple给下游的Bolt

(4) Task

每个spout/bolt会被当作很多task在集群中运行,一个task就是一个spout/bolt的实例。

(5) WorkerExecutor

一个拓扑会在一个或者多个worker进程执行,每个worker都是一个物理JVM且执行的只是拓扑的一部分,一个worker只能为一个拓扑执行executor。每个worker会在一个JVM中运行一个或多个executor,而每个executor对应一个线程,可以运行多个taskexecutor会在每次循环里顺序调用所有的task,在Storm中一个executor默认对应一个task

(6) Streaming Grouping

Streaming Grouping定义了一个消息流是如何在两个组件之间分发的,要记住boltspout在集群中是由多个task实例并行执行的。如果从task的角度来看一个拓扑tuple流在组件之间的分发的话,应该如下图所示:


5.20 StreamingGrouping[14]

 

5.20中,圆圈代表的是task,方框代表的是组件spout/bolt,组件之间的箭头表示的是消息流在组件之间的分发,注意每个组件的task不一定都在同一个worker进程中,上图是从task的角度来看流分组的过程。具体有哪些分发策略,可以回顾之前讲的流数据分组。

4.3 基本操作

         Storm编写代码,Spout是发送数据的源,Bolt是处理逻辑组件,这些组件实现是用户自己实现的。Storm提供一些组件间的分发策略,可以回顾之前讲的流数据分组,如Shuffle GroupingFields Grouping等策略,这些策略是Strom实现好的,用户只需要用分组策略将这些组件组成一个DAG即可。

 

4.4 编程模型实例分析

编写程序时,我们需要实现相应的Spout组件、Bolt处理逻辑组件的代码,然后将这些组件组成一个拓扑提交到集群即可。下面以一个单词计数的组件作为示例来了解编程模型,


XXX-单词计数拓扑

图来源:Storm-SIGMOD14

该拓扑定义了三个组件TweetSpoutParseTweetBoltWordCountBolt,作用分别是发送推文tuple、对推文tuple进行单词分割、统计每个单词的数量。每个组件的并行度(即instance数量)在代码中指定,注意TweetSpoutParseTweetBolt组件之间用的是Shuffle Grouping的分发策略,是为了使ParseTweetBolt的实例任务被分配的任务均匀些,而ParseTweetBoltWordCountBolt组件之间用的是Fields Grouping策略,保证了相同单词一定在同一个WordCountBolt实例中统计个数。

       Topology核心代码:

 

文本框: //创建一个TopologyBuilder
TopologyBuilder tb = new TopologyBuilder();
//将Spout、Bolt连接成一个拓扑,并且指定每个组件运行的executor数量和组件之间的shuffle方式,默认一个executor使用一个task实例
tb.setSpout("SpoutBolt", new CreateSentenceSpout(), 2);
tb.setBolt("SplitBolt", new SpiltWordBolt(), 2).shuffleGrouping("SpoutBolt");
tb.setBolt("CountBolt", new CountBolt(), 4).fieldsGrouping("SplitBolt", new Fields("word"));
//创建配置
Config conf = new Config();
//设置worker数量
conf.setNumWorkers(2);//每一个Worker 进程默认都会对应一个Acker 线程,用于容错
//提交任务
//集群提交
//StormSubmitter.submitTopology("myWordcount", conf, tb.createTopology());
//本地提交
LocalCluster localCluster = new LocalCluster();
localCluster.submitTopology("myWordcount", conf, tb.createTopology());


4.5 Topology的并行度

通过前面的小节知道,用户提交的应用被表示为一个topology,然后提交到Storm集群中运行的。在Storm集群中运行的topology主要有三个主体:worker进程、Executor(线程)、task(任务),三个主体之间的关系在上节已经讲过,下面通过一个例子来理解上节的概念和一个topology的并行度。


5.21 拓扑并行度计算[15]

 

如图5.21所示,该拓扑由三个组件构成:BlueSpoutGrennBoltYellowBolt,形成了一个有向无环图(DAG)。这三个组件可以分别生成多个线程来进行并行处理。图中,这三个组件对应的线程个数分别被设置为226,以每个线程处理的单位在Storm中被称为executor。假设运行这个拓扑的worker进程数量是2个(worker可以在一个或多个节点上),那么每个worker将会分配10/2=5个线程。如上图所示,最后每个worker分配了1个有两个taskGreenBolt的线程、1个有一个taskBlueBolt的线程、3个有一个taskYellowBolt的线程。

每个executor默认对应一个task进行计算,然而Storm中也可以进一步设置每个executor生成多个task实例来进行并行计算。例如,图中GreenBolt每个Executortask数为2BlueSpoutYellowBolttask数为1。因此,在图中,GreenBolt的实际task并行度为4

猜你喜欢

转载自blog.csdn.net/qq_21125183/article/details/80582306