内容
核心概念
Apache Storm从一端读取实时数据的原始流,并通过一系列小处理单元传递它,并在另一端输出处理过的有用的信息。下图描述了Apache Storm的核心概念。
现在让我们仔细看看Apache Storm的组件:
组件 |
描述 |
Tuple |
Tuple是Storm中的主要数据结构。 它是有序元素的列表。 默认情况下,Tuple支持所有数据类型。 通常,它被建模为一组用逗号分隔开并传递给Storm集群的值。 |
Stream |
Stream是Storm中的核心抽象。一个Stream由无限的Tuple序列组成,这些元组会被分布式并行地创建和处理。通过Stream中Tuple包含的字段名称来定义这个Stream。
|
Spout |
Stream的来源。 一般来说,Storm接受来自原始数据源的输入数据,例如Twitter Streaming API,Apache Kafka队列,Kestrel队列等。另外,您可以写Spout以从数据源读取数据。 “ISpout”是实现Spout的核心接口,一些特定的接口是IRichSpout,BaseRichSpout,KafkaSpout等。 |
Bolt |
Bolt是逻辑处理单元。 Spouts将数据传递到Bolt然后Bolt处理这些数据并生成新的输出流。 Bolt可以执行过滤(filtering),聚合(aggregation),连接(joining),与数据源和数据库进行交互(interacting)的操作。 Bolt接收数据并发射到一个或多个其他的Bolt。 “IBolt”是实现Bolt的核心接口。 一些常见的接口是IRichBolt,IBasicBolt等。 |
我们来看一个“Twitter分析”的实时示例,看看它如何在Apache Storm中建模。下图描述了结构:
“Twitter Analysis”的输入来自Twitter Streaming API。 Spout将使用Twitter Streaming API读取用户的推文,并将其输出为Tuple流。 来自Spout的每个Tuple以twitter用户名和一个推文作为值并用逗号分开。 然后,这组Tuple将被转发给Bolt,Bolt把推文分成单独的单词,计算单词数量,并将信息保存到指定的数据源中。 现在,我们可以通过查询数据源轻松获得结果。
1.Topology
Spouts和Bolts连接在一起,形成一个Topology,实时应用程序逻辑在这个Storm Topology中指定。 简而言之,一个Topology是一个有向图,其顶点是计算,边是数据流。一个简单的Topology开始于Spouts,Spout将数据发送到一个或多个Bolts。 Bolt表示Topology中具有最小处理逻辑的节点,并且Bolt的输出可以作为输入发射到另一Bolt中。Storm将一直运行Topology,直到用户终止它。 Apache Storm的主要工作是运行Topology,并在给定的时间运行任意数量的Topology。
2.Task
Spout和Bolt是 Topology中最小的逻辑单元,一个Topology是使用一个Spout和一组Bolt构建的。 Spout和Bolt应该以特定的顺序正确执行,以便Topology成功运行。 Storm中对每个Spout和Bolt的执行称为“任务”。 简单来说,一个任务就是执行一个Spout或者一个Bolt。 在给定时间内,每个Spout和Bolt都可以有多个实例在多个单独的线程中运行。
3.Worker
Topology在多个工作节点(Worker)上以分布式方式运行。 Storm将任务平均分配在所有的工作节点上。 工作节点的角色是监听作业,并在新作业到达时启动或停止进程。
4.Stream Grouping
数据流从Spouts流向 Bolts或从一个Bolt流向另一个Bolt。 流分组(Stream grouping)控制Tuple在Topology中的前进路径,并帮助我们理解Tuple在Topology中的传输。 如下所述,Storm中有八种内置分组。你也可以通过实现CustomStreamGrouping接口来自定义一个流分组策略。
a). Shuffle Grouping
在随机分组中,相同数量的元组随机分布在所有执行Bolt的Worker中。 下图描述了随机分组的场景。
b). Field Grouping
Tuple中相同值的字段被组合在一起,剩下的Tuple留在外面。 然后,将具有相同字段值的Tuple发送给执行Bolt的同一个Worker。 例如,如果流按字段“word”分组,则具有相同字符串“Hello”的Tuple将移至同一个Worker。 下图显示了Field Grouping的工作原理。
c). Globle Grouping
所有的流可以分组并转发给一个Bolt。 此分组将源的所有实例生成的Tuple发送到单个目标实例(具体来说,选择ID最小的Worker)。
d). All Grouping
All Grouping将每个Tuple的单个副本发送到接收Bolt的所有实例。 这种分组被用于向Bolt发送信号。 All Grouping对于连接(join)操作都很有用。
e). Partial Key Grouping
跟Field Grouping一样,流也是用指定的分组字段进行分组的,但是在多个下游Bolt之间是有负载均衡的,这样当输入数据有倾斜时可以更好的利用资源。这篇论文很好的解释了这是如何工作的,有哪些优势。
f). None Grouping
即不用关心流是如何分组的,目前None Grouping等价于Shuffle Grouping
g). Direct Grouping
一种特殊的分组。对于这样分组的流,Tuple的生产者决定消费者的哪个任务会接收处理这个Tuple。只能在声明做直连的流(direct streams)上声明Direct groupings分组方式。只能通过使用org.apache.storm.task.OutputCollector.java类里的
emitDirect方法来发射Tuple给直连流。一个Bolt可以通过提供的TopologyContext来获得消费者的任务ID,也可以通过OutputCollector对象的emit函数(会返回Tuple被发送到的任务的ID)来跟踪消费者的任务ID。在ack的实现中,Spout有两个直连输入流,ack和ackFail,使用了这种直连分组的方式。
h). Local or shuffle grouping
如果目标Bolt在同一个worker进程里有一个或多个任务,Tuple就会通过洗牌(Shuffle)的方式被分配到这些同一个进程内的任务里。否则,就跟普通的洗牌分组(Shuffle Grouping)一样。这种方式的好处是可以提高Topology的处理效率,因为worker内部通信就是进程内部通信了,相比Topology之间的进程间通信要高效的多。worker进程间通信是通过使用Netty来进行网络通信的。
5. Reliability(可靠性)
Storm保证了Topology中Spout产生的每个Tuple都会被处理,Storm是通过跟踪每个Spout所产生的所有Tuple构成的树形结构并得知这棵树何时被完整地处理来达到可靠性。每个Topology对这些树形结构都有一个关联的“消息超时”设置,如果在这个超时时间里Storm检测到Spout产生的一个Tuple没有被成功处理完,那这个Tuple就被认为处理失败了,后续会重新处理一遍。
为了发挥Storm的可靠性,需要你在创建一个Tuple树中的一条边时告诉Storm,也需要在处理完每个Tuple之后告诉Storm。这些都是通过Bolt发射Tuple数据用的OutputCollector对象来完成的。标记(anchoring)在emit方法里完成,处理完一个Tuple后需要使用ack方法来告诉Storm。