Apache Storm spout停止从spout发出消息

时间:2018-03-06 09:44:39

标签: apache-storm apache-storm-topology

我们长期以来一直在努力解决这个问题。简而言之,我们的风暴拓扑在一段时间后以随机方式停止从喷口发出消息。我们有一个自动脚本,在主数据刷新活动完成后每天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和闪存驱动器)用于生产和测试环境,并且没有外部因素可能导致此问题,因为异常处理在代码中无处不在。

当这件事情发生时,似乎所有事情都突然停止了,并且没有发生原因的痕迹。

非常感谢任何帮助!

2 个答案:

答案 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关键路径中存在阻塞的线程,或者是否从上游接收到相同的任何数据。

相关问题