将KStream实现到全球共享存储中?

时间:2020-02-20 13:23:02

标签: apache-kafka kafka-consumer-api apache-kafka-streams spring-kafka spring-cloud-stream-binder-kafka

我在Java应用程序(Spring Cloud Stream)中使用Kafka Streams API。我有一个特定的用例,如下:

  • 我的应用程序将从主题A消费,并向主题B消费和消费。
  • 对于主题A上的每条消息,都有一组针对主题B产生的相应消息,应用程序使用这些消息来跟踪内部状态变化。它使用KStream从主题B消费以将这种状态具体化为可查询的存储。

由于将运行该应用程序的多个实例,并且不能保证将任一主题的特定分区分配给这些实例,因此状态存储必须在应用程序之间进行共享共享。否则,如果主题B发生重新平衡,则应用程序实例可能会丢失它们正在跟踪主题A消息的状态信息。请考虑以下情形:

  • 实例1具有主题A的分区1和主题B的分区1。
  • 主题B的分区发生重新平衡。
  • 实例1现在具有主题A的分区1(未更改),但是具有主题B的分区2。
  • 实例1现在失去了对主题B具有分区1时所创建的状态存储中的数据的访问权限。

如果仅针对主题A发生重新平衡,也会发生相同的情况。

有可能实现为“全球状态存储”吗?我知道有一个GlobalKTable的概念,但是我需要使用KStream抽象,因为我需要访问完整的事件流。作为参考,我的KStream使用者如下:

    @StreamListener(INPUT_TOPIC)
    public void consumeKStream(KStream<String, Pojo> kStream) {
        kStream.groupByKey(Serialized.with(keySerde, valueSerde)).aggregate(HashMap::new, (key, value, map) -> {
            map.put(value.getFoo(), value.getBar()); return map;
        }, Materialized.<String, Map<Foo, Bar>, KeyValueStore<Bytes, byte[]>>as(STATE_STORE_NAME)
                .withKeySerde(keySerde).withValueSerde(valueMapSerde));
    }

1 个答案:

答案 0 :(得分:0)

如果您从主题A和主题B中读取数据,并且您具有实现来自主题B的数据并在主题A记录的存储中进行查找的拓扑,则可以保证实例将获得共分区分配。因此,您描述的情况将永远不会发生。

您可以通过检查包含子拓扑的Topology(通过describe())来验证这一点。子拓扑是在任务执行时执行的,并且任务具有保证的共分区输入主题分配。

比较:https://docs.confluent.io/current/streams/architecture.html#parallelism-model