Kafka在金融系统中的实践
1. 概念
- 幂等性 + 事务性
- Kafka 的 enable.idempotence=true 解决了 生产端的消息重复发送问题,保证“至多一次” → “恰好一次”。
- transactional.id + 事务 API 则让生产者能把多个写操作当作原子单元,要么全写入,要么全不写。
- 消费者端隔离级别
- isolation.level=read_committed 确保消费端只读取 提交成功的事务消息,不会读到失败/未提交的写入。
- 这相当于 SQL 里的 READ COMMITTED 隔离级别。
- 两阶段提交(2PC)与事务日志
- Kafka 内部事务机制不是严格意义上的 分布式 XA 2PC,而是 Producer Coordinator + Transaction Log 的轻量实现。
- 当你把多个 Topic/Partition 的消息放在一个事务里时,Kafka 会写一条 事务日志(txn log),由 Coordinator 来决定事务的提交/中止状态,消费者依赖 txn log 过滤未提交消息。
- 所以它更像是 “Kafka 内部的两阶段提交”,如果要与外部数据库(如 MySQL、Redis)做一致性,仍需要 外部协调机制(典型是 Outbox Pattern)。
2. 工程实践
在金融支付类系统里,通常会结合以下手段来确保可靠性:
- 生产端配置最佳实践
1
2
3
4
5=true # 解决了生产端的消息重复发送问题,保证“至多一次” → “恰好一次”。
acks=all # 确保 ISR 同步确认,确保消息不重复
retries=Integer.MAX_VALUE # 确保消息不丢失
=1 # 避免并发请求导致的乱序
=tx-producer-001 - 消费端配置最佳实践
1
2
3
4=read_committed
=false # 结合事务手动提交offset
# offset 也写入 Kafka 的事务,确保消息消费与结果提交原子化。
# 常见模式是 Kafka + DB 的事务性写入(即 Outbox Pattern) - 幂等消费(Exactly Once Processing)
- 即使 Kafka 层面保证了 “Exactly Once Delivery”,但在消费者更新外部存储(数据库、账本系统)时,仍要确保幂等性。
- 常见做法:
- 使用 唯一事务ID/流水号 作为幂等键
- 在数据库侧维护 dedup 表/唯一索引,避免重复扣款
3. 金融场景案例
- 支付宝/微信支付 - 支付链路
- Kafka 事务常用于 支付事件流,比如:
- 扣款事件(资金冻结)
- 风控事件(交易审核)
- 清算/记账事件(账本入账)
- 如果任何一步失败,整个事务会被中止,消费者端不会看到“半成品交易”。
- Kafka 事务常用于 支付事件流,比如:
- 证券交易所撮合系统
- 撮合引擎把订单事件写入 Kafka,撮合成功后再写入交易结果事件,两者要么同时写入,要么同时回滚。
- 避免出现 “订单被接收但未撮合成功” 这种不一致。
- 银行账务系统(Outbox + Kafka EOS)
- 常见设计是 双写一致性:
- 业务库写账务流水(Outbox 表)
- Kafka Connect CDC 监听 Outbox 表 → 推送到 Kafka → 消费到清算/风控服务
- Outbox 表和账务写操作在同一数据库事务中完成,Kafka 端依赖 EOS 保证消息不丢不重。
- 常见设计是 双写一致性:
总结:Kafka EOS 只能保证 Kafka 内部端到端不丢不重,如果要与外部系统(DB/账本)做事务一致性,需要使用 Outbox Pattern 或幂等消费 来兜底。