Kafka流中的聚集和状态存储保留

时间:2018-07-22 01:48:13

标签: apache-kafka-streams

我有一个如下的用例。对于每个传入事件,我想看看 某个字段以查看其状态是否从A更改为B,如果是,请将其发送给 输出主题。流程是这样的:带有键“ xyz”的事件以状态A进入,一段时间后 另一个事件是状态为B的键“ xyz”。我使用高级DSL编写了此代码。

final KStream<String, DomainEvent> inputStream....

final KStream<String, DomainEvent> outputStream = inputStream
          .map((k, v) -> new KeyValue<>(v.getId(), v))
                    .groupByKey(Serialized.with(Serdes.String(), jsonSerde))
                    .aggregate(DomainStatusMonitor::new,
                            (k, v, aggregate) -> {
                                aggregate.updateStatusMonitor(v);
                                return aggregate;
                            }, Materialized.with(Serdes.String(), jsonSerde))
                    .toStream()
                    .filter((k, v) -> v.isStatusChangedFromAtoB())
                    .map((k,v) -> new KeyValue<>(k, v.getDomainEvent()));

是否有更好的方法使用DSL编写此逻辑?

有关上面代码中的聚合创建的状态存储的问题的一对。

  1. 默认情况下是否正在创建内存状态存储?
  2. 如果我拥有无限数量的唯一传入密钥,将会发生什么? 如果默认情况下使用的是内存存储,是否不需要切换到持久性存储? 我们如何处理DSL中的情况?
  3. 如果状态存储很大(内存中或持久性),它将如何影响 启动时间?如何使流处理等待,以使商店得到完全初始化? 还是Kafka Streams会确保在处理任何传入事件之前完全初始化状态存储?

谢谢!

1 个答案:

答案 0 :(得分:8)

  1. 默认情况下,将使用持久性RocksDB存储。如果要使用内存存储,则可以传入Materialized.as(Stores.inMemoryKeyValueStore(...))

  2. 如果拥有无限数量的唯一键,则最终将耗尽主内存或磁盘,并且应用程序将死亡。根据您的语义,可以通过使用带有大“ gap”参数的会话窗口聚合来获取“ TTL”,而不是使旧密钥过期。

  3. 在处理新数据之前,将始终恢复状态。如果您使用内存中存储,这将通过使用基础的changelog主题来实现。根据状态的大小,这可能需要一段时间。如果您使用持久性RocksDB存储,则会从磁盘加载状态,因此无需还原,处理应立即进行。仅在这种情况下,才松开本地磁盘上的状态,才会从changelog主题进行还原。