我有两个Kafka Spout,其值我想发送到同一个螺栓。
有可能吗?
答案 0 :(得分:11)
是的,有可能:
TopologyBuilder b = new TopologyBuilder();
b.setSpout("topic_1", new KafkaSpout(...));
b.setSpout("topic_2", new KafkaSpout(...));
b.setBolt("bolt", new MyBolt(...)).shuffleGrouping("topic_1").shuffleGrouping("topic_2");
您也可以使用任何其他分组。
<强>更新强>
为了区分消费者螺栓中的元组(即topic_1或topic_2),有两种可能:
1)您可以使用运营商ID(由@ user-4870385建议):
if(input.getSourceComponent().equalsIgnoreCase("topic_1")) {
//do something
} else {
//do something
}
2)您可以使用流名称(由@zenbeni建议)。对于这种情况,两个spouts都需要声明命名流,并且bolt需要通过流名称连接到spouts:
public class MyKafkaSpout extends KafkaSpout {
final String streamName;
public MyKafkaSpout(String stream) {
this.streamName = stream;
}
// other stuff omitted
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
// compare KafkaSpout.declareOutputFields(...)
declarer.declare(streamName, _spoutConfig.scheme.getOutputFields());
}
}
构建拓扑,现在需要使用流名称:
TopologyBuilder b = new TopologyBuilder();
b.setSpout("topic_1", new MyKafkaSpout("stream_t1"));
b.setSpout("topic_2", new MyKafkaSpout("stream_t2"));
b.setBolt("bolt", new MyBolt(...)).shuffleGrouping("topic_1", "stream_t1").shuffleGrouping("topic_2", "stream_t2");
在MyBolt
中,流名称现在可用于区分输入元组:
// in my MyBolt.execute():
if(input.getSourceStreamId().equals("Topic1")) {
// do something
} else {
// do something
}
讨论:
虽然使用流名称的第二方法更自然(根据@zenbeni), first 更灵活(IHMO)。流名称直接由spout / bolt声明(即,在写入spout / bolt代码时);相比之下,当拓扑结合在一起时(即,在使用时),分配了操作员ID。
假设我们得到三个螺栓作为类文件(没有源代码)。前两个应该用作生成器,并且都声明具有相同名称的输出流。如果第三个消费者通过流来区分输入元组,则这将不起作用。即使两个给定的生成器螺栓都声明了不同的输出流名称,预期的输入流名称也可能在消费者螺栓中进行硬编码,并且可能不匹配。因此,它也不起作用。但是,如果消费者使用组件名称(即使它们是硬编码的)来区分传入的元组,则可以正确分配预期的组件ID。
当然,可以从给定的类继承(如果没有声明final
并覆盖declareOutputFields(...)
以便分配自己的流名称。但是,这是更多的额外工作要做。
答案 1 :(得分:0)
是的,可能。你可以让任何喷嘴与同一个螺栓对话。 请参阅https://storm.apache.org/documentation/Tutorial.html“Streams”部分。