如何查看正在运行的Storm拓扑的当前输出?

时间:2019-12-12 13:16:09

标签: apache-storm

当前正在学习如何使用Storm(版本2.1.0 ),我对此数据流处理(DSP)引擎的特定方面有些困惑: 如何 教程为系统设置和运行我们的第一个应用程序提供了很好的解释。不幸的是,我找不到一个页面提供有关拓扑生成的结果的详细信息。

在DSP应用程序中,没有最终输出,因为输入数据是连续输入的数据流(或者我们可以说应用程序停止时有最终输出)。我想要的是能够查看正在运行的拓扑的当前输出状态(当前时间生成的实际输出数据)。

我可以运行WordCountTopology。我了解此拓扑的输出是由以下代码片段生成的:

public static class WordCount extends BaseBasicBolt {
    Map<String, Integer> counts = new HashMap<String, Integer>();

    @Override
    public void execute(Tuple tuple, BasicOutputCollector collector) {
        String word = tuple.getString(0);
        Integer count = counts.get(word);
        if (count == null) {
            count = 0;
        }
        count++;
        counts.put(word, count);
        collector.emit(new Values(word, count));
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
        declarer.declare(new Fields("word", "count"));
    }
}

我的误解是关于<"word":string, "count":int>输出的位置。只是在内存中,写在数据库中的某个地方,还是写在一个文件中吗?

进一步探讨这个问题:存储正在进行的输出数据的现有可能性是什么?处理此类数据的“ 好方法”是什么?

我希望我的问题不会太幼稚。并感谢StackOverflow社区始终为您提供良好的帮助。

1 个答案:

答案 0 :(得分:0)

自从我发布此问题以来已经过了几天。我将与您分享我的尝试。尽管我不能确定这是否是正确的方法,但以下两个命题回答了我的问题。

简单的System.out.println()

我尝试做的第一件事是直接在我的 BaseBasicBolt prepare()方法中创建一个System.out.println("Hello World!")。在每个Bolt线程执行开始时,仅调用一次此方法。

public void prepare(Map topoConf, TopologyContext context) {
  System.out.println("Hello World!");   
}

最大的挑战是弄清楚日志的写入位置。默认情况下,它写在<storm installation folder>/logs/workers-artifacts/<topology name>/<worker-port>/worker.log中,其中<worker-port>是请求的工作程序/插槽的端口。

例如,对于conf.setNumWorkers(3),拓扑请求访问3个工作线程(3个插槽)。因此,<worker-port>的值将是6700、6701和6702。这些值是3个插槽的端口号(在storm.yaml下的supervisor.slots.ports中定义)。

注意:您将拥有与 BaseBasicBolt 的并行大小一样多的“ Hello World!”。当用builder.setBolt("split", new SplitSentence(), 8)实例化 split 螺栓时,它会导致8个并行线程,每个线程都编写自己的日志。

写入文件

出于研究目的,我必须分析特定格式的大量日志。我发现的解决方案是将日志附加到每个螺栓管理的特定文件中。

以下是我对 count 螺栓的文件记录解决方案的自己实现。

public static class WordCount extends BaseBasicBolt {
    private String workerName;
    private FileWriter fw;
    private BufferedWriter bw;
    private PrintWriter out;
    private String logFile = "/var/log/storm/count.log";
    private Map<String, Integer> counts = new HashMap<String, Integer>();

    public void prepare(Map topoConf, TopologyContext context) {
        this.workerName = this.toString();
        try {
            this.fw = new FileWriter(logFile, true);
            this.bw = new BufferedWriter(fw);
            this.out = new PrintWriter(bw);
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    @Override
    public void execute(Tuple tuple, BasicOutputCollector collector) {
        String word = tuple.getString(0);
        Integer count = counts.get(word);
        if (count == null) {
            count = 0;
        }
        count++;
        counts.put(word, count);
        collector.emit(new Values(word, count));

        out.println(this.workerName + ": Hello World!");
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
        declarer.declare(new Fields("word", "count"));
    }
}

在此代码中,我的日志文件位于/var/log/storm/count.log中,并且调用out.println(text)会在文件的此末尾附加text。由于我不确定它是否是线程安全的,因此所有同时写入同一文件的并行线程都可能导致数据丢失。

注意:如果螺栓分布在多台计算机上,则每台计算机都将具有自己的日志文件。在测试期间,我用1台计算机配置了一个简单的集群(运行Nimbus + Supervisor + UI),因此我只有1个日志文件。

结论

有多种处理输出数据的方法,更常见的是使用Storm记录任何内容。我没有发现任何官方方法可以做到这一点,而且文档对此主题也很淡化。

尽管我们中的一些人对简单的sysout.println()感到满意,但其他人可能需要将大量数据推送到特定文件中,或者可能在专用的数据库引擎中。 Storm是您可以使用Java进行的任何操作,因为它是简单的Java编程。

对于完成此答案的任何建议和其他评论,我们将不胜感激。