Storm中有以下几个基本概念:
1. Topologies 拓扑
2. Streams 流
3. Spouts 数据源(喷嘴)
4. Bolts 数据流处理组件(螺栓)
5. Stream groupings 流分组
6. Reliability 可靠性
7. Tasks 任务
8. Workers 工作者

Topologies(拓扑)
Storm topology是对实时逻辑处理应该的封装。它和MapReduce作业很像。关键的区别在于MapReduce作业执行完就结束了,而topology永远在运行(直到你杀死它)。topology是通过stream groupings连接的spouts和bolts组成的图表。当然,你也可以定义序列化的对象来实现自定义的元组类型。

Streams(流)
stream是Storm中核心的抽象概念。stream是以分布式方式并行处理和创建的无限元祖序列。数据流由一种能够标书数据流中元组的域(fields)的模式来定义。默认情况下,元组可以包含integer,long,short,byte,string,double,float,boolean和byte array。

每一个数据流在定义的时候都赋予了一个id。由于在单一数据源的spout和blot比较常见,这种情况下不需要使用id来区分数据流,因为可以使用OutputFieldsDeclarer来定义简单的没有id的数据流。实际上数据流给了默认的id“default”。

Spouts(数据源)
spout是拓扑中数据流的来源。一般spout会从外部的数据源读取元组然后发送到拓扑中。spout分为可靠的或者不可靠的。可靠的spout在处理失败的时候能够重新发送该元组,不可靠的spout在发送完元组之后就会忘记它。

spout可以发送多个数据流。为了实现这个,可以通过 OutputFieldsDeclarer 的declareStream声明多个数据流然后在用poutOutputCollector的emit方法发送的时候指定该数据流。

spout的主要方法是nextTuple.nextTuple要么向拓扑中发送一个新的元组,要么在没有可发送的元组的时候直接返回。需要注意的是,因为storm调用spout的方法都在同一个线程中,nextTuple方法不能被spout的其他方法阻塞,否则会导致数据流的中断。

spout的其他主要方法是ackfail。从spout发出的元组在成功处理或者处理失败的时候调用这两个方法。ackfail方法只有可靠的spout才会调用。

Bolts(数据流处理组件)
拓扑中的所有数据处理是都由blot完成的。blots能够干任何事情通过过滤、函数,聚合,连接,与数据库交互等等。

Bolts可以做简单的流转换。执行负责的流转换通常需要多个步骤和多个bolts。例如,将tweets数据流转换成一个趋势图像的数据流至少需要两个步骤:一个bolt用于对每个图片的转发进行滚动计数,另一个或者多个bolt将数据流输出为转发最多的图片结果(相对于使用2个bolt,如果使用3个bolt你可以有更好的扩展性)。

Blots可以发送多个数据流。为了实现这个功能,可以通过OutputFieldsDeclarer类的declareStream方法来声明不同的数据流,然后在发送数据时在OutputCollectoremit方法中将数据流id作为参数实现数据发送的功能。

在定义Bolt的输入数据流时,你需要订阅另一个组件的指定的流。如果你想订阅其他组件的所有流,你必须分别订阅每一个流。对于声明为默认id(default)的数据流,InputDeclarer支持订阅此类数据流的语法糖。也就是说,如果想要订阅来自组件“1”的数据流,declarer.shuffleGrouping(“1”)与declarer.shuffleGrouping(“1”,DEFAULT_STREAM_ID)两种声明方式是等价的。

Blot的关键方法是execute方法。execute方法负责接收一个元组作为输入,使用OutputCollector发送新的元组。Bolt必须为它所处理的每一个元组调用OutputCollectorack方法,以便storm能够了解元组是否处理完成(并且最终决定是否可以相应最初的spout元组)。一般情况下,对于每个输入元组,在处理之后可以根据需要选择不发送还是发送多个新元组,然后再响应(ack)输入元组。Storm提供的IBasicBolt接口能够实现元组的自动应答。

在Bolt中启动新县城进行异步处理是一种非常好的方式,因为OutputCollector是线程安全的,可以在任何时候进行调用。

Stream groupings(流分组)
为每一个bolt确定输入数据流是定义一个拓扑的重要部分。数据流分组定义了在bolt的任务之间数据流将如何划分。

Storm有八种内置的数据流分组方式。你也可以通过实现CustomStreamGrouping接口来实现一个自定义的流分组。

  1. Shuffle grouping:元组将在bolt的任务之间随机分配以保证每个任务都能得到同等数量的元组。
  2. Fields grouping:数据流通过指定的域来分组。例如,如果数据流通过“user-id”字段来分组,所有相同“user-id”的元组都将分配到同一个任务,但是不同“user-id”的元组将分配到不同的任务。
  3. Partial Key grouping:数据流根据指定的域来分组,它跟Fields grouping很像,但是会在下流的两个bolt之间负载均衡,当输入数据倾斜的时候提高了资源利用率。
  4. All grouping:数据流将复制多份传给所有bolt的任务。使用这种分组的时候要小心了。
  5. Global grouping:整个数据流将发送到bolt的一个任务中,是id最小的那个任务。
  6. None grouping:这种情况下你不需要关心数据流如何分组。目前,none grouping和shuffle grouping是等价的。最终,storm可能通过none grouping来让bolt和它所订阅的spout或者bolt在同一线程中执行。
  7. Direct grouping:这是一种特殊的分组方法。使用这种方法意味着元组的发送者可以指定下游的那个任务可以接收该元组。只有在数据流被声明为直接数据流时才能够使用直接分组方式。使用直接数据流发送元组需要使用OutputCollectoremitDirect方法。Bolt可以通过TopologyContext来获取它下游消费者的任务id,也可以通过跟踪OutputCollectoremit方法的数据来获取任务id。
  8. Local or shuffle grouping:如果目标bolt在相同的worker进程中有一个或者多个任务,元组将会转移到进程内的任务中。否则,和shuffle grouping一样。

Reliability(可靠性)
Storm保证每个spout元组都能够被拓扑完全的处理掉。通过跟踪每个spout元组组成的元祖树,来确定元组树是否成功的完成。每一个拓扑都有一个“消息超时”参数。如果storm在规定的超时时间内没有检测到spout元组被成功完成,则会标记该元组为失败并且稍候会重新执行。

为了利用storm的可靠性机制,你必须在元组树创建新节点的时候以及元组处理完的时候通知storm。在bolt发送元组的时候通过OutputCollector对象来实现。在emit方法中实现元组锚定,使用ack方法来声明你已经完成了元组的处理。

Tasks(任务)
每个spout或者bolt在集群中执行多个任务。每个任务对应一个执行线程,数据流分组定义如何将元组从一组任务发送到另一组任务。通过TopologyBuildersetSpoutsetBolt方法为每一个spout或者bolt设置并行。

Workers(工作者)
拓扑是通过一个或者多个worker 进程。每一个worker进程都是一个实际的jvm进程,并且执行拓扑所有任务的一个子集。例如,如果定义拓扑的并行度为300并且分配50个worker,则每个worker执行6个任务(worker进程内部的线程)。storm将会均匀的分配任务给所有的worker。