连载中 6/20

消息不丢(下):Broker 刷盘与消费 ACK

2026-07-31 · 1930 阅读 · 0 评论 · 0 赞

中场休息并不安全

上一篇把消息从生产者安全送到了 Broker,但 Broker 只是「收到了」,离「永远不会丢」还有两道坎:它自己断电怎么办?消费端有没有把活干完?这一篇把后两关补齐。

Broker 第一道坎:刷盘策略

消息到了 Broker 先写入内存(页缓存),再落到磁盘。什么时候落盘,两种策略:

  • 同步刷盘(SYNC_FLUSH):消息真正写到磁盘上,才给生产者返回成功。机器断电,已确认的消息一条不丢。代价是写盘的延迟算进了发送链路,吞吐明显下降;
  • 异步刷盘(ASYNC_FLUSH):写进页缓存就返回成功,由后台线程批量刷盘。性能高得多,但断电瞬间缓存里没落盘的消息就没了——用户收到了「发送成功」,消息却不见了。

RocketMQ 默认异步刷盘,交易类业务要显式改成同步刷盘。Kafka 没有同步刷盘选项,它的思路是靠多副本换安全:一份数据在多台机器的页缓存里,全丢的概率大幅降低,性能还快。

Broker 第二道坎:主从复制

单台 Broker 刷盘刷得再勤,机器整个挂了数据还是没了。所以要有主从复制,又分两档:

  • 同步复制(SYNC_MASTER):主节点等从节点把消息写完,才给生产者返回成功。主挂了,从节点上有全量数据;
  • 异步复制:主节点写完就返回,从节点异步追。主挂的瞬间,还没追上的消息丢失。

Kafka 的对应概念是 acks=all:生产者等所有 ISR(同步副本集合)里的副本都写入才返回,配合 min.insync.replicas=2 和 replication.factor=3,允许坏一台机器不丢数据。

组合矩阵:稳和快的四档位

刷盘 x 复制组合可靠性适用
同步刷盘 + 同步复制最高,单机断电或宕机都不丢订单、支付等核心交易
同步刷盘 + 异步复制防断电,不防主机宕机折中场景,少用
异步刷盘 + 同步复制多机缓存互备,断电窗口小一般业务,性能与安全兼得
异步刷盘 + 异步复制最低,两端都有丢的窗口日志埋点,允许丢

消费端:ACK 时机是最容易踩的坑

消费端的丢法最隐蔽。两种时序:

  • 先提交位移,再处理业务:消费者拉到消息就提交 offset,然后干活。活干到一半进程崩溃,重启后 offset 已经过去了,这条消息再也不会被投递——丢了,而且是悄无声息地丢;
  • 先处理业务,再提交位移:业务成功后再 ACK。崩溃了位移没提交,重启后消息重投——重复消费,但至少没丢。重复用幂等解决(第 7 篇),丢失可没有后悔药。

结论只有一个:宁可重复,不可丢失,永远先干活后确认。Kafka 要把 enable.auto.commit 关掉,业务处理完手动 commitSync;RocketMQ 返回 CONSUME_SUCCESS 才算确认,抛异常或返回 RECONSUME_LATER 都会触发重投。

还要防一种死循环:业务代码有 bug,这条消息永远处理失败,于是永远重投——重投必须有上限(RocketMQ 默认 16 次),耗尽后进死信队列等人工介入,这正是第 11 篇的主角。

消息不丢全链路检查表

环节必须做的
生产端禁用 oneway;检查发送状态/回调异常;核心链路上本地消息表
Broker同步刷盘或 acks=all + min.insync.replicas>=2;同步复制
消费端关自动提交;业务成功后再 ACK;重试有上限,死信有告警
兜底生产-消费对账任务,定期核对两端的业务单号集合

小结

Broker 端靠「同步刷盘 + 同步复制」防天灾,消费端靠「先干活后 ACK」防人祸。三关守下来,消息不丢就有了工程保证——但请清醒:这套组合拳的每一次「确认」,都在制造重复的可能,不丢的代价就是把重复问题放大。

下一主角顺理成章:消息不重复——为什么「恰好一次」是营销话术,以及消费幂等的三板斧。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#消息队列#消息不丢#刷盘#同步复制#消费ACK

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10101 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9872 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9293 阅读 · 21 评论 · 287 赞