之前搜索网上kafka事务相关文章,要么不清不楚,要么过于深奥。最近难得一闲,啃了一下kip-98,终于如愿能系统地总结一下kafka事务的原理与实现。
kafka官方设计文档 kip-98。大家可以先阅读我这篇文章,再去啃kip原文。
Kafka 的事务可以看作Kafka 中最难的知识点之一!
一般而言,消息中间件的消息传输保障有3个层级:
Kafka 的消息传输保障机制非常直观。当生产者向 Kafka 发送消息时,一旦消息被成功提交到日志文件,由于多副本机制的存在,这条消息就不会丢失。
Kafka从0.11.0.0版本开始引入了幂等和事务这两个特性,以此来实现EOS(exactly oncesemantics,精确一次处理语义)。
所谓的幂等,简单地说就是对接口的多次调用所产生的结果和调用一次是一致的。生产者在进行重试的时候有可能会重复写入消息,而使用Kafka的幂等性功能之后就可以避免这种情况。
为了实现生产者的幂等性,Kafka为此引入了
客户端需要开启enable.idempotence
为true。
为什么需要幂等?
因为事务开启后必然会有很多的失败重试
幂等性并不能跨多个分区运作,而事务可以弥补这个缺陷。事务可以保证对多个分区写入操作的原子性。操作的原子性是指多个操作要么全部成功,要么全部失败,不存在部分成功、部分失败的可能。
consume-transform-produce
原子操作consumer 事务语义相对弱一些
为了支持事务,kafka新增加了如下模块:
__transaction_state
持久化存储事务的日志ControlBatch
兼容老的ProduceBatch
,写到用户的topic,告诉用于之前fetch的数据是否已经commit。详见jira。 之前线上有个案例case,旧版本客户端消费该数据导致故障。注意4.3和4.4是Consume-Transform-Produce场景独有的步骤,涉及到消费和生产的联动,这里我不多介绍。
步骤:
PID\epoch\sequence number
字段
- 4.3 AddOffsetCommitsToTxnRequest:批量消费和生产时使用到。
sendOffsetsToTransaction(Map<TopicPartition, OffsetAndMetadata> offsets,
String consumerGroupId)
- 4.4 TxnOffsetCommitRequest 与4.3配合endTransaction
\ abortTransaction
abortTransaction
后 下游消费者读取后会丢弃掉对应的数据
收到这个请求后,
1)协调器将往事务日志里面写入PREPARE_COMMIT
和PREPARE_ABORT
消息。
2)发送COMMIT
或ABORT
marker到用户的数据里面(即5.2)。
3)事务日志写入COMMITTED
和ABORTED
消息。
- 5.2 WriteTxnMarkerRequest事务协调器发给各个tp的leader的broker,broker收到后会往对应的topic里面插入ControlBatch
(即marker)。告知该PID之前发送的消息的状态是怎么样的。注意:消费者需要缓存该PID的消息直到收到ControlBatch
信息,才直到应该如何处理这些消息(业务处理or丢弃)。ControlBatch
(即marker)写到tp里后,事务协调器会往事务日志里面写入COMMITTED
和ABORTED
消息,事务完成。不难分析,kafka的事务是相对轻量的,对性能影响相对可控。
kafka-producer-perf-test.sh
的 --transactional-id
用于测试并发事务的性能。
潜在性能下降点:单producer写入性能,特别是开启幂等后的性能下降。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。