我的拓扑结构如下:
请注意,Bolt2和Bolt3从Bolt1和Bolt4都接收元组。所有的螺栓都是运行python脚本的ShellBolts,而spout是一个运行python脚本的ShellSpout,它从RabbitMQ读取。除了Bolt4之外,一切都按预期工作。如果我一次向RabbitMQ添加一条消息,它将全部工作并完成干净。如果我在Bolt4上挂起消息时对消息进行排队,那么它将永远不会被Bolt4处理。其他螺栓仍然执行其功能,但Bolt4将在完成第一个螺栓后坐在那里。
Storm UI显示所有元组都由bolt4执行,但只有一个被激活。没有失败。我使用Storm 0.9.5,以及风暴启动程序中包含的multilang python适配器。
shellbolt和spout实现只声明输出字段,没有别的。
如果我将TOPOLOGY_MAX_SPOUT_PENDING设置为1,那么一切正常,但是我一次只能处理一个元组,而Bolt1& 2最终等待Bolt4做好准备。
每个螺栓每个元组需要3-30秒才能完成。
所以我的问题是:我下一步该看哪儿?
编辑:这是一个最小的失败案例。
bolt1.py:
import storm
import time
import json
class Bolt1(storm.BasicBolt):
# overrides storm.Bolt.process
def process(self, tup):
objID, APIArgs = tup.values
APIArgs = json.loads(APIArgs)
self.emit("bolt3Queue", objID, **APIArgs)
self.emit("bolt2Queue", objID, **APIArgs)
self.emit("bolt4Queue", objID, **APIArgs)
storm.ack(tup)
def emit(self, stream, objID, **APIArgs):
tup = [objID, json.dumps(APIArgs)]
storm.log("Emit [%s] %s" % (stream, tup))
storm.emit(tup, stream=stream)
if __name__ == '__main__':
Bolt1().run()
bolt2.py:
import storm
import time
import json
class Bolt2(storm.BasicBolt):
# overrides storm.Bolt.process
def process(self, tup):
objID, APIArgs = tup.values
APIArgs = json.loads(APIArgs)
storm.ack(tup)
def emit(self, stream, objID, **APIArgs):
tup = [objID, json.dumps(APIArgs)]
storm.log("Emit [%s] %s" % (stream, tup))
storm.emit(tup, stream=stream)
if __name__ == '__main__':
Bolt2().run()
bolt3.py:
import storm
import time
import json
class Bolt3(storm.BasicBolt):
# overrides storm.Bolt.process
def process(self, tup):
objID, APIArgs = tup.values
APIArgs = json.loads(APIArgs)
storm.ack(tup)
def emit(self, stream, objID, **APIArgs):
tup = [objID, json.dumps(APIArgs)]
storm.log("Emit [%s] %s" % (stream, tup))
storm.emit(tup, stream=stream)
if __name__ == '__main__':
Bolt3().run()
bolt4.py:
import storm
import time
import json
class Bolt4(storm.BasicBolt):
# overrides storm.Bolt.process
def process(self, tup):
objID, APIArgs = tup.values
APIArgs = json.loads(APIArgs)
self.emit("bolt3Queue", objID, **APIArgs)
self.emit("bolt2Queue", objID, **APIArgs)
storm.ack(tup)
def emit(self, stream, objID, **APIArgs):
tup = [objID, json.dumps(APIArgs)]
storm.log("Emit [%s] %s" % (stream, tup))
storm.emit(tup, stream=stream)
if __name__ == '__main__':
Bolt4().run()
spout.py:
import storm
import random
class Spout(storm.Spout):
def nextTuple(self):
storm.emit(["id1234", "{}"], id=str(random.randint(1, 10000)))
if __name__ == '__main__':
Spout().run()
拓扑:
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package storm.starter;
import backtype.storm.Config;
import backtype.storm.LocalCluster;
import backtype.storm.StormSubmitter;
import backtype.storm.spout.ShellSpout;
import backtype.storm.task.ShellBolt;
import backtype.storm.topology.*;
import backtype.storm.topology.base.BaseBasicBolt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;
import java.util.HashMap;
import java.util.Map;
public class PyroTopology {
public static class PythonBolt extends ShellBolt implements IRichBolt {
public PythonBolt(String script) {
super("python", script);
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {}
@Override
public Map<String, Object> getComponentConfiguration() {
return null;
}
}
public static class Bolt4 extends ShellBolt implements IRichBolt {
public Bolt4() {
super("python", "bolt4.py");
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declareStream("bolt3Queue", new Fields("objID", "APIArgs"));
declarer.declareStream("bolt2Queue", new Fields("objID", "APIArgs"));
}
@Override
public Map<String, Object> getComponentConfiguration() {
return null;
}
}
public static class Bolt1 extends ShellBolt implements IRichBolt {
public Bolt1() {
super("python", "bolt1.py");
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declareStream("bolt3Queue", new Fields("objID", "APIArgs"));
declarer.declareStream("bolt2Queue", new Fields("objID", "APIArgs"));
declarer.declareStream("bolt4Queue", new Fields("objID", "APIArgs"));
}
@Override
public Map<String, Object> getComponentConfiguration() {
return null;
}
}
public static class PythonSpout extends ShellSpout implements IRichSpout {
public PythonSpout() {
super("python", "spout.py");
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("objID", "APIArgs"));
}
@Override
public Map<String, Object> getComponentConfiguration() {
return null;
}
}
public static void main(String[] args) throws Exception {
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("rabbit", new PythonSpout(), 1);
builder.setBolt("bolt1", new Bolt1(), 1).
shuffleGrouping("rabbit");
builder.setBolt("bolt4", new Bolt4(), 1).
shuffleGrouping("bolt1", "bolt4Queue");
builder.setBolt("bolt3", new PythonBolt("bolt3.py"), 1).
shuffleGrouping("bolt1", "bolt3Queue").
shuffleGrouping("bolt4", "bolt3Queue");
builder.setBolt("bolt2", new PythonBolt("bolt2.py"), 1).
shuffleGrouping("bolt1", "bolt2Queue").
shuffleGrouping("bolt4", "bolt2Queue");
Config conf = new Config();
conf.setStatsSampleRate(1.0);
conf.put(Config.TOPOLOGY_DEBUG, true);
conf.put(Config.TOPOLOGY_MAX_SPOUT_PENDING, 5);
conf.put(Config.TOPOLOGY_MESSAGE_TIMEOUT_SECS, 60);
if (args != null && args.length > 0) {
conf.setNumWorkers(3);
StormSubmitter.submitTopologyWithProgressBar(args[0], conf, builder.createTopology());
}
else {
conf.setMaxTaskParallelism(3);
LocalCluster cluster = new LocalCluster();
cluster.submitTopology("word-count", conf, builder.createTopology());
Thread.sleep(30000);
cluster.shutdown();
}
}
}
我使用此部署:
storm jar target/storm-starter-0.9.5-jar-with-dependencies.jar storm.starter.PyroTopology vb
每个组件1个元组后,整个系统挂起。没有处理或失败的新元组。在系统卡住之后,这就是我的Storm UI:
它就像这样永远。 (为了以防万一,我等了几个小时。)
答案 0 :(得分:1)
您正在使用BasicBolt
自动为您处理acking。因此,您不得在您的代码中手动输入元组。这导致单个元组的多个ackes,这混淆了Storm的机制来跟踪acks(通过xor-ing消息ID和ack ID)。作为替代方案(如果您需要高级的acking行为,您可以实现Bolt
。
如图所示,您的鲸鱼喷水池没有收到确认,因此当达到 max spout pending 时,Storm会停止发出元组。此外,您会看到螺栓的“已执行”和“已执行”计数不匹配 - 这也表示未正确处理确认。