Kafka Streams - 是否有可能减少由多个聚合创建的内部主题的数量
Kafka Streams - is it possible to reduce the number of internal topics created by multiple aggregations
我有一个 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
运算符会创建一个用于重新分区的内部主题,因此如果我们有多个子拓扑 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
可以 return 多条记录(例如像 flatMap
那样),那么我们可以 return 一组记录(每个分组一条记录),但这似乎也无法使用 DSL。
我的问题是,给定一个可以按多个值分组的记录(例如 { "gender": "female", "location": "canada", "age-group": "25-30" }
),是否应该关注创建多个主题(每个分组 2 个)(例如我们我们有 100 个不同的分组)?当单个记录可以按多个值分组时,是否有其他策略可能更适合?我提出的建议(将多个聚合下沉到单个更新日志主题)是不是一个坏主意(即使唯一键的数量非常少)?
如果要按不同的属性进行分组,就避免不了多次重新划分topic。假设您有两个分组属性 g1
和 g2
以及三个具有以下值的记录:
r1 = g1:A, g2:1
r2 = g1:A, g2:2
r3 = g1:B, g2:2
因此,要根据 g1
正确聚合记录,记录 r1
和 r2
必须组合在一起。假设您的重新分区主题有 2 个分区 p1
和 p2
,记录将重新分配为
p1: r1, r2
p2: r3,
另一方面,如果您在 r2
上聚合,记录 r2
和 r3
必须分组在一起:
p1: r1
p2: r2,r3
请注意,对于这两种情况,r2
必须转到不同的分区,因此,不可能使用单个主题,但每个分组需要一个主题。 (这不是 Kafka 特有的——任何其他框架也需要多次复制和重新分发日期)。
理论上,如果添加更多语义信息(如超级键、子键或一对一键映射),可以减少主题的数量。但这不受 Kafka Streams(和 AFAIK,没有其他可比系统)的支持。
我有一个 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
运算符会创建一个用于重新分区的内部主题,因此如果我们有多个子拓扑 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
可以 return 多条记录(例如像 flatMap
那样),那么我们可以 return 一组记录(每个分组一条记录),但这似乎也无法使用 DSL。
我的问题是,给定一个可以按多个值分组的记录(例如 { "gender": "female", "location": "canada", "age-group": "25-30" }
),是否应该关注创建多个主题(每个分组 2 个)(例如我们我们有 100 个不同的分组)?当单个记录可以按多个值分组时,是否有其他策略可能更适合?我提出的建议(将多个聚合下沉到单个更新日志主题)是不是一个坏主意(即使唯一键的数量非常少)?
如果要按不同的属性进行分组,就避免不了多次重新划分topic。假设您有两个分组属性 g1
和 g2
以及三个具有以下值的记录:
r1 = g1:A, g2:1
r2 = g1:A, g2:2
r3 = g1:B, g2:2
因此,要根据 g1
正确聚合记录,记录 r1
和 r2
必须组合在一起。假设您的重新分区主题有 2 个分区 p1
和 p2
,记录将重新分配为
p1: r1, r2
p2: r3,
另一方面,如果您在 r2
上聚合,记录 r2
和 r3
必须分组在一起:
p1: r1
p2: r2,r3
请注意,对于这两种情况,r2
必须转到不同的分区,因此,不可能使用单个主题,但每个分组需要一个主题。 (这不是 Kafka 特有的——任何其他框架也需要多次复制和重新分发日期)。
理论上,如果添加更多语义信息(如超级键、子键或一对一键映射),可以减少主题的数量。但这不受 Kafka Streams(和 AFAIK,没有其他可比系统)的支持。