页面树结构

版本比较

标识

  • 该行被添加。
  • 该行被删除。
  • 格式已经改变。

本页主要列出了 Storm 的主要概念和资源链接,在链接里你可以发现更多的信息。概念如下:

  1. 拓扑(Topologies)Topologies(拓扑)
  2. 流(Streams)Streams(流)
  3. 数据源(Spouts)Spouts(数据源)
  4. 数据流处理组件(Bolts)Bolts(数据流处理组件)
  5. 数据流分组(Stream groupings)Stream groupings(数据流分组)
  6. 可靠性(Reliability)Reliability(可靠性)
  7. 任务(Tasks)Tasks(任务)
  8. 工作进程(Workers)Workers(工作进程)

Topologies(拓扑

...

Storm 的拓扑是对实时计算应用逻辑的封装,它的作用与 MapReduce 的任务(Job)很相似,区别在于 MapReduce 的一个 Job 在得到结果之后总会结束,而拓扑会一直在集群中运行,直到你手动去终止它。拓扑还可以理解成由一系列通过数据流(Stream Grouping)相互关联的 Spout 和 Bolt 组成的的拓扑结构。Spout 和 Bolt 称为拓扑的组件(Component)。我们会在后文中给出这些概念的解释。

...

  • TopologyBuilder:在 Java 中使用此类构造拓扑
  • 在生产环境中运行拓扑
  • 本地模式:通过本文学习如何在本地模式中开发、测试拓扑

...

Streams(数据流)

数据流(Streams)是 Storm 中最核心的抽象概念。一个数据流指的是在分布式环境中并行创建、处理的一组元组(tuple)的无界序列。数据流可以由一种能够表述数据流中元组的域(fields)的模式来定义。在默认情况下,元组(tuple)包含有整型(Integer)数字、长整型(Long)数字、短整型(Short)数字、字节(Byte)、双精度浮点数(Double)、单精度浮点数(Float)、布尔值以及字节数组等基本类型对象。当然,你也可以通过定义可序列化的对象来实现自定义的元组类型。

...

  • 元组(Tuple):数据流由多个元组构成
  • OutputFieldsDeclarer:用于声明数据流和数据流对应的模式
  • 序列化(Serialization):关于 Storm 元组的动态类型以及声明自定义序列化模型的相关内容

...

Spouts(数据源)

数据源(Spout)是拓扑中数据流的来源。一般 Spout 会从一个外部的数据源读取元组然后将他们发送到拓扑中。根据需求的不同,Spout 既可以定义为可靠的数据源,也可以定义为不可靠的数据源。一个可靠的 Spout 能够在它发送的元组处理失败时重新发送该元组,以确保所有的元组都能得到正确的处理;相对应的,不可靠的 Spout 就不会在元组发送之后对元组进行任何其他的处理。

...

  • IRichSpout:这是实现 Spout 的接口
  • 消息的可靠性处理

...

Bolts(数据流处理组件)

拓扑中所有的数据处理均是由 Bolt 完成的。通过数据过滤(filtering)、函数处理(functions)、聚合(aggregations)、联结(joins)、数据库交互等功能,Bolt 几乎能够完成任何一种数据处理需求。

...

  • IRichBolt:用于定义 Bolt 的基本接口
  • IBasicBolt: 用于定义带有过滤或者其他简单的函数操作功能的 Bolt 的简便接口
  • OutputCollector:Bolt 使用此类来发送数据流
  • 消息的可靠性处理

...

Stream

...

groupings(数据流分组)

  1. 为拓扑中的每个 Bolt 的确定输入数据流是定义一个拓扑的重要环节。数据流分组定义了在 Bolt 的不同任务(tasks)中划分数据流的方式。
  2. 在 Storm 中有八种内置的数据流分组方式,而且你还可以通过CustomStreamGrouping 接口实现自定义的数据流分组模型。这八种分组分时分别为:
  3. 随机分组(Shuffle grouping):这种方式下元组会被尽可能随机地分配到 Shuffle grouping(随机分组):这种方式下元组会被尽可能随机地分配到 Bolt 的不同任务(tasks)中,使得每个任务所处理元组数量能够能够保持基本一致,以确保集群的负载均衡。
  4. 域分组(Fields grouping):这种方式下数据流根据定义的“域”来进行分组。例如,如果某个数据流是基于一个名为“userFields grouping(域分组):这种方式下数据流根据定义的“域”来进行分组。例如,如果某个数据流是基于一个名为“user-id”的域进行分组的,那么所有包含相同的“user-id”的元组都会被分配到同一个任务中,这样就可以确保消息处理的一致性。
  5. 部分关键字分组(Partial Partial Key grouping):这种方式与域分组很相似,根据定义的域来对数据流进行分组,不同的是,当数据倾斜的时候,会在下游的两个 grouping(部分关键字分组):这种方式与域分组很相似,根据定义的域来对数据流进行分组,不同的是,当数据倾斜的时候,会在下游的两个 Bolt 间进行负载均衡,它能更好的利用资源。感兴趣的读者可以参考这篇论文,其中详细解释了这种分组方式的工作原理以及它的优点。
  6. 完全分组(All grouping):这种方式下数据流会被同时发送到 All grouping(完全分组):这种方式下数据流会被同时发送到 Bolt 的所有任务中(也就是说同一个元组会被复制多份然后被所有的任务处理),使用这种分组方式要特别小心。
  7. 全局分组(Global grouping):这种方式下所有的数据流都会被发送到 Global grouping(全局分组):这种方式下所有的数据流都会被发送到 Bolt 的同一个任务中,也就是 id 最小的那个任务。
  8. 非分组(None grouping):使用这种方式说明你不关心数据流如何分组。目前这种方式的结果与随机分组完全等效,不过未来 None grouping(非分组):使用这种方式说明你不关心数据流如何分组。目前这种方式的结果与随机分组完全等效,不过未来 Storm 社区可能会考虑通过非分组方式来让 Bolt 和它所订阅的 Spout 或 Bolt 在同一个线程中执行。
  9. 直接分组(Direct grouping):这是一种特殊的分组方式。使用这种方式意味着元组的发送者可以指定下游的哪个任务可以接收这个元组。只有在数据流被声明为直接数据流时才能够使用直接分组方式。使用直接数据流发送元组需要使用 Direct grouping(直接分组):这是一种特殊的分组方式。使用这种方式意味着元组的发送者可以指定下游的哪个任务可以接收这个元组。只有在数据流被声明为直接数据流时才能够使用直接分组方式。使用直接数据流发送元组需要使用 OutputCollector 的其中一个 emitDirect 方法。Bolt 可以通过 TopologyContext 来获取它的下游消费者的任务 id,也可以通过跟踪 OutputCollector 的 emit 方法(该方法会返回它所发送元组的目标任务的 id)的数据来获取任务 id。
  10. 本地或随机分组(Local Local or shuffle grouping):如果在源组件的 grouping(本地或随机分组):如果在源组件的 worker 进程里目标 Bolt 有一个或更多的任务线程,元组会被随机分配到那些同进程的任务中。换句话说,这与随机分组的方式具有相似的效果。

...

  • TopologyBuilder:使用此类构造拓扑
  • InputDeclarer:在 TopologyBuilder 中调用 setBolt 方法时会返回这个对象的实例,通过该对象就可以定义 Bolt 的输入数据流以及数据流的分组方式

...

Reliability(可靠性)

Storm 可以通过拓扑来确保每个发送的元组都能得到正确处理。通过跟踪由 Spout 发出的每个元组构成的元组树可以确定元组是否已经完成处理。每个拓扑都有一个“消息延时”参数,如果 Storm 在延时时间内没有检测到元组是否处理完成,就会将该元组标记为处理失败,并会在稍后重新发送该元组。

...

关于可靠性保障的更多内容可以参考这篇文章:消息的可靠性处理。

...

Tasks(任务)

在 Storm 集群中每个 Spout 和 Bolt 都由若干个任务(tasks)来执行。每个任务都与一个执行线程相对应。数据流分组可以决定如何由一组任务向另一组任务发送元组。你可以在 TopologyBuilder 的 setSpout 方法和 setBolt 方法中设置 Spout/Bolt 的并行度。

...

Workers(工作进程)

拓扑是在一个或多个工作进程(worker processes)中运行的。每个工作进程都是一个实际的 JVM 进程,并且执行拓扑的一个子集。例如,如果拓扑的并行度定义为300,工作进程数定义为50,那么每个工作进程就会执行6个任务(进程内部的线程)。Storm 会在所有的 worker 中分散任务,以便实现集群的负载均衡。

...