开源流计算框架Storm
一、Storm简介
批处理系统关注吞吐率,流处理系统关注延时
Storm可以简单、高效、可靠地处理流数据,并支持多种编程语言
Storm框架可以方便地与数据库系统进行整合,从而开发出强大的实时计算系统
Twitter是全球访问量最大的社交网站之一,Twitter开发Storm流处理框架也是为了应对其不断增长的流数据实时处理需求

二、Storm的特点
Storm可用于许多领域中,如实时分析、在线机器学习、持续计算、远程RPC、数据提取加载转换等
Storm具有以下主要特点:
整合性:Storm可方便地与队列系统和数据库系统进行整合,
简易的API:Storm的API在使用上即简单又方便
可扩展性:Storm的并行特性使其可以运行在分布式集群中
容错性:Storm可自动进行故障节点的重启、任务的重新分配
可靠的消息处理:Storm保证每个消息都能完整处理
支持各种编程语言:Storm支持使用各种编程语言来定义任务
快速部署:Storm可以快速进行部署和使用
免费、开源:Storm是一款开源框架,可以免费使用
三、Storm设计思想
Storm主要术语包括Streams、Spouts、Bolts、Topology和Stream Groupings
1、Streams(流数据Tuple序列)
Storm将流数据Stream描述成一个无限的Tuple序列,这些Tuple序列会以分布式的方式并行地创建和处理

每个tuple是一堆值,每个值有一个名字,并且每个值可以是任何类型
Tuple本来应该是一个Key-Value的Map,由于各个组件间传递的tuple的字段名称已经事先定义好了,所以Tuple只需要按序填入各个Value,所以就是一个Value List(值列表)
Tuple中结构如下:(Key已事先定义好了,所以只需填入各个Value即可。词频统计中,Key一般为"word",Value就是每一个单词,即每个Field就是单词)

2、Spout(Streams的源头)
Storm认为每个Stream都有一个源头,并把这个源头抽象为Spout
通常Spout会从外部数据源(队列、数据库等)读取数据,然后封装成Tuple形式,发送到Stream中。Spout是一个主动的角色,在接口内部有个nextTuple函数,Storm框架会不停的调用该函数

3、Bolt(Streams的状态转换和处理过程)
Bolt:Storm将Streams的状态转换和处理过程(也包括对Tuple的处理逻辑)抽象为Bolt。Bolt即可以处理Tuple,也可以将处理后的Tuple作为新的Streams发送给其他Bolt
Bolt可以执行过滤、函数操作、Join、操作数据库等任何操作
Bolt是一个被动的角色,其接口中有一个execute(Tuple input)方法,在接收到消息之后会调用此函数,用户可以在此方法中执行自己的处理逻辑
一个Bolt包含多个Task,这些Task可分布于多个节点并行执行。
4、Topology(Spouts和Bolts组成的网络抽象,也是用户提交的流计算任务,对应Job)
Topology:Storm将Spouts和Bolts组成的网络抽象成Topology,它可以被提交到Storm集群执行。Topology可视为流转换图,图中节点是一个Spout或Bolt,边则表示Bolt订阅了哪个Stream。当Spout或者Bolt发送元组时,它会把元组发送到每个订阅了该Stream的Bolt上进行处理
Topology里面的每个组件(Spout或Bolt)都包含处理逻辑, 而组件之间的连接则表示数据流动的方向
Topology里面的每一个组件都是并行运行的
Topology相当于用户提交的流计算任务,对应Hadoop批量处理中的Job。 作业以Topology(Spark)或Job(MapReduce)形式提交执行。
在Topology里面可以指定每个组件(如spout、bolt)的并行度, Storm会在集群里面分配那么多的线程来同时计算。(如并行度是5,则有5个线程并行执行)
在Topology的具体实现上,Storm中的Topology定义仅仅是一些Thrift结构体(二进制高性能的通信中间件),支持各种编程语言进行定义(Thrift结构体与具体编程语言无关,所以可用各种编程语言来定义Thrift结构体)
即用Thrift结构来描述Topology,即描述各个Spout与Bolt间、Bolt之间Tuple如何流转,如何被处理。
5、Stream Groupings(用于告知Topology在两个组件间进行Tuple传送的方式)
Storm中的Stream Groupings用于告知Topology如何在两个组件间(如Spout和Bolt之间,或者不同的Bolt之间)进行Tuple的传送。每一个Spout和Bolt都可以有多个分布式任务,一个任务在什么时候、以什么方式发送Tuple就是由Stream Groupings来决定的

上图中一个圆圈表示一个Task任务,这些Task任务可分布式运行与多个节点。
目前,Storm中的Stream Groupings有如下几种方式:
(1)ShuffleGrouping:随机分组,随机分发Stream中的Tuple,保证每个Bolt的Task接收Tuple数量大致一致;负载均衡
(2)FieldsGrouping:按照字段分组,保证相同字段Field的Tuple分配到同一个Task中(词频统计)
(3)AllGrouping:广播发送,每一个Task都会收到所有的Tuple
(4)GlobalGrouping:全局分组,所有的Tuple都发送到同一个Task中
(5)NonGrouping:不分组,和ShuffleGrouping类似,当前Task的执行会和它的被订阅者在同一个线程中执行
(6)DirectGrouping:直接分组,直接指定由某个Task来执行Tuple的处理
四、Storm框架设计
Storm运行任务的方式与Hadoop类似:Hadoop运行的是MapReduce作业,而Storm运行的是“Topology”(Topology描述Tuple如何被转发和处理,Storm流计算就是对Tuple的处理,所以Storm的作业就是Topology)
但两者的任务大不相同,主要的不同是:MapReduce作业最终会完成计算并结束运行,而Topology将持续处理消息(直到人为终止,类似守护进程)

系统角色中,JobTracker和Nimbus负责作业管理,TaskTracker和Supervisor负责任务管理。
Storm集群采用“Master—Worker”的节点方式(主从方式,Master作为管家):
Master节点运行名为“Nimbus”的后台程序(类似Hadoop中的“JobTracker”),负责在集群范围内分发代码、为Worker分配任务和监测故障
Worker节点运行名为“Supervisor”的后台程序,负责监听分配给它所在机器上运行的Task,即根据Nimbus分配的任务来决定启动或停止Worker进程,一个Worker节点上同时运行若干个Worker进程。每个Worker进程用多线程方式运行Task。
Storm使用Zookeeper来作为分布式协调组件,负责Nimbus和多个Supervisor之间的所有协调工作。Nimbus和Supervisor之间借助Zookeeper通信。
用户提交的作业、Nimbus和Supervisor的状态信息都保存于Zookeeper。借助于Zookeeper,若Nimbus进程或Supervisor进程意外终止,重启时也能读取Zookeeper中保存之前的Nimbus或Supervisor状态信息并继续工作,使得Storm极其稳定。

(1)worker:每个worker进程都属于一个特定的Topology;每个Supervisor节点的worker进程可以有多个;每个worker为Topology中的每个组件(Spout或 Bolt)运行一个或者多个executor线程来提供task的运行服务
(2)executor:executor是产生于worker进程内部的线程,会执行同一个组件的一个或者多个task。
(3)task:实际的数据处理由task完成,在Topology的生命周期中,每个组件的task数目是不会发生变化的,而executor的数目却不一定。executor数目小于等于task的数目。默认情况下,二者是相等的(即一般一个executor执行一个Task)。

基于这样的架构设计,Storm的工作流程如下图所示:
1、Storm客户端节点负责提交Topology作业,然后由Nimbus节点把作业分配给Supervisor节点进行处理(作业分配后提交给Zookeeper,Supervisor从Zookeeper领取任务)
2、Nimbus节点首先将提交的Topology作业进行分片,分成一个个Task,分配给相应的Supervisor,并将Task和Supervisor相关的信息提交到Zookeeper集群上
3、Supervisor会去Zookeeper集群上认领自己的Task,通知自己的Worker进程启动executor线程进行Task的处理
说明:在提交了一个Topology之后,Storm就会创建Spout/Bolt实例(即实例化对象,包含了对Tuple的处理逻辑)并进行序列化。之后,将序列化的组件发送给所有的任务所在的机器(即Supervisor节点),在每一个任务上反序列化组件
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。 序列化的实现:将需要被序列化的类

浙公网安备 33010602011771号