Storm概念
Spout(消息源)
Bolt(消息处理者)
Stream grouping(数据的分发方式)
Topology(拓扑)
Worker(工作进程)
Task(执行具体逻辑的任务)
Executor(执行Task的线程)
Configuration(配置)
storm里面各个对象的示意图
计算拓补:Topology
一个实时计算应用程序的逻辑在storm里面被封装到topology对象里面, 我把它叫做计算拓补. Storm里面的topology相当于Hadoop里面的一个MapReduce Job, 它们的关键区别是:一个MapReduce Job最终总是会结束的, 然而一个storm的topoloy会一直运行 — 除非你显式的杀死它。 一个Topology是Spouts和Bolts组成的图状结构, 而链接Spouts和Bolts的则是Stream groupings。
消息源: Spout
消息源Spouts是storm里面一个topology里面的
消息生产者
。一般来说消息源会从一个外部源读取数据并且向topology里面发出消息: tuple。 消息源Spouts可以是
可靠的
也可以是
不可靠的
。一个可靠的消息源可以
重新发射
一个tuple如果这个tuple没有被storm成功的处理, 但是一个不可靠的消息源Spouts一旦发出一个tuple就把它彻底忘了 — 也就不可能再发了。
消息源Spouts
可以发射
多条消息流stream
。要达到这样的效果, 使用OutFieldsDeclarer.declareStream来定义多个stream, 然后使用SpoutOutputCollector来发射指定的sream。
消息处理者: Bolt
所有的消息处理逻辑被封装在bolts里面。 Bolts可以做很多事情:
过滤, 聚合, 查询数据库等等
。
Bolts的主要方法是
execute
, 它以一个tuple作为输入,Bolts使用OutputCollector来发射tuple, Bolts必须要为它处理的每一个tuple调用OutputCollector的
ack方法
,以
通知storm这个tuple被处理完成
了。– 从而我们通知这个tuple的发射者Spouts。 一般的流程是: Bolts处理一个输入tuple, 发射0个或者多个tuple, 然后调用ack通知storm自己已经处理过这个tuple了。
storm提供了一个IBasicBolt会自动调用ack。
Worker
Supervisor会监听分配给它那台机器的工作,根据需要启动/关闭工作进程,这个工作进程就是worker
每一个worker都会占用工作节点的一个端口,这个
端口可以在storm.yarm中配置
。
一个topology可能会在一个或者多个工作进程里面执行,每个工作进程执行整个topology的一部分,所以一个运行的topology由运行在很多机器上的很多工作进程组成
。
Task:任务
每一个Spout和Bolt会被当作很多task在整个集群里面执行。
默认情况下每一个task对应到一个线程(Executor
),这个线程用来执行这个task,而stream grouping则是定义怎么从
一堆
task发射
tuple
到另外一堆task。
配置Configuration
storm里面有一堆参数可以配置来调整nimbus, supervisor以及正在运行的topology的行为, 一些配置是系统级别的, 一些配置是topology级别的。所有有默认值的配置的默认配置是配置在default.xml里面的。你可以通过定义个storm.xml在你的classpath厘米来覆盖这些默认配置。并且你也可以在代码里面设置一些topology相关的配置信息 – 使用StormSubmitter。当然,这些配置的优先级是: default.xml < storm.xml < TOPOLOGY-SPECIFIC配置。
消息流:Stream
消息流是storm里面的最关键的抽象。一个消息流是一个没有边界的tuple序列, 而这些tuples会被以一种分布式的方式并行地创建和处理。 对消息流的定义主要是对消息流里面的tuple的定义, 我们会给tuple里的每个字段一个名字。 并且不同tuple的对应字段的类型必须一样。 也就是说: 两个tuple的第一个字段的类型必须一样, 第二个字段的类型必须一样, 但是第一个字段和第二个字段可以有不同的类型。 在默认的情况下, tuple的字段类型可以是: integer, long, short, byte, string, double, float, boolean和byte array。 你还可以自定义类型 — 只要你实现对应的序列化器
消息分发策略:Stream groupings
1.
Shuffle Grouping:
随机分组
,随机派发stream里面的tuple,保证每个bolt接收到的tuple数目相同。
2.
Fields Grouping:
按字段分组
,比如按userid来分组,具有同样userid的tuple会被分到相同的Bolts,而不同的userid则会被分配到不同的Bolts。
3.
All Grouping:
广播发送
,对于每一个tuple,所有的Bolts都会收到。
4.
Global Grouping:
全局分组
,这个tuple被分配到storm中的一个bolt的其中一个task。再具体一点就是分配给id值最低的那个task。
5.
Non Grouping:
不分组
,这个分组的意思是说stream不关心到底谁会收到它的tuple。目前这种分组和Shuffle grouping是一样的效果,有一点不同的是storm会把这个bolt放到这个bolt的订阅者同一个线程里面去执行。
6.
Direct Grouping:
直接分组
, 这是一种比较特别的分组方法,用这种分组意味着消息的发送者指定由消息接收者的哪个task处理这个消息。只有被声明为Direct Stream的消息流可以声明这种分组方法。而且这种消息tuple必须使用emitDirect方法来发射。消息处理者可以通过TopologyContext来获取处理它的消息的taskid (OutputCollector.emit方法也会返回taskid)
7.
Local or shuffle grouping:如果目标bolt有一个或者多个task在同一个工作进程中,tuple将会被随机发生给这些tasks。否则,和普通的Shuffle Grouping行为一致。