附录 B:Kafka Streams DSL 速查

Kafka Streams DSL 常用操作速查卡:StreamsBuilder 拓扑创建、KStream/KTable/KGroupedStream 的常用转换操作、Join 语义、状态存储配置、EOS 配置参数及 TopologyTestDriver 测试模板。

StreamsBuilder

StreamsBuilder builder = new StreamsBuilder();

KStream<String, String> stream = builder.stream("input-topic");
KTable<String, String> table = builder.table("input-topic");
GlobalKTable<String, String> global = builder.globalTable("input-topic");

Topology topology = builder.build();
方法输出说明
stream(topic)KStream记录流
table(topic)KTable更新流
globalTable(topic)GlobalKTable全局表

KStream 操作

// 无状态
stream.filter((k, v) -> v.length() > 0)
      .map((k, v) -> KeyValue.pair(k, v.toUpperCase()))
      .mapValues(String::toUpperCase)
      .flatMapValues(v -> Arrays.asList(v.split(" ")))
      .selectKey((k, v) -> v.substring(0, 3));

// 有状态
stream.groupByKey()
      .count(Materialized.as("count-store"));

stream.groupByKey()
      .reduce((a, b) -> a + b, Materialized.as("reduce-store"));

stream.groupByKey()
      .aggregate(
          () -> 0.0,
          (key, value, agg) -> agg + Double.parseDouble(value),
          Materialized.as("agg-store")
      );
操作输入输出状态
filterKStreamKStream无
mapKStreamKStream无
mapValuesKStream/KTableKStream/KTable无
flatMapValuesKStreamKStream无
selectKeyKStreamKStream无(改变 key 后会触发 repartition)
groupByKeyKStreamKGroupedStream无
countKGroupedStreamKTable有
reduceKGroupedStreamKTable有
aggregateKGroupedStreamKTable有

map 与 selectKey 都被标记为 key-changing:下游一旦做聚合,Kafka Streams 会插入 repartition topic 把相同 key 拉到同一分区;mapValues / flatMapValues 不改变 key,不触发 repartition。

Join

// KStream + KStream(Windowed Join)
stream1.join(stream2, (v1, v2) -> v1 + "-" + v2,
    JoinWindows.ofTimeDifferenceWithNoGrace(Duration.ofMinutes(5)));

// KStream + KTable(非窗口)
stream.leftJoin(table, (s, t) -> s + ":" + t);

// KTable + KTable
KTable<String, String> joined = table1.join(table2, (v1, v2) -> v1 + v2);
Join类型窗口
stream.join(stream)KStream + KStreamWindowed
stream.leftJoin(table)KStream + KTable无
stream.join(table)KStream + KTable无
table.join(table)KTable + KTable无

状态存储

// KeyValueStore
Stores.keyValueStoreBuilder(
    Stores.persistentKeyValueStore("my-store"),
    Serdes.String(), Serdes.Long()
);

// WindowStore
Stores.windowStoreBuilder(
    Stores.persistentWindowStore("win-store",
        Duration.ofDays(7), Duration.ofHours(1), false),
    Serdes.String(), Serdes.Long()
);
类型API持久化
KeyValueStorepersistentKeyValueStore()RocksDB
WindowStorepersistentWindowStore()RocksDB
InMemoryinMemoryKeyValueStore()堆内存

配置

Properties props = new Properties();
props.put(StreamsConfig.APPLICATION_ID_CONFIG, "my-app");
props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "kafka:9092");
props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());
props.put(StreamsConfig.PROCESSING_GUARANTEE_CONFIG, StreamsConfig.EXACTLY_ONCE_V2);
props.put(StreamsConfig.COMMIT_INTERVAL_MS_CONFIG, 10000);
props.put(StreamsConfig.NUM_STREAM_THREADS_CONFIG, 4);
配置说明
APPLICATION_ID_CONFIGConsumer Group ID
PROCESSING_GUARANTEEEXACTLY_ONCE_V2
COMMIT_INTERVAL_MSOffset 提交间隔
NUM_STREAM_THREADS每个实例的线程数

测试

@Test
void test() {
    try (TopologyTestDriver driver = new TopologyTestDriver(topology, props)) {
        TestInputTopic<String, String> input = driver.createInputTopic(
            "input", new StringSerializer(), new StringSerializer());
        TestOutputTopic<String, String> output = driver.createOutputTopic(
            "output", new StringDeserializer(), new StringDeserializer());

        input.pipeInput("key", "value");
        assertEquals("VALUE", output.readValue());
    }
}

返回 目录 。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「java」更多文章

  1. 15.3 全书总结与学习路径回顾
  2. 15.2 响应式流处理的演进趋势
  3. 15.1 引擎选型指南