当前,我们正在使用:Kafka Streams API(版本1.1.0)来处理来自Kafka集群的消息(3个代理,每个主题3个分区,复制因子2)。已安装的Kafka版本为1.1.1。
最终用户向我们报告了数据消失的问题。他们报告说突然他们看不到任何数据(例如,昨天他们可以在UI中看到n条记录,第二天早上的表是空的)。我们检查了这个特定用户的变更日志主题,它看起来很奇怪,看起来几天不活动之后(给定的键值对可能连续几天都没有变化),缺少变更日志主题中的总价值。
KTable组装线:(消息由事件中的“用户名”分组)
@Bean
public KTable<UsernameVO, UserItems> itemsOfTheUser() {
return streamsBuilder.stream("application-user-UserItems", Consumed.with(Serdes.String(), serdes.forA(UserItems.class)))
.groupBy((key, event) -> event.getUsername(),
Serialized.with(serdes.forA(UsernameVO.class), serdes.forA(UserItems.class)))
.aggregate(
UserItems::none,
(key, event, userItems) ->
userItems.after(event),
Materialized
.<UsernameVO, UserItems> as(persistentKeyValueStore("application-user-UserItems"))
.withKeySerde(serdes.forA(UsernameVO.class))
.withValueSerde(serdes.forA(UserItems.class)));
}
汇总对象(KTable值):
public class UserItems {
private final Map<String, Item> items;
public static UserItems none() {
return new UserItems();
}
private UserItems() {
this(emptyMap());
}
@JsonCreator
private UserItems(Map<String, Item> userItems) {
this.userItems = userItems;
}
@JsonValue
@SuppressWarnings("unused")
Map<String, Item> getUserItems() {
return Collections.unmodifiableMap(items);
}
...
public UserItems after(ItemAddedEvent itemEvent) {
Item item = Item.from(itemEvent);
Map<String, Item> newItems = new HashMap<>(items);
newItems.put(itemEvent.getItemName(), item);
return new UserItems(newItems);
}
application-user-UserItems
此源主题没有问题。保留设置为最大,所有消息始终显示。
application-user-UserItems-store-changelog (紧凑型,具有默认配置-保留期未更改,也没有任何更改)
这是奇怪的部分。我们可以在变更日志中观察到某些用户的值正在丢失:
Offset | Partition | Key | Value
...........................................
...
320 0 "User1" : {"ItemName1":{"param":"foo"}}
325 0 "User1" : {"ItemName1":{"param":"foo"},"ItemName2":{"param":"bar"}}
1056 0 "User1" : {"ItemName3":{"param":"zyx"}}
...
我们可以从上面看到,首先,消息被正确聚合:处理了Item1,然后将Item2应用于聚合。但是经过一段时间(可能是几天)后,正在处理另一个事件-似乎缺少“ User1”键下的值,并且仅存在Item3。
在该应用程序中,用户无法一次删除所有项并添加另一项-用户只能逐项添加或删除项。因此,如果他删除ItemName1和ItemName2,然后添加ItemName3,我们将在更改日志中期望类似的内容
Offset | Partition | Key | Value
..............................................
...
320 0 "User1" : {"ItemName1":{"param":"foo"}}
325 0 "User1" : {"ItemName1":{"param":"foo"},"ItemName2":{"param":"bar"}}
1054 0 "User1" : {"ItemName2":{"param":"bar"}}
1055 0 "User1" : {}
1056 0 "User1" : {"ItemName3":{"param":"zyx"}}
起初,我们认为它与changelog主题保留有关(但我们对其进行了检查,并且仅启用了压缩)。
application-user-UserItems-store-changelog PartitionCount:3 ReplicationFactor:1 Configs:cleanup.policy=compact,max.message.bytes=104857600
Topic: application-user-UserItems-store-changelog Partition: 0 Leader: 0 Replicas: 0 Isr: 0
Topic: application-user-UserItems-store-changelog Partition: 1 Leader: 2 Replicas: 2 Isr: 2
Topic: application-user-UserItems-store-changelog Partition: 2 Leader: 1 Replicas: 1 Isr:
任何想法或提示将不胜感激。干杯
答案 0 :(得分:0)
我遇到了与您描述的问题相同的问题,似乎该问题与您的kafka-streams配置有关。 您已经提到“源”主题具有以下配置:
3个代理,每个主题3个分区,复制因子2
确保将以下属性至少设置为2(默认设置为1)到kafka流配置(replication.factor)
StreamsConfig.REPLICATION_FACTOR_CONFIG [replication.factor]
这也与您编写的内容相对应(changelog主题的复制因子设置为1)
application-user-UserItems-store-changelog PartitionCount:3 ReplicationFactor:1 Configs:cleanup.policy = compact,max.message.bytes = 104857600
因此,我的假设是由于代理中断而丢失了数据(由于复制因子2,数据应保留在源主题中,因此您可以重新处理并填充变更日志主题)