我们长期以来一直在努力解决这个问题。简而言之,我们的风暴拓扑在一段时间后以随机方式停止从喷口发出消息。我们有一个自动脚本,在主数据刷新活动完成后每天06:00 UTC重新部署拓扑。
在过去两周内,我们的拓扑在UTC时间晚些时候(22:00到02:00之间)停止发送消息3次。它只在我们重启时才上线,大概是06:00 UTC。
我搜索过很多答案&博客,但无法找到这里发生的事情。我们有一个非锚定拓扑,这是我们在3 - 4年前做出的选择。我们从0.9.2开始,现在我们在1.1.0。
我已经检查了所有类型的日志,并且我100%确定控制器的nextTuple()
方法没有被调用,并且系统中没有异常发生可能导致这种情况。我还检查了我们积累的所有类型的日志,甚至没有一个ERROR或WARN日志解释突然停止。 INFO日志也没有用。在工作日志或管理员日志或nimbus日志中没有任何内容可以连接到此问题。
这是我们的spout类的外观: 的 Controller.java
public class Controller implements IRichSpout {
SpoutOutputCollector _collector;
Calendar LAST_RUN = null;
List<ControllerMessage> msgList;
/**
* It is to open the spout
*/
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
_collector = collector;
msgList= new ArrayList<ControllerMessage>();
MongoIndexingHandler mongoIndexingHandler = new MongoIndexingHandler();
mongoIndexingHandler.createMongoIndexes();
}
/**
* It executes the next tuple
*/
@Override
public void nextTuple() {
Map<String, Object> logMap = new HashMap<>();
logMap.put("BEGIN", new Date());
try {
TriggerHandler thandler = new TriggerHandler();
if (msgList.size() == 0) {
List<ControllerMessage> mList = thandler.getControllerMessage(new Date());
msgList = mList;
}
if (msgList.size() > 0) {
ControllerMessage message = msgList.get(0);
if(thandler.fire(message.getFireTime())) {
Util.log(message, "CONTROLLER_LOGS", message.getTime(), new Date());
msgList.remove(0);
_collector.emit(new Values(message));
}
}
else{
Utils.sleep(1000);
}
} catch (Exception e) {
_collector.reportError(e);
Util.exLog(e, "EXECUTOR_ERROR", new Date(), "nextTuple()",Controller.class);
}
}
/**
* It acknowledges the messages
*/
@Override
public void ack(Object id) {
}
/**
* It tells failed messages
*/
@Override
public void fail(Object id) {
}
/**
* It declares the message name
*/
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("SPOUT_MESSAGE"));
}
@Override
public void activate() {
}
@Override
public void close() {
}
@Override
public void deactivate() {
}
@Override
public Map<String, Object> getComponentConfiguration() {
return null;
}
}
这是拓扑类: DiagnosticTopology.java
public class DiagnosticTopology {
public static void main(String[] args) throws Exception {
int gSize = (null != args && args.length > 0) ? Integer.parseInt(args[0]) : 2;
int sSize = (null != args && args.length > 1) ? Integer.parseInt(args[1]) : 128;
int sMSize = (null != args && args.length > 2) ? Integer.parseInt(args[2]) : 16;
int aGSize = (null != args && args.length > 3) ? Integer.parseInt(args[3]) : 16;
int rSize = (null != args && args.length > 4) ? Integer.parseInt(args[4]) : 64;
int rMSize = (null != args && args.length > 5) ? Integer.parseInt(args[5]) : 16;
int dMSize = (null != args && args.length > 6) ? Integer.parseInt(args[6]) : 8;
int wSize = (null != args && args.length > 7) ? Integer.parseInt(args[7]) : 16;
String topologyName = (null != args && args.length > 8) ? args[8] : "DIAGNOSTIC";
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("controller", new Controller(), 1);
builder.setBolt("generator", new GeneratorBolt(), gSize).shuffleGrouping("controller");
builder.setBolt("scraping", new ScrapingBolt(), sSize).shuffleGrouping("generator");
builder.setBolt("smongo", new MongoBolt(), sMSize).shuffleGrouping("scraping");
builder.setBolt("aggregation", new AggregationBolt(), aGSize).shuffleGrouping("scraping");
builder.setBolt("rule", new RuleBolt(), rSize).shuffleGrouping("smongo");
builder.setBolt("rmongo", new RMongoBolt(), rMSize).shuffleGrouping("rule");
builder.setBolt("dstatus", new DeviceStatusBolt(), dMSize).shuffleGrouping("rule");
builder.setSpout("trigger", new TriggerSpout(), 1);
builder.setBolt("job", new JobTriggerBolt(), 4).shuffleGrouping("trigger");
Config conf = new Config();
conf.setDebug(false);
conf.setNumWorkers(wSize);
StormSubmitter.submitTopologyWithProgressBar(topologyName, conf, builder.createTopology());
}
}
我们有相当好的服务器(Xeon,8核,32 GB和闪存驱动器)用于生产和测试环境,并且没有外部因素可能导致此问题,因为异常处理在代码中无处不在。
当这件事情发生时,似乎所有事情都突然停止了,并且没有发生原因的痕迹。
非常感谢任何帮助!
答案 0 :(得分:2)
我不知道导致您出现问题的原因,但我建议您首先检查升级到最新的Storm版本是否可以解决问题。我知道至少有两个与工作线程死亡有关的问题,但没有回来https://issues.apache.org/jira/browse/STORM-1750 https://issues.apache.org/jira/browse/STORM-2194。 1750在1.1.0中固定,但2194在1.1.1之前不固定。
如果升级没有为您解决问题,您可以通过执行以下操作来调试它。
下次拓扑挂起时,请打开Storm UI并找到您的喷口。它将显示运行该spout的执行程序列表,以及哪些worker负责运行它们。挑选一个喷口执行者没有发射任何东西的工人。在运行该worker的机器上打开一个shell,找到worker JVM的进程ID。您可以使用jps -m
轻松完成此操作。
示例输出显示我的本地计算机上具有端口6701的worker JVM,其具有pid 7592:
7592工人测试-2-1520361882 d24dc55d-76c7-4cc6-93fa-2663fcdcb1ba-10.0.75.1 6701 f7b6f8e4-6c87-47ca-a7b7-655009b6c62a
执行kill -3 <pid>
触发线程转储,或者根据需要使用jstack <pid>
。
在线程转储中,您应该能够找到挂起的执行程序线程。例如,当我为带有名为&#34; word&#34;的spout的拓扑进行线程转储时,其中一个spout执行程序的编号为13,我看到
编辑:堆栈溢出不会让我发布堆栈跟踪,因为启发式查找未格式化的代码是不好的。我花了很长时间尝试将堆栈跟踪发布为编写原始答案,因此我无法继续尝试。这是应该在这里的追踪https://pastebin.com/2Sz5kkQ1
它向我展示了执行者13当前正在做什么。在这种情况下,它在调用nextTuple时会休眠。
如果您可以找到您的悬挂执行人员正在做什么,您应该更好地解决问题,或向Storm报告错误。
答案 1 :(得分:0)
我们已经在我们的应用程序中观察到这一点,我们的CPU非常繁忙,所有其他线程都在等待轮到他们。当我们尝试使用JVisualVM查找根本原因来检查资源使用情况时,我们发现某些螺栓中的某些功能导致了大量的开销和CPU时间。请检查通过。任何分析工具,如果在nextTuple()方法的CPU关键路径中存在阻塞的线程,或者是否从上游接收到相同的任何数据。