我正在使用Kafka作为消息代理,为一个简单的数据管道实现完全一次语义。我可以通过设置集合const postsCount = await Post.find(query).countDocuments();
const allPosts = await Post.find(query)
.populate('likes')
.skip(startIndex)
.limit(noOfRecordsPerPage)
.sort({ createdAt: 'desc' });
来强制Kafka生产者将每个生产记录精确地写入一次。
但是,在消耗方面,我需要保证消费者只读取一次每个记录(我不希望将消耗的记录存储到外部系统或刚刚处理的另一个Kafka主题中)。为此,我必须确保处理轮询的记录,并将它们的偏移量以原子方式/事务方式(同时成功/失败)提交给enable.idempotence=true
主题。
在这种情况下,我是否需要使用Kafka事务API在消费者轮询循环中创建事务生产者,在事务内部执行以下操作:(1)处理消耗的记录,(2)提交其偏移量,然后完成交易。在这种情况下,正常的commitSync / commitAsync是否可以提供服务?
答案 0 :(得分:1)
“在消费方面,我需要保证消费者准确地读取每个记录一次”
Gopinath的答案很好地说明了如何在KafkaProducer和KafkaConsumer之间实现一次精确匹配。这些配置(连同KafkaProducer中Transaction API的应用程序)确保了生产者发送的所有数据将只存储在Kafka中一次。但是,它不能保证消费者只读取一次数据。当然,这取决于您的胶印管理。
无论如何,我了解您的问题,您想知道使用者本身是如何一次处理消耗的消息。
为此,您需要以原子方式自行管理偏移。这意味着您需要围绕自己构建“交易”
commitSync和commitAsync方法将使您无所适从,因为它们只能确保在Consumer中最多处理一次或最少处理一次。另外,您的处理是幂等的。
有一个不错的blog,它解释了一种利用ConsumerRebalanceListener
并将其偏移量存储在本地文件系统中的实现。还提供了完整的代码示例。
“我是否需要借助Kafka交易API在消费者轮询循环中创建交易生产者”
Transaction API仅适用于KafkaProducers,据我所知不能用于您的胶印管理。
答案 1 :(得分:0)
'一次'功能可以通过以下三种设置的组合来实现:
isolation.level = read_committed
transactional.id = <unique_id>
processing.guarantee = exactly_once
有关启用一次功能的更多信息:
https://www.confluent.io/blog/simplified-robust-exactly-one-semantics-in-kafka-2-5/
https://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how-apache-kafka-does-it/