【问题标题】:How to update an existing Storm topology with new bolts in code?如何使用代码中的新螺栓更新现有的 Storm 拓扑?
【发布时间】:2019-01-23 06:26:26
【问题描述】:

我正在编写一个使用 Apache Storm v1.1.2、Kafka v0.11.0.1、Zookeeper 3.4.6、Eureka 和 Cloud-Config 的 dockerized Java Spring 应用程序,所有这些都在由 Docker-Compose 编排的 Docker 容器中。

我通过 KafkaSpout 接收的元组有一个“值”字段,它是一个 protobuf 对象。我使用自定义反序列化器将我的对象从中取出进行处理。

我有一个基本的应用程序工作,我有一个螺栓,它打印传入的消息并根据 protobuf 对象中字段的值将它们路由到其他特定的螺栓。我还将 LocalCluster、Config 和 TopologyBuilder 作为 Spring Bean 工作。

目前我在 PostContruct 中设置了所有螺栓,但我需要能够动态添加螺栓,以根据 protobuf 对象的其他字段过滤传入消息并执行基本聚合函数(最大/最小/窗口平均值)。

我想使用 REST 控制器来执行此操作,但是如何在不丢失数据的情况下停止和启动拓扑?我也不希望从一开始就通过监听 Kafka 主题来重新启动拓扑,因为该系统将收到极高的负载。

这篇文章看起来很有希望,但我绝对希望整个过程自动化,所以我不会进入 Zookeeper https://community.hortonworks.com/articles/550/unofficial-storm-and-kafka-best-practices-guide.html

如何在代码中编辑现有拓扑以动态添加新螺栓?

【问题讨论】:

    标签: java spring docker apache-kafka apache-storm


    【解决方案1】:

    你不能。 Storm 拓扑在提交后是静态的。如果您需要根据元组中的字段改变处理,最好的选择是预先提交您需要的所有螺栓。然后,您可以使用一个或多个检查元组的螺栓来改变元组通过拓扑的路径,并根据元组内容发送到特定的流。

    例如做一个SplitterBolt

    public void execute(Tuple input) {
      if (tuple.getIntegerByField("theDecider") == 1) {
        collector.emit("onlyOnes", tuple.getValues());
      } else {
        collector.emit("others", tuple.getValues());
      }
    }
    

    您在拓扑构建代码中的位置会有类似

    builder.setSpout("kafka-spout", ...);
    builder.setBolt("splitter", new SplitterBolt()).shuffleGrouping("kafka-spout");
    builder.setBolt("countOnes", new CounterBolt()).shuffleGrouping("splitter", "onlyOnes");
    builder.setBolt("countOthers", new CounterBolt()).shuffleGrouping("splitter", "others");
    

    【讨论】:

    • 感谢您的回答!所以我正在做一些与你已经建议的非常相似的事情。我从您的回复中猜测,如果我想添加一个新的螺栓来读取“onlyOnes”(就像我要将所有的加在一起),我需要终止拓扑,将螺栓添加到拓扑中与之前的其他螺栓一起,重新提交拓扑以继续处理。我查看了有状态的螺栓,但我猜如果你杀死拓扑,状态就会丢失
    • 是的,如果你想在拓扑中添加一个新的bolt,你需要杀死它,编辑拓扑定义并重新提交。我相信当拓扑被杀死时,有状态的螺栓状态会丢失(但不确定)。为什么你不能在拓扑中开始使用 SumBolt 呢?您可以使用带外消息(例如通过 Zookeeper,请参阅 github.com/ptgoetz/storm-signals)来打开和关闭它。
    • 再次感谢您的帮助!我正在制作的应用程序必须能够根据传入消息的字段和选择的聚合器创建任意聚合器螺栓。例如,用户可以使用具有 aggregatorType SUM 和 filterName“num”的 DTO 进行 REST 调用,然后具有字段“name”和值为“num”的传入消息将被接受到新螺栓中。因此,bolt 将对所有具有该名称的消息进行汇总并发布总和。名称可以是任何东西,聚合类型可以是几个简单操作之一。
    • 那么当用户添加总和螺栓时会发生什么?处理是重新开始,还是拓扑只是在它所在的任何点继续运行?如果多个用户添加一个总和螺栓怎么办?我觉得您正在描述更适合批处理工具的东西,您的 REST 调用将能够启动批处理作业,该作业会产生结果并将其发布到某处。
    • 如果您决定要使用 Storm,另一种选择是拆分拓扑。你可以使用例如Kafka 作为中间队列。因此,当您的用户询问总和时,您可以启动一个从 Kafka 读取并计算总和的新拓扑(即类似于 yourCurrentTopology -> Kafka -> userTriggeredSumTopology)。这将使您可以将用户定义的拓扑部分与拓扑的其余部分解耦。
    猜你喜欢
    • 2018-07-20
    • 2013-02-07
    • 1970-01-01
    • 2014-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    相关资源
    最近更新 更多