簡體   English   中英

使用 Kafka Streams 從多個主題中累積事件

[英]Accumulate Events from Multiple Topics using Kafka Streams

如果這是一個愚蠢的問題,我深表歉意。

我有一個場景,我有來自上游服務的 3 個主題(沒有鍵控)。 不幸的是,我無法改變這 3 個主題的行為。

上游服務在一天結束時批量發布所有消息,我需要獲得事務的累積視圖,因為事務的順序對下游服務很重要。

我知道我無法對主題的不同分區中的消息重新排序,所以我想是否可以累積它們,然后我的服務可以獲取累積的結果並在處理之前重新排序它們。

但是,我注意到一種奇怪的行為,我希望有人能澄清我遺漏了什么。

當我使用 1 到 500 個帳戶進行操作時,我看到 500 條消息累積並顯示在輸出主題中。

但是,當我對 10,000 個帳戶嘗試相同的操作時,我看到的輸出超出了預期。 (關於輸出主題的 13,000 條消息)。

    KStream<String, TransactionAccumulator> transactions =
        disbursements
            .merge(repayments)
            .merge(fees)
            .groupBy(
                (k, v) -> v.getAccountId(),
                with(
                    String(),
                    serdeFrom(
                        new JsonSerializer<>(mapper),
                        new JsonDeserializer<>(Transaction.class, mapper))))
            .windowedBy(SessionWindows.with(Duration.of(1, ChronoUnit.MINUTES)))
            .aggregate(
                TransactionAccumulator::new,
                (key, value, aggregate) -> aggregate.add(value),
                (aggKey, aggOne, aggTwo) -> aggOne.merge(aggTwo),
                Materialized.with(
                    String(),
                    serdeFrom(
                        new JsonSerializer<>(mapper),
                        new JsonDeserializer<>(TransactionAccumulator.class, mapper))))
            .toStream((key, value) -> key.key());

如前所述,上游服務在一天結束時(而不是實時)發布所有事件。

很感激我在這里缺少的東西,因為對於較小的體積,它似乎有效。


更新 1

我嘗試了使用抑制來嘗試僅發送最終窗口的建議。

但是,使用它時,它基本上不會向輸出主題發布任何消息,盡管我看到“KTABLE-SUPPRESS-STATE-STORE”中有消息

帶有抑制的更新代碼如下。

   disbursements
        .merge(repayments)
        .merge(fees)
        .groupBy(
            (key, value) -> value.getAccountId(),
            Grouped.with(
                Serdes.String(),
                Serdes.serdeFrom(
                    new JsonSerializer<>(mapper),
                    new JsonDeserializer<>(Transaction.class, mapper))))
        .windowedBy(TimeWindows.of(Duration.ofMinutes(1)).grace(ofMinutes(1)))
        .aggregate(
            TransactionAccumulator::new,
            (key, value, aggregate) -> aggregate.add(value),
            Materialized.with(
                Serdes.String(),
                Serdes.serdeFrom(
                    new JsonSerializer<>(mapper),
                    new JsonDeserializer<>(TransactionAccumulator.class, mapper))))
        .suppress(Suppressed.untilWindowCloses(BufferConfig.unbounded()))
        .mapValues(
            value -> {
              LOGGER.info(
                  "Sending {} Transactions for {}",
                  value.getTransactions().size(),
                  value.getAccountId());
              return value;
            })
        .toStream((key, value) -> key.key());

我也沒有看到引入的日志消息。 為了清楚起見,我在這個實驗中使用的是Spring Cloud Stream,我在stream-app上看到的最終日志條目如下。

INFO 23436 --- [-StreamThread-1] org.apache.kafka.streams.KafkaStreams    : stream-client [StreamConsumer-consume-applicationId-de25a238-5f0f-4d84-9bd2-3e7b01b7f0b3] State transition from REBALANCING to RUNNING
INFO 23436 --- [-StreamThread-1] o.a.k.s.s.i.RocksDBTimestampedStore      : Opening store KSTREAM-AGGREGATE-STATE-STORE-0000000006.1583625600000 in regular mode
INFO 23436 --- [-StreamThread-1] o.a.k.s.s.i.RocksDBTimestampedStore      : Opening store KSTREAM-AGGREGATE-STATE-STORE-0000000006.1583625600000 in regular mode
INFO 23436 --- [-StreamThread-1] o.a.k.s.s.i.RocksDBTimestampedStore      : Opening store KSTREAM-AGGREGATE-STATE-STORE-0000000006.1583625600000 in regular mode
INFO 23436 --- [-StreamThread-1] o.a.k.s.s.i.RocksDBTimestampedStore      : Opening store KSTREAM-AGGREGATE-STATE-STORE-0000000006.1583625600000 in regular mode
INFO 23436 --- [-StreamThread-1] o.a.k.s.s.i.RocksDBTimestampedStore      : Opening store KSTREAM-AGGREGATE-STATE-STORE-0000000006.1583625600000 in regular mode
INFO 23436 --- [-StreamThread-1] o.a.k.s.s.i.RocksDBTimestampedStore      : Opening store KSTREAM-AGGREGATE-STATE-STORE-0000000006.1583625600000 in regular mode
INFO 23436 --- [-StreamThread-1] o.a.k.s.s.i.RocksDBTimestampedStore      : Opening store KSTREAM-AGGREGATE-STATE-STORE-0000000006.1583625600000 in regular mode
INFO 23436 --- [-StreamThread-1] o.a.k.s.s.i.RocksDBTimestampedStore      : Opening store KSTREAM-AGGREGATE-STATE-STORE-0000000006.1583625600000 in regular mode
INFO 23436 --- [-StreamThread-1] o.a.k.s.s.i.RocksDBTimestampedStore      : Opening store KSTREAM-AGGREGATE-STATE-STORE-0000000006.1583625600000 in regular mode
INFO 23436 --- [-StreamThread-1] o.a.k.s.s.i.RocksDBTimestampedStore      : Opening store KSTREAM-AGGREGATE-STATE-STORE-0000000006.1583625600000 in regular mode
INFO 23436 --- [-StreamThread-1] o.a.k.s.s.i.RocksDBTimestampedStore      : Opening store KSTREAM-AGGREGATE-STATE-STORE-0000000006.1583625600000 in regular mode
INFO 23436 --- [-StreamThread-1] o.a.k.s.s.i.RocksDBTimestampedStore      : Opening store KSTREAM-AGGREGATE-STATE-STORE-0000000006.1583625600000 in regular mode

抱歉,我還不能發表評論,但這是我的兩分錢:

  1. KGroupedStream.aggregate()卡夫卡流使用一個記錄緩存以控制聚集更新從的物化視圖(或KTable)發射的速率aggregate到狀態存儲和下游處理器。 例如使用消息:
("word1", 4)
("word1", 2)
("word2", 3)
("word1", 1)

還有你的字數拓撲:

wordCntPerSentenceKStream
    .groupByKey()
    .aggregate(() -> 0, (word, newWordCnt, aggsWordCnt) -> aggsWordCnt + newWordCnt, Materialized.as("word-cnt-store").withValueSerde(Serdes.Integer())
    .toStream();

您可能會收到這樣的下游消息:

("word1", 6)
("word2", 3)
("word1", 7)

所以我的猜測是您的輸入主題可能包含單個 AccountId 的多個事務,並且當緩存 ( cache.max.bytes.buffering ) 已滿或commit.interval.ms時,記錄緩存將被刷新。

  1. 如果您的接收器是冪等,你可以重寫你的TransactionAccumulator用新的消息鍵,也可以使用KTable.suppress()的說明這里只發出匯總窗口的最后一條消息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM