首页 文章

Kafka Streams - 是否可以减少多个聚合创建的内部主题的数量

提问于
浏览
2

我有一个Kafka Streams应用程序,它按几个值对传入的消息进行分组 . 例如:

示例消息:

{ "gender": "female", "location": "canada", "age-group": "25-30" }

拓扑结构:

table
    .groupBy((key, value) -> groupByGender) // example key: female
    .count("gender-counts");

table
    .groupBy((key, value) -> groupByLocation) // example key: canada
    .count("location-counts");

table
    .groupBy((key, value) -> groupByAgeGroup) // example key: 25-30
    .count("age-group-counts");

这导致了很多主题:

my-consumer-gender-counts-changelog
my-consumer-gender-counts-repartition
my-consumer-location-counts-changelog
my-consumer-location-counts-repartition
my-consumer-age-group-counts-changelog
my-consumer-age-group-counts-repartition

如果我们可以将多个聚合发送到单个状态存储,并将值按组包含在键中,那将会很好 . 例如:

table
    .groupBy((key, value) -> groupByGender) // example key: female_gender
    .count("counts");

table
    .groupBy((key, value) -> groupByLocation) // example key: canada_location
    .count("counts");

table
    .groupBy((key, value) -> groupByAgeGroup) // example key: 25-30_age_group
    .count("counts");

这将导致更少的主题:

counts-changelog
counts-repartition

这当前似乎不可能(无论如何使用DSL),因为使用 groupBy 运算符创建了一个内部主题用于重新分区,因此如果我们有多个不同的子拓扑,那么Kafka Streams将尝试注册相同的内容 . 从多个来源重新分配主题 . 这会导致以下错误:

org.apache.kafka.streams.errors.TopologyBuilderException: Invalid topology building: Topic counts-repartition has already been registered by another source.
        at org.apache.kafka.streams.processor.TopologyBuilder.validateTopicNotAlreadyRegistered(TopologyBuilder.java:518)

如果 groupBy 可以返回多个记录(例如 flatMap ),那么我们可以返回一组记录(每个分组一个记录),但这似乎也不可能使用DSL .

我的问题是,鉴于可以按多个值(例如 { "gender": "female", "location": "canada", "age-group": "25-30" } )分组的单个记录,是否应该关注多个主题(每个分组2个)的创建(例如,我们有100个不同的分组)?当单个记录可以按多个值分组时,还有其他策略可能更适合吗?我提出的建议(将多个聚合下沉到单个更改日志主题)是一个坏主意(即使唯一键的数量非常低)?

1 回答

  • 2

    如果要按不同属性进行分组,则无法避免多个重新分区主题 . 假设您有两个分组属性 g1g2 以及三个具有以下值的记录:

    r1 = g1:A, g2:1
    r2 = g1:A, g2:2
    r3 = g1:B, g2:2
    

    因此,要根据 g1 正确聚合记录,必须将记录 r1r2 组合在一起 . 假设您的重新分区主题有2个分区 p1p2 ,该记录将重新分配

    p1: r1, r2
    p2: r3,
    

    另一方面,如果您在 r2 上聚合,则必须将记录 r2r3 组合在一起:

    p1: r1
    p2: r2,r3
    

    注意,对于这两种情况, r2 必须转到不同的分区,因此,不可能使用单个主题,但每个分组需要一个主题 . (这不是Kafka特定的 - 任何其他框架都需要复制并重新分配日期多次) .

    从理论上讲,如果添加更多语义信息(如超密钥,子密钥或1对1密钥映射),则可以减少主题数量 . 但Kafka Streams(和AFAIK,没有其他可比系统)不支持 .

相关问题