我的要求是跳过或避免使用kafka流DSL API从INPUT主题收到重复的消息(具有相同的密钥)。
如果发生任何故障,源系统可能会将重复的消息发送到INPUT主题。
流量-
源系统->输入主题-> Kafka流->输出主题
当前,我正在使用flatMap生成有效载荷中的多个密钥,但是flatMap是无状态的,因此无法避免从INPUT Topic接收到重复的消息处理。
我正在寻找DSL API,该API可以跳过从INPUT主题接收到的重复记录,并且还可以在发送到OUTPUT主题之前生成多个键/值。
“精确思考一次”配置在此处可用于基于密钥对从INPUT主题接收到的消息进行重复数据删除,但看起来它无法正常工作,可能我不了解“精确修饰一次”的用法。
您能给它点灯吗?
答案 0 :(得分:0)
仅一次即可用于确保使用和处理输入主题不会导致输出主题重复。但是,从一次角度来看,您描述的输入主题中的重复项实际上并不是重复项,而是两条常规输入消息。
要除去输入主题重复项,可以使用带有附加状态存储的transform()
步骤(DSL中没有内置的运算符可以执行您想要的操作)。对于每个输入记录,首先要检查是否在商店中找到相应的键。如果没有,则将其添加到商店中并转发消息。如果在商店中找到它,则将输入重复删除。请注意,如果您在Kafka Streams应用程序中启用了一次精确处理,则只有在100%正确性保证的情况下才能使用。其他人,即使您尝试进行重复数据删除,如果发生故障,Kafka Streams可能会重新引入重复数据。
此外,您需要确定要将条目保留在商店中的时间。如果您确定输入主题中没有其他重复项,则可以使用Punctuation
从存储中删除旧数据。一种方法是将记录时间戳(或偏移量)也存储在存储中。这样,您可以将当前时间与punctuate()
中的商店记录时间进行比较,并删除旧记录(即,您可以通过store#all()
对商店中的所有条目进行迭代)。
在transform()
之后,您可以应用flatMap()
(或者也可以将flatMap()
代码直接合并到transform()
中。
答案 1 :(得分:0)
我的要求是跳过或避免使用kafka流DSL API从INPUT主题收到重复的消息(具有相同的密钥)。
看看https://github.com/confluentinc/kafka-streams-examples上的EventDeduplication
示例,它就是这样做的。然后,您可以使用特定于您的用例的必需flatMap
功能来修改示例。
这是示例的要点:
final KStream<byte[], String> input = builder.stream(inputTopic);
final KStream<byte[], String> deduplicated = input.transform(
// In this example, we assume that the record value as-is represents a unique event ID by
// which we can perform de-duplication. If your records are different, adapt the extractor
// function as needed.
() -> new DeduplicationTransformer<>(windowSize.toMillis(), (key, value) -> value),
storeName);
deduplicated.to(outputTopic);
和
/**
* @param maintainDurationPerEventInMs how long to "remember" a known event (or rather, an event
* ID), during the time of which any incoming duplicates of
* the event will be dropped, thereby de-duplicating the
* input.
* @param idExtractor extracts a unique identifier from a record by which we de-duplicate input
* records; if it returns null, the record will not be considered for
* de-duping but forwarded as-is.
*/
DeduplicationTransformer(final long maintainDurationPerEventInMs, final KeyValueMapper<K, V, E> idExtractor) {
if (maintainDurationPerEventInMs < 1) {
throw new IllegalArgumentException("maintain duration per event must be >= 1");
}
leftDurationMs = maintainDurationPerEventInMs / 2;
rightDurationMs = maintainDurationPerEventInMs - leftDurationMs;
this.idExtractor = idExtractor;
}
@Override
@SuppressWarnings("unchecked")
public void init(final ProcessorContext context) {
this.context = context;
eventIdStore = (WindowStore<E, Long>) context.getStateStore(storeName);
}
public KeyValue<K, V> transform(final K key, final V value) {
final E eventId = idExtractor.apply(key, value);
if (eventId == null) {
return KeyValue.pair(key, value);
} else {
final KeyValue<K, V> output;
if (isDuplicate(eventId)) {
output = null;
updateTimestampOfExistingEventToPreventExpiry(eventId, context.timestamp());
} else {
output = KeyValue.pair(key, value);
rememberNewEvent(eventId, context.timestamp());
}
return output;
}
}
private boolean isDuplicate(final E eventId) {
final long eventTime = context.timestamp();
final WindowStoreIterator<Long> timeIterator = eventIdStore.fetch(
eventId,
eventTime - leftDurationMs,
eventTime + rightDurationMs);
final boolean isDuplicate = timeIterator.hasNext();
timeIterator.close();
return isDuplicate;
}
private void updateTimestampOfExistingEventToPreventExpiry(final E eventId, final long newTimestamp) {
eventIdStore.put(eventId, newTimestamp, newTimestamp);
}
private void rememberNewEvent(final E eventId, final long timestamp) {
eventIdStore.put(eventId, timestamp, timestamp);
}
@Override
public void close() {
// Note: The store should NOT be closed manually here via `eventIdStore.close()`!
// The Kafka Streams API will automatically close stores when necessary.
}
}
我正在寻找DSL API,该API可以跳过从INPUT主题接收到的重复记录,并且还可以在发送到OUTPUT主题之前生成多个键/值。
DSL没有开箱即用的功能,但是上面的示例显示了如何通过将DSL与Kafka Streams的Processor API结合使用,轻松构建自己的重复数据删除逻辑。 1}}。
“精确思考一次”配置在此处可用于基于密钥对从INPUT主题接收到的消息进行重复数据删除,但看起来它无法正常工作,可能我不了解“精确修饰一次”的用法。
正如Matthias J. Sax在回答中提到的那样,从Kafka的角度来看,从其一次处理语义的角度来看,这些“重复项”不是重复项。 Kafka确保自己不会引入任何此类重复项,但不能为上游数据源即开即用地做出此类决定,而上游数据源是Kafka的黑匣子。
答案 2 :(得分:0)
感谢Matt和Michel的帮助。非常感激。
我当时正在考虑结合使用FlatMap和FilterNot API。只是模拟者到州立商店,我们将交易详细信息存储到canssandra中。
FilterNot-逻辑可以包括连接Cassandra和检查重复项。 FlatMap-逻辑包括生成多个键/值并将其发送到OUTPUT主题。
这里要考虑到与Cassandra的连接是否失败以及第一种建议的方法-在每天数百万笔交易,保留期等情况下,状态存储的可持续性。
请让我知道哪种方法更好。