简述
为拓扑中的每个 Bolt 的确定输入数据流是定义一个拓扑的重要环节。数据流分组定义了在 Bolt 的不同任务(tasks)中划分数据流的方式。
在 Storm 中有八种内置的数据流分组方式,而且还可以通过 CustomStreamGrouping接口实现自定义的数据流分组模型。(所以总共可以算是九种分组方式)
具体分组
这八种分组分时分别为:
- Shuffle grouping:随机分组。这种方式下元组会被尽可能随机地分配到Bolt的不同任务(tasks)中,使得每个任务所处理元组数量能够保持基本一致,以确保集群的负载均衡。
- Fields grouping:按字段分组。这种方式下数据流根据定义的Field来进行分组。比如,如果某个数据流是基于一个名为“user-id”的字段进行分组的,那么所有包含相同的“user-id”的tuple都会被分配到同一个任务中,这样就可以确保消息处理的一致性。
- Partial Key grouping:部分关键字分组。这种方式与Fields grouping很相似,根据定义的域来对数据流进行分组,不同的是,这种方式会考虑下游Bolt数据处理的均衡性问题,在输入数据源关键字不平衡时会有更好的性能。
- All grouping:完全分组。这种方式下数据流会被同时发送到Bolt的所有任务中(也就是说同一个元组会被复制多份然后被所有的任务处理),使用这种分组方式要特别小心。
- Global grouping:全局分组。这种方式下所有的数据流都会被发送到 Bolt 的同一个任务中,也就是id最小的那个任务。
- None grouping:无分组。使用这种方式说明你不关心数据流如何分组。目前这种方式的结果与随机分组完全等效,不过未来Storm社区可能会考虑通过非分组方式来让 Bolt 和它所订阅的 Spout 或 Bolt 在同一个线程中执行。
- Direct grouping:直接分组。这是一种特殊的分组方式。使用这种方式意味着元组的发送者可以指定下游的哪个任务可以接收这个元组。只有在数据流被声明为直接数据流时才能够使用直接分组方式。使用直接数据流发送元组需要使用OutputCollector的其中一个emitDirect方法。Bolt可以通过TopologyContext来获取它的下游消费者的任务id,也可以通过跟踪OutputCollector的emit方法(该方法会返回它所发送元组的目标任务的id)的数据来获取任务 id。
- Local or shuffle grouping:本地或随机分组。如果目标bolt有一个或者多个task与源bolt的task在同一个工作进程中,tuple将会被随机发送给这些同进程中的tasks。否则,和普通的Shuffle Grouping行为一致。
其中Shuffle grouping、Fields grouping、All grouping、Global grouping四种策略用得较多。
实例
拿最简单的WordCount来做例子:
新建wordcount项目
新建RandomSentenceSpout类来产生数据
package com.topo;
import org.apache.storm.spout.SpoutOutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseRichSpout;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Values;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Random;
public class RandomSentenceSpout extends BaseRichSpout {
private static final long serialVersionUID = 610223919252661