文章目录
- 前言
- 一、消息丢失的全链路分析
- 二、生产者端:确保消息成功发送
-
- 2.1 核心配置
- 2.2 acks参数详解
- 2.3 幂等性原理
- 2.4 发送确认机制
- 三、Broker端:持久化与副本机制
-
- 3.1 副本机制架构
- 3.2 Broker端关键配置
- 3.3 为什么不能启用unclean选举
- 3.4 刷盘机制
- 四、消费者端:手动提交与幂等处理
-
- 4.1 消费确认流程
- 4.2 消费者端核心配置
- 4.3 手动提交的两种方式
- 4.4 消费者幂等性
- 五、Exactly-Once语义
-
- 5.1 三种语义级别
- 5.2 生产端Exactly-Once
- 5.3 消费端Exactly-Once
- 六、兜底方案:死信队列与补偿机制
-
- 6.1 死信队列设计
- 6.2 落库+定时任务
- 七、配置总结与最佳实践
-
- 7.1 全链路配置清单
- 7.2 不同场景的权衡
- 写在最后:
前言
在分布式系统中,消息丢失是致命的——少一条订单消息,可能意味着一个订单无法履约;少一条日志消息,可能让故障排查失去关键线索。Kafka虽然以高性能著称,但默认配置并不能保证消息完全不丢失。
"如何保证Kafka消息不丢失"是面试中的高频问题,更是生产环境必须面对的挑战。本文将从生产者端、Broker端、消费端三个维度,全面剖析消息丢失的原因及解决方案,并深入探讨幂等性、事务、Exactly-Once等高级话题。
一、消息丢失的全链路分析
#mermaid-svg-zvgmnDB2temXqivk{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zvgmnDB2temXqivk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zvgmnDB2temXqivk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zvgmnDB2temXqivk .error-icon{fill:#552222;}#mermaid-svg-zvgmnDB2temXqivk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zvgmnDB2temXqivk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zvgmnDB2temXqivk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zvgmnDB2temXqivk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zvgmnDB2temXqivk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zvgmnDB2temXqivk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zvgmnDB2temXqivk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zvgmnDB2temXqivk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zvgmnDB2temXqivk .marker.cross{stroke:#333333;}#mermaid-svg-zvgmnDB2temXqivk svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zvgmnDB2temXqivk p{margin:0;}#mermaid-svg-zvgmnDB2temXqivk .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-zvgmnDB2temXqivk .cluster-label text{fill:#333;}#mermaid-svg-zvgmnDB2temXqivk .cluster-label span{color:#333;}#mermaid-svg-zvgmnDB2temXqivk .cluster-label span p{background-color:transparent;}#mermaid-svg-zvgmnDB2temXqivk .label text,#mermaid-svg-zvgmnDB2temXqivk span{fill:#333;color:#333;}#mermaid-svg-zvgmnDB2temXqivk .node rect,#mermaid-svg-zvgmnDB2temXqivk .node circle,#mermaid-svg-zvgmnDB2temXqivk .node ellipse,#mermaid-svg-zvgmnDB2temXqivk .node polygon,#mermaid-svg-zvgmnDB2temXqivk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zvgmnDB2temXqivk .rough-node .label text,#mermaid-svg-zvgmnDB2temXqivk .node .label text,#mermaid-svg-zvgmnDB2temXqivk .image-shape .label,#mermaid-svg-zvgmnDB2temXqivk .icon-shape .label{text-anchor:middle;}#mermaid-svg-zvgmnDB2temXqivk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zvgmnDB2temXqivk .rough-node .label,#mermaid-svg-zvgmnDB2temXqivk .node .label,#mermaid-svg-zvgmnDB2temXqivk .image-shape .label,#mermaid-svg-zvgmnDB2temXqivk .icon-shape .label{text-align:center;}#mermaid-svg-zvgmnDB2temXqivk .node.clickable{cursor:pointer;}#mermaid-svg-zvgmnDB2temXqivk .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zvgmnDB2temXqivk .arrowheadPath{fill:#333333;}#mermaid-svg-zvgmnDB2temXqivk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zvgmnDB2temXqivk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zvgmnDB2temXqivk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zvgmnDB2temXqivk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zvgmnDB2temXqivk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zvgmnDB2temXqivk .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zvgmnDB2temXqivk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zvgmnDB2temXqivk .cluster text{fill:#333;}#mermaid-svg-zvgmnDB2temXqivk .cluster span{color:#333;}#mermaid-svg-zvgmnDB2temXqivk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zvgmnDB2temXqivk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zvgmnDB2temXqivk rect.text{fill:none;stroke-width:0;}#mermaid-svg-zvgmnDB2temXqivk .icon-shape,#mermaid-svg-zvgmnDB2temXqivk .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zvgmnDB2temXqivk .icon-shape p,#mermaid-svg-zvgmnDB2temXqivk .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zvgmnDB2temXqivk .icon-shape rect,#mermaid-svg-zvgmnDB2temXqivk .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zvgmnDB2temXqivk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zvgmnDB2temXqivk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zvgmnDB2temXqivk :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
可能丢失的环节
环节1:生产者发送失败
环节2:Leader宕机数据未同步
环节3:消费者处理成功但提交失败
消息流转链路
发送
存储
同步
消费
生产者
Kafka Broker
Partition Leader
ISR副本
消费者
消息丢失的三个环节:
- 生产者端:消息发送过程中网络故障、Leader宕机
- Broker端:消息已写入Leader但未同步到副本,Leader宕机
- 消费者端:消息消费后提交Offset前,业务处理失败
二、生产者端:确保消息成功发送
2.1 核心配置
| acks | all | 等待所有ISR副本确认,确保数据不丢 |
| retries | 3 或更大 | 网络抖动时自动重试 |
| enable.idempotence | true | 开启幂等性,防止重试导致重复 |
| max.in.flight.requests.per.connection | 5 | 幂等性开启时可大于1 |
2.2 acks参数详解
acks是生产者端最重要的可靠性参数:
| acks=0 | 发送即成功,不等待确认 | 最低,可能丢数据 | 最高 |
| acks=1 | Leader确认即可 | 中等,Leader宕机可能丢 | 中等 |
| acks=all | 所有ISR副本确认 | 最高,不会丢 | 最低 |
为什么acks=all能保证不丢:
- 消息写入Leader后,还要等待所有ISR(In-Sync Replicas)副本都写入成功
- 即使Leader宕机,ISR中也有完整的消息
- 配合min.insync.replicas配置,确保至少有N个副本确认
2.3 幂等性原理
开启幂等性(enable.idempotence=true)后,Kafka会为每个生产者分配一个唯一的Producer ID,并为每条消息生成一个单调递增的Sequence Number。
#mermaid-svg-XSpegie2CtsVtNHh{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XSpegie2CtsVtNHh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XSpegie2CtsVtNHh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XSpegie2CtsVtNHh .error-icon{fill:#552222;}#mermaid-svg-XSpegie2CtsVtNHh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XSpegie2CtsVtNHh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XSpegie2CtsVtNHh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XSpegie2CtsVtNHh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XSpegie2CtsVtNHh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XSpegie2CtsVtNHh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XSpegie2CtsVtNHh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XSpegie2CtsVtNHh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XSpegie2CtsVtNHh .marker.cross{stroke:#333333;}#mermaid-svg-XSpegie2CtsVtNHh svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XSpegie2CtsVtNHh p{margin:0;}#mermaid-svg-XSpegie2CtsVtNHh .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-XSpegie2CtsVtNHh .cluster-label text{fill:#333;}#mermaid-svg-XSpegie2CtsVtNHh .cluster-label span{color:#333;}#mermaid-svg-XSpegie2CtsVtNHh .cluster-label span p{background-color:transparent;}#mermaid-svg-XSpegie2CtsVtNHh .label text,#mermaid-svg-XSpegie2CtsVtNHh span{fill:#333;color:#333;}#mermaid-svg-XSpegie2CtsVtNHh .node rect,#mermaid-svg-XSpegie2CtsVtNHh .node circle,#mermaid-svg-XSpegie2CtsVtNHh .node ellipse,#mermaid-svg-XSpegie2CtsVtNHh .node polygon,#mermaid-svg-XSpegie2CtsVtNHh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XSpegie2CtsVtNHh .rough-node .label text,#mermaid-svg-XSpegie2CtsVtNHh .node .label text,#mermaid-svg-XSpegie2CtsVtNHh .image-shape .label,#mermaid-svg-XSpegie2CtsVtNHh .icon-shape .label{text-anchor:middle;}#mermaid-svg-XSpegie2CtsVtNHh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XSpegie2CtsVtNHh .rough-node .label,#mermaid-svg-XSpegie2CtsVtNHh .node .label,#mermaid-svg-XSpegie2CtsVtNHh .image-shape .label,#mermaid-svg-XSpegie2CtsVtNHh .icon-shape .label{text-align:center;}#mermaid-svg-XSpegie2CtsVtNHh .node.clickable{cursor:pointer;}#mermaid-svg-XSpegie2CtsVtNHh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XSpegie2CtsVtNHh .arrowheadPath{fill:#333333;}#mermaid-svg-XSpegie2CtsVtNHh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XSpegie2CtsVtNHh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XSpegie2CtsVtNHh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XSpegie2CtsVtNHh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XSpegie2CtsVtNHh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XSpegie2CtsVtNHh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XSpegie2CtsVtNHh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XSpegie2CtsVtNHh .cluster text{fill:#333;}#mermaid-svg-XSpegie2CtsVtNHh .cluster span{color:#333;}#mermaid-svg-XSpegie2CtsVtNHh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XSpegie2CtsVtNHh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XSpegie2CtsVtNHh rect.text{fill:none;stroke-width:0;}#mermaid-svg-XSpegie2CtsVtNHh .icon-shape,#mermaid-svg-XSpegie2CtsVtNHh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XSpegie2CtsVtNHh .icon-shape p,#mermaid-svg-XSpegie2CtsVtNHh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XSpegie2CtsVtNHh .icon-shape rect,#mermaid-svg-XSpegie2CtsVtNHh .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XSpegie2CtsVtNHh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XSpegie2CtsVtNHh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XSpegie2CtsVtNHh :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
幂等性去重
Producer ID:P1Sequence:1
Broker接收
Producer ID:P1Sequence:1
Broker收到重复
检查序列号已存在
直接返回成功不重复写入
幂等性的作用:
- 防止生产者重试导致的消息重复
- Broker端根据<PID, 分区, SeqNumber>去重
- 保证单个生产者、单个分区的Exactly-Once
2.4 发送确认机制
即使配置得当,也可能出现无法恢复的错误。因此,代码层面必须处理发送结果。
同步发送 + 回调 是可靠的实践:
三、Broker端:持久化与副本机制
3.1 副本机制架构
#mermaid-svg-tZHunJKWPlgSAEjc{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tZHunJKWPlgSAEjc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tZHunJKWPlgSAEjc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tZHunJKWPlgSAEjc .error-icon{fill:#552222;}#mermaid-svg-tZHunJKWPlgSAEjc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tZHunJKWPlgSAEjc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tZHunJKWPlgSAEjc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tZHunJKWPlgSAEjc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tZHunJKWPlgSAEjc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tZHunJKWPlgSAEjc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tZHunJKWPlgSAEjc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tZHunJKWPlgSAEjc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tZHunJKWPlgSAEjc .marker.cross{stroke:#333333;}#mermaid-svg-tZHunJKWPlgSAEjc svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tZHunJKWPlgSAEjc p{margin:0;}#mermaid-svg-tZHunJKWPlgSAEjc .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-tZHunJKWPlgSAEjc .cluster-label text{fill:#333;}#mermaid-svg-tZHunJKWPlgSAEjc .cluster-label span{color:#333;}#mermaid-svg-tZHunJKWPlgSAEjc .cluster-label span p{background-color:transparent;}#mermaid-svg-tZHunJKWPlgSAEjc .label text,#mermaid-svg-tZHunJKWPlgSAEjc span{fill:#333;color:#333;}#mermaid-svg-tZHunJKWPlgSAEjc .node rect,#mermaid-svg-tZHunJKWPlgSAEjc .node circle,#mermaid-svg-tZHunJKWPlgSAEjc .node ellipse,#mermaid-svg-tZHunJKWPlgSAEjc .node polygon,#mermaid-svg-tZHunJKWPlgSAEjc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-tZHunJKWPlgSAEjc .rough-node .label text,#mermaid-svg-tZHunJKWPlgSAEjc .node .label text,#mermaid-svg-tZHunJKWPlgSAEjc .image-shape .label,#mermaid-svg-tZHunJKWPlgSAEjc .icon-shape .label{text-anchor:middle;}#mermaid-svg-tZHunJKWPlgSAEjc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-tZHunJKWPlgSAEjc .rough-node .label,#mermaid-svg-tZHunJKWPlgSAEjc .node .label,#mermaid-svg-tZHunJKWPlgSAEjc .image-shape .label,#mermaid-svg-tZHunJKWPlgSAEjc .icon-shape .label{text-align:center;}#mermaid-svg-tZHunJKWPlgSAEjc .node.clickable{cursor:pointer;}#mermaid-svg-tZHunJKWPlgSAEjc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-tZHunJKWPlgSAEjc .arrowheadPath{fill:#333333;}#mermaid-svg-tZHunJKWPlgSAEjc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-tZHunJKWPlgSAEjc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-tZHunJKWPlgSAEjc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tZHunJKWPlgSAEjc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-tZHunJKWPlgSAEjc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tZHunJKWPlgSAEjc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-tZHunJKWPlgSAEjc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-tZHunJKWPlgSAEjc .cluster text{fill:#333;}#mermaid-svg-tZHunJKWPlgSAEjc .cluster span{color:#333;}#mermaid-svg-tZHunJKWPlgSAEjc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-tZHunJKWPlgSAEjc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-tZHunJKWPlgSAEjc rect.text{fill:none;stroke-width:0;}#mermaid-svg-tZHunJKWPlgSAEjc .icon-shape,#mermaid-svg-tZHunJKWPlgSAEjc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tZHunJKWPlgSAEjc .icon-shape p,#mermaid-svg-tZHunJKWPlgSAEjc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-tZHunJKWPlgSAEjc .icon-shape rect,#mermaid-svg-tZHunJKWPlgSAEjc .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tZHunJKWPlgSAEjc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-tZHunJKWPlgSAEjc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-tZHunJKWPlgSAEjc :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
ISR集合
Leader + 同步中的副本
min.insync.replicas=2
至少2个副本确认
Topic:orders-3副本
Partition 0Leader
Partition 0Follower 1
Partition 0Follower 2
Partition 1Follower
Partition 1Leader
Partition 1Follower
3.2 Broker端关键配置
| replication.factor | 3 | 每个分区至少3个副本 |
| min.insync.replicas | 2 | 最小ISR副本数,配合acks=all |
| unclean.leader.election.enable | false | 禁止非ISR副本成为Leader |
3.3 为什么不能启用unclean选举
场景:Leader宕机,ISR中只剩下一个副本,但这个副本也挂了。此时有一个非ISR副本(落后很多)还在。
- 启用unclean选举:非ISR副本成为Leader,丢失了ISR中已写入但未同步的数据
- 禁用unclean选举:等待ISR中副本恢复,期间分区不可用
权衡:Kafka选择了可用性 vs 一致性。对于金融、交易等场景,必须禁用unclean选举,保证数据一致性优先。
3.4 刷盘机制
Kafka虽然依赖页缓存,但最终数据要持久化到磁盘:
| flush.messages | 累积多少条消息刷盘 | 越高性能越好,宕机丢失越多 |
| flush.ms | 间隔多久刷盘 | 同上 |
生产建议:使用默认值(不主动刷盘),依赖副本机制保证可靠性。操作系统自己会刷盘,且多个副本同时宕机概率极低。
四、消费者端:手动提交与幂等处理
4.1 消费确认流程
#mermaid-svg-MU0I9laUkXvTxT7p{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MU0I9laUkXvTxT7p .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MU0I9laUkXvTxT7p .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MU0I9laUkXvTxT7p .error-icon{fill:#552222;}#mermaid-svg-MU0I9laUkXvTxT7p .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MU0I9laUkXvTxT7p .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MU0I9laUkXvTxT7p .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MU0I9laUkXvTxT7p .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MU0I9laUkXvTxT7p .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MU0I9laUkXvTxT7p .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MU0I9laUkXvTxT7p .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MU0I9laUkXvTxT7p .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MU0I9laUkXvTxT7p .marker.cross{stroke:#333333;}#mermaid-svg-MU0I9laUkXvTxT7p svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MU0I9laUkXvTxT7p p{margin:0;}#mermaid-svg-MU0I9laUkXvTxT7p .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-MU0I9laUkXvTxT7p .cluster-label text{fill:#333;}#mermaid-svg-MU0I9laUkXvTxT7p .cluster-label span{color:#333;}#mermaid-svg-MU0I9laUkXvTxT7p .cluster-label span p{background-color:transparent;}#mermaid-svg-MU0I9laUkXvTxT7p .label text,#mermaid-svg-MU0I9laUkXvTxT7p span{fill:#333;color:#333;}#mermaid-svg-MU0I9laUkXvTxT7p .node rect,#mermaid-svg-MU0I9laUkXvTxT7p .node circle,#mermaid-svg-MU0I9laUkXvTxT7p .node ellipse,#mermaid-svg-MU0I9laUkXvTxT7p .node polygon,#mermaid-svg-MU0I9laUkXvTxT7p .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MU0I9laUkXvTxT7p .rough-node .label text,#mermaid-svg-MU0I9laUkXvTxT7p .node .label text,#mermaid-svg-MU0I9laUkXvTxT7p .image-shape .label,#mermaid-svg-MU0I9laUkXvTxT7p .icon-shape .label{text-anchor:middle;}#mermaid-svg-MU0I9laUkXvTxT7p .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MU0I9laUkXvTxT7p .rough-node .label,#mermaid-svg-MU0I9laUkXvTxT7p .node .label,#mermaid-svg-MU0I9laUkXvTxT7p .image-shape .label,#mermaid-svg-MU0I9laUkXvTxT7p .icon-shape .label{text-align:center;}#mermaid-svg-MU0I9laUkXvTxT7p .node.clickable{cursor:pointer;}#mermaid-svg-MU0I9laUkXvTxT7p .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MU0I9laUkXvTxT7p .arrowheadPath{fill:#333333;}#mermaid-svg-MU0I9laUkXvTxT7p .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MU0I9laUkXvTxT7p .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MU0I9laUkXvTxT7p .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MU0I9laUkXvTxT7p .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MU0I9laUkXvTxT7p .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MU0I9laUkXvTxT7p .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MU0I9laUkXvTxT7p .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MU0I9laUkXvTxT7p .cluster text{fill:#333;}#mermaid-svg-MU0I9laUkXvTxT7p .cluster span{color:#333;}#mermaid-svg-MU0I9laUkXvTxT7p div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MU0I9laUkXvTxT7p .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MU0I9laUkXvTxT7p rect.text{fill:none;stroke-width:0;}#mermaid-svg-MU0I9laUkXvTxT7p .icon-shape,#mermaid-svg-MU0I9laUkXvTxT7p .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MU0I9laUkXvTxT7p .icon-shape p,#mermaid-svg-MU0I9laUkXvTxT7p .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MU0I9laUkXvTxT7p .icon-shape rect,#mermaid-svg-MU0I9laUkXvTxT7p .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MU0I9laUkXvTxT7p .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MU0I9laUkXvTxT7p .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MU0I9laUkXvTxT7p :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
可靠消费流程
是
否
拉取消息
业务处理
处理成功?
手动提交Offset
记录异常不提交Offset
等待下次拉取重新处理
4.2 消费者端核心配置
| enable.auto.commit | false | 关闭自动提交,改为手动 |
| auto.offset.reset | earliest | 无Offset时从最早开始消费 |
| max.poll.records | 500 | 控制每次拉取数量,避免处理超时 |
4.3 手动提交的两种方式
同步提交(commitSync):
- 阻塞直到提交成功
- 适合核心业务,确保Offset一定提交
- 性能较差
异步提交(commitAsync):
- 非阻塞,提交失败通过回调处理
- 性能好,但可能提交失败
- 通常结合重试机制
最佳实践:同步提交+重试机制,或在异步提交回调中处理失败情况。
4.4 消费者幂等性
消费者端也可能收到重复消息(如Rebalance后重新消费),因此业务处理必须幂等。
幂等实现方式:
- 业务主键去重:订单号、业务ID作为唯一键
- 数据库乐观锁:update … where version = oldVersion
- Redis分布式锁:处理前加锁,处理后释放
五、Exactly-Once语义
5.1 三种语义级别
| At Most Once | 最多一次 | 可能丢消息 |
| At Least Once | 至少一次 | 可能重复 |
| Exactly Once | 精确一次 | 不丢不重 |
Kafka默认是At Least Once,通过以下配置可以实现Exactly Once。
5.2 生产端Exactly-Once
幂等生产者 + 事务:
#mermaid-svg-2XnHpb7RH1IyDQL2{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2XnHpb7RH1IyDQL2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2XnHpb7RH1IyDQL2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2XnHpb7RH1IyDQL2 .error-icon{fill:#552222;}#mermaid-svg-2XnHpb7RH1IyDQL2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2XnHpb7RH1IyDQL2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2XnHpb7RH1IyDQL2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2XnHpb7RH1IyDQL2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2XnHpb7RH1IyDQL2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2XnHpb7RH1IyDQL2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2XnHpb7RH1IyDQL2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2XnHpb7RH1IyDQL2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2XnHpb7RH1IyDQL2 .marker.cross{stroke:#333333;}#mermaid-svg-2XnHpb7RH1IyDQL2 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2XnHpb7RH1IyDQL2 p{margin:0;}#mermaid-svg-2XnHpb7RH1IyDQL2 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-2XnHpb7RH1IyDQL2 .cluster-label text{fill:#333;}#mermaid-svg-2XnHpb7RH1IyDQL2 .cluster-label span{color:#333;}#mermaid-svg-2XnHpb7RH1IyDQL2 .cluster-label span p{background-color:transparent;}#mermaid-svg-2XnHpb7RH1IyDQL2 .label text,#mermaid-svg-2XnHpb7RH1IyDQL2 span{fill:#333;color:#333;}#mermaid-svg-2XnHpb7RH1IyDQL2 .node rect,#mermaid-svg-2XnHpb7RH1IyDQL2 .node circle,#mermaid-svg-2XnHpb7RH1IyDQL2 .node ellipse,#mermaid-svg-2XnHpb7RH1IyDQL2 .node polygon,#mermaid-svg-2XnHpb7RH1IyDQL2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2XnHpb7RH1IyDQL2 .rough-node .label text,#mermaid-svg-2XnHpb7RH1IyDQL2 .node .label text,#mermaid-svg-2XnHpb7RH1IyDQL2 .image-shape .label,#mermaid-svg-2XnHpb7RH1IyDQL2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-2XnHpb7RH1IyDQL2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2XnHpb7RH1IyDQL2 .rough-node .label,#mermaid-svg-2XnHpb7RH1IyDQL2 .node .label,#mermaid-svg-2XnHpb7RH1IyDQL2 .image-shape .label,#mermaid-svg-2XnHpb7RH1IyDQL2 .icon-shape .label{text-align:center;}#mermaid-svg-2XnHpb7RH1IyDQL2 .node.clickable{cursor:pointer;}#mermaid-svg-2XnHpb7RH1IyDQL2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2XnHpb7RH1IyDQL2 .arrowheadPath{fill:#333333;}#mermaid-svg-2XnHpb7RH1IyDQL2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2XnHpb7RH1IyDQL2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2XnHpb7RH1IyDQL2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2XnHpb7RH1IyDQL2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2XnHpb7RH1IyDQL2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2XnHpb7RH1IyDQL2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2XnHpb7RH1IyDQL2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2XnHpb7RH1IyDQL2 .cluster text{fill:#333;}#mermaid-svg-2XnHpb7RH1IyDQL2 .cluster span{color:#333;}#mermaid-svg-2XnHpb7RH1IyDQL2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2XnHpb7RH1IyDQL2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2XnHpb7RH1IyDQL2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-2XnHpb7RH1IyDQL2 .icon-shape,#mermaid-svg-2XnHpb7RH1IyDQL2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2XnHpb7RH1IyDQL2 .icon-shape p,#mermaid-svg-2XnHpb7RH1IyDQL2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2XnHpb7RH1IyDQL2 .icon-shape rect,#mermaid-svg-2XnHpb7RH1IyDQL2 .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2XnHpb7RH1IyDQL2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2XnHpb7RH1IyDQL2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2XnHpb7RH1IyDQL2 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
事务消息流程
beginTransaction
发送消息1
发送消息2
commitTransaction
所有消息原子提交
beginTransaction
发送消息
abortTransaction
所有消息回滚消费者不可见
事务的作用:
- 多个分区写入的原子性
- 生产者宕机恢复后,未提交的消息不会暴露
- 配合幂等性,实现跨分区Exactly-Once
5.3 消费端Exactly-Once
消费端Exactly-Once = 事务消息 + 幂等消费 + 原子提交
理想模型:
但实际操作复杂,常见做法是业务DB与Offset绑定:
- 将Offset存储在业务数据库的同一事务中
- 业务处理成功时,同时更新Offset
- 保证处理结果和消费进度原子性
六、兜底方案:死信队列与补偿机制
即使配置再完善,也无法100%保证不出现异常。兜底方案是最后一道防线。
6.1 死信队列设计
#mermaid-svg-BiBnJmKAJS6ICDFs{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BiBnJmKAJS6ICDFs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BiBnJmKAJS6ICDFs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BiBnJmKAJS6ICDFs .error-icon{fill:#552222;}#mermaid-svg-BiBnJmKAJS6ICDFs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BiBnJmKAJS6ICDFs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BiBnJmKAJS6ICDFs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BiBnJmKAJS6ICDFs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BiBnJmKAJS6ICDFs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BiBnJmKAJS6ICDFs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BiBnJmKAJS6ICDFs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BiBnJmKAJS6ICDFs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BiBnJmKAJS6ICDFs .marker.cross{stroke:#333333;}#mermaid-svg-BiBnJmKAJS6ICDFs svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BiBnJmKAJS6ICDFs p{margin:0;}#mermaid-svg-BiBnJmKAJS6ICDFs .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-BiBnJmKAJS6ICDFs .cluster-label text{fill:#333;}#mermaid-svg-BiBnJmKAJS6ICDFs .cluster-label span{color:#333;}#mermaid-svg-BiBnJmKAJS6ICDFs .cluster-label span p{background-color:transparent;}#mermaid-svg-BiBnJmKAJS6ICDFs .label text,#mermaid-svg-BiBnJmKAJS6ICDFs span{fill:#333;color:#333;}#mermaid-svg-BiBnJmKAJS6ICDFs .node rect,#mermaid-svg-BiBnJmKAJS6ICDFs .node circle,#mermaid-svg-BiBnJmKAJS6ICDFs .node ellipse,#mermaid-svg-BiBnJmKAJS6ICDFs .node polygon,#mermaid-svg-BiBnJmKAJS6ICDFs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BiBnJmKAJS6ICDFs .rough-node .label text,#mermaid-svg-BiBnJmKAJS6ICDFs .node .label text,#mermaid-svg-BiBnJmKAJS6ICDFs .image-shape .label,#mermaid-svg-BiBnJmKAJS6ICDFs .icon-shape .label{text-anchor:middle;}#mermaid-svg-BiBnJmKAJS6ICDFs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BiBnJmKAJS6ICDFs .rough-node .label,#mermaid-svg-BiBnJmKAJS6ICDFs .node .label,#mermaid-svg-BiBnJmKAJS6ICDFs .image-shape .label,#mermaid-svg-BiBnJmKAJS6ICDFs .icon-shape .label{text-align:center;}#mermaid-svg-BiBnJmKAJS6ICDFs .node.clickable{cursor:pointer;}#mermaid-svg-BiBnJmKAJS6ICDFs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BiBnJmKAJS6ICDFs .arrowheadPath{fill:#333333;}#mermaid-svg-BiBnJmKAJS6ICDFs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BiBnJmKAJS6ICDFs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BiBnJmKAJS6ICDFs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BiBnJmKAJS6ICDFs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BiBnJmKAJS6ICDFs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BiBnJmKAJS6ICDFs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BiBnJmKAJS6ICDFs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BiBnJmKAJS6ICDFs .cluster text{fill:#333;}#mermaid-svg-BiBnJmKAJS6ICDFs .cluster span{color:#333;}#mermaid-svg-BiBnJmKAJS6ICDFs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-BiBnJmKAJS6ICDFs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BiBnJmKAJS6ICDFs rect.text{fill:none;stroke-width:0;}#mermaid-svg-BiBnJmKAJS6ICDFs .icon-shape,#mermaid-svg-BiBnJmKAJS6ICDFs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BiBnJmKAJS6ICDFs .icon-shape p,#mermaid-svg-BiBnJmKAJS6ICDFs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BiBnJmKAJS6ICDFs .icon-shape rect,#mermaid-svg-BiBnJmKAJS6ICDFs .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BiBnJmKAJS6ICDFs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BiBnJmKAJS6ICDFs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BiBnJmKAJS6ICDFs :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
死信队列流程
否
是
消息发送失败
重试次数>3?
等待后重试
写入死信队列
人工介入
定时任务补偿
死信队列的作用:
- 隔离处理失败的消息
- 避免阻塞正常消息处理
- 提供人工介入和自动补偿的入口
6.2 落库+定时任务
对于核心业务,可以采取更保险的方式:
这种方式虽然牺牲了部分性能,但实现了业务操作与消息发送的原子性。
七、配置总结与最佳实践
7.1 全链路配置清单
| 生产者 | acks=all | 等待所有副本确认 |
| retries=3 | 网络抖动重试 | |
| enable.idempotence=true | 防止重试重复 | |
| 同步发送+回调 | 处理发送失败 | |
| Broker | replication.factor=3 | 3副本 |
| min.insync.replicas=2 | 至少2个同步副本 | |
| unclean.leader.election=false | 禁止落后副本成为Leader | |
| 消费者 | enable.auto.commit=false | 手动提交 |
| 业务处理成功后才提交 | 避免处理失败丢消息 | |
| 幂等处理 | 防止重复消费 | |
| 兜底 | 死信队列 | 隔离失败消息 |
| 落库+定时任务 | 核心业务双重保障 |
7.2 不同场景的权衡
| 日志收集 | acks=1,异步发送 | 可容忍少量丢失,追求吞吐 |
| 业务通知 | acks=all,幂等开启 | 不丢不重,中等吞吐 |
| 交易核心 | acks=all,事务+幂等 | 绝对不丢,接受性能损失 |
| 离线计算 | acks=all,批量消费 | 吞吐优先,允许一定延迟 |
写在最后:
Kafka消息不丢失不是一个单一配置能解决的问题,而是需要从生产端、Broker端、消费端三个维度,配合幂等性、事务、死信队列等机制,构建一个全链路可靠的消息系统。
记住:没有绝对的100%不丢失,只有无限接近100%的工程实践。理解原理、合理配置、完善监控、兜底补偿,是保证消息可靠性的四大支柱。

