通过Apache Storm中的字段分组将输入从单个喷口发送到多个螺栓

时间:2018-11-15 18:23:24

标签: apache-storm

builder.setSpout("spout", new TweetSpout());
builder.setBolt("bolt", new TweetCounter(), 2).fieldsGrouping("spout",
new Fields("field1"));

我在字段分组中添加了输入字段“ field1”。根据字段分组的定义,所有具有相同“ field1”的推文应转到TweetCounter的单个任务。 TweetCounter螺栓的执行者编号设置为2。

但是,如果传入流的所有元组中的“ field1”都相同,这是否意味着即使我为TweetCounter指定了2个执行程序,该流也只会发送给其中一个,而另一个实例仍然为空?

要进一步研究我的特定用例,如何使用单个喷口,并根据输入字段(field1)的特定值将数据发送到不同的螺栓?

2 个答案:

答案 0 :(得分:0)

解决此问题的一种方法似乎是使用Direct grouping,由源代码决定哪个组件将接收元组。 :

  

这是一种特殊的分组。以这种方式分组的流意味着元组的生产者决定消费者的哪个任务将接收此元组。直接分组只能在已经声明为直接流的流上声明。发出到直接流的元组必须使用[emitDirect](javadocs / org / apache / storm / task / OutputCollector.html#emitDirect(int,int,java.util.List)方法之一发出。使用提供的TopologyContext或通过在OutputCollector中跟踪generate方法的输出(返回元组发送到的任务ID)来跟踪其使用者的任务ID。

您可以看到它的示例使用here

 collector.emitDirect(getWordCountIndex(word),new Values(word));

其中getWordCountIndex返回该元组将要处理的组件的索引。

答案 1 :(得分:0)

this answer中描述的使用emitDirect的一种替代方法是实现自己的流分组。复杂度大致相同,但是它允许您跨多个螺栓重用分组逻辑。

例如,Storm中的洗牌分组被实现为CustomStreamGrouping,如下所示:

public class ShuffleGrouping implements CustomStreamGrouping, Serializable {
    private ArrayList<List<Integer>> choices;
    private AtomicInteger current;

    @Override
    public void prepare(WorkerTopologyContext context, GlobalStreamId stream, List<Integer> targetTasks) {
        choices = new ArrayList<List<Integer>>(targetTasks.size());
        for (Integer i : targetTasks) {
            choices.add(Arrays.asList(i));
        }
        current = new AtomicInteger(0);
        Collections.shuffle(choices, new Random());
    }

    @Override
    public List<Integer> chooseTasks(int taskId, List<Object> values) {
        int rightNow;
        int size = choices.size();
        while (true) {
            rightNow = current.incrementAndGet();
            if (rightNow < size) {
                return choices.get(rightNow);
            } else if (rightNow == size) {
                current.set(0);
                return choices.get(0);
            }
        } // race condition with another thread, and we lost. try again
    }
}

暴风雨将呼叫prepare来告诉您分组负责的任务ID,以及拓扑上的某些上下文。当Storm在使用此分组的地方从螺栓/喷嘴发射出元组时,Storm将调用chooseTasks,让您定义元组应执行的任务。然后,您将在构建拓扑时使用分组,如下所示:

TopologyBuilder tp = new TopologyBuilder();
tp.setSpout("spout", new MySpout(), 1);
tp.setBolt("bolt", new MyBolt())
  .customGrouping("spout", new ShuffleGrouping());

请注意,分组必须是Serializable并且是线程安全的。