订阅更新

广告归因数据丢了一条,ROI算错了——Producer的acks到底怎么配?

Kafka手册 第 2 题 约 6 分钟读完

本文目录
  1. 先说结论
  2. 三种acks模式详解
  3. acks=all的隐藏陷阱:min.insync.replicas
  4. 三种acks性能对比
  5. 实战经验:不同公司的不同选择
  6. 面试高频追问
  7. 总结

先说结论

acks参数决定了Producer认为消息'发送成功'的条件:acks=0(发了就忘,最快最危险)、acks=1(Leader写入即成功,默认值)、acks=all(ISR全部副本确认,最安全)。

实际生产中不同业务用不同配置:广告归因/交易数据用acks=all + min.insync.replicas=2;用户行为埋点/日志用acks=1够了;acks=0几乎不用。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

在某短剧出海公司,我负责投放中台的数据处理,提供每5分钟的数据时效,便于投手进行广告投放决策。广告归因数据每一条都直接影响ROI计算——如果某个广告平台回传的一条归因丢了,这个用户的获客成本就算错了,投手可能做出错误决策。这就是为什么Kafka的消息可靠性不是纸上谈兵,而是真金白银的问题。acks参数就是这道防线的核心。

三种acks模式详解

acks=0:发完就忘(Fire and Forget)

Producer发出消息后不等任何确认。Broker宕机或网络抖动,消息丢了Producer完全不知道。唯一优点是吞吐量最高。适用场景几乎没有,除非做压测。

acks=1:Leader确认(默认值)

Producer等Leader Broker写入本地Log就算成功。如果Leader写完后、Follower同步前Leader挂了,消息就丢了。概率很低但确实存在。对用户行为埋点,偶尔丢一两条不影响大盘统计,用acks=1就够了。

acks=all(或acks=-1):ISR全部确认

Producer等所有ISR副本都写入成功才算成功。最安全,但要配合min.insync.replicas用,否则ISR只剩Leader一个也算all,和acks=1没区别。

// Producer配置示例
Properties props = new Properties();
props.put("bootstrap.servers", "broker1:9092,broker2:9092,broker3:9092");
 
// 方案一:高吞吐(埋点/日志场景)
props.put("acks", "1");
props.put("retries", 3);                    // 失败重试3次
props.put("batch.size", 32768);              // 32KB批量发送
props.put("linger.ms", 5);                   // 等5ms攒一批再发
 
// 方案二:高可靠(交易/归因场景,我在短剧公司广告归因用这个)
props.put("acks", "all");
props.put("retries", Integer.MAX_VALUE);     // 无限重试
props.put("enable.idempotence", true);       // 幂等,防重试产生重复
props.put("max.in.flight.requests.per.connection", 5); // 幂等模式最多5

acks=all的隐藏陷阱:min.insync.replicas

很多人以为设了acks=all就万事大吉,其实不是。acks=all的含义是'所有ISR副本确认'。如果ISR只剩Leader一个(其他Follower都掉队了),acks=all等价于acks=1,该丢还是丢。

所以必须配合min.insync.replicas使用:

# Broker端配置(server.properties 或 Topic级别覆盖)
min.insync.replicas=2
 
# 推荐组合(3副本集群):
# replication.factor=3     ← 每个Partition 3个副本
# min.insync.replicas=2    ← 至少2个ISR副本确认
# acks=all                 ← Producer等所有ISR确认
#
# 效果:1个Broker挂了 → 剩2个ISR → 正常写入
#       2个Broker挂了 → ISR不足2个 → Producer报错(不丢数据但停写)
# 在停写和丢数据之间,我们选停写——数据补得回来,丢了就真没了

三种acks性能对比

维度acks=0acks=1acks=all
可靠性最低,可能丢中等,Leader挂会丢最高,ISR全确认
吞吐量最高高较低(等多副本确认)
延迟最低(<1ms)低(~5ms)较高(~10-20ms)
我的使用场景没用过埋点/行为日志广告归因/虚拟礼物交易
搭配参数无retries=3min.insync.replicas=2+幂等

实战经验:不同公司的不同选择

在某元宇宙社交公司:用户行为埋点(点击、浏览、在线时长)用acks=1,偶尔丢一两条不影响大盘统计。但虚拟礼物交易Topic用acks=all + min.insync.replicas=2,丢一条交易就会导致财务对不上账。

在某短剧出海公司:广告归因数据用acks=all。每条归因直接影响ROI计算——某广告平台回传说某用户是通过广告A获取的,如果丢了,广告A的ROI就偏低,投手可能误判效果不好而停掉它。归因数据宁可慢一点也不能丢。

在某知名出海硬件品牌:埋点SDK采集的数据经Kafka流入Databricks,用acks=1。将1000+埋点事件聚合为100+标准事件后,单条丢失对整体分析影响极小。

面试高频追问

追问一:开了acks=all消息就一定不丢吗?

不一定。三个漏洞:① 没配min.insync.replicas,ISR退化到只剩Leader;② Broker磁盘坏了,数据还在Page Cache没刷盘;③ Producer端发送前就失败了(比如序列化异常),消息根本没进Kafka。端到端不丢还需要Producer的回调确认+Consumer的手动提交offset。

追问二:acks=all会不会很慢?

比acks=1慢,但没想象中夸张。3副本集群大约多10-15ms延迟。可以增大batch.size和linger.ms来提吞吐。我在短剧公司的归因链路,acks=all配合linger.ms=10ms,端到端5分钟时效完全没问题。

追问三:enable.idempotence是什么?

开启Producer幂等性。retries>0时,网络抖动可能导致同一条消息发两次。幂等模式下Kafka给每条消息一个序列号,Broker端自动去重。推荐acks=all时一起开启。

总结

acks参数是Kafka可靠性的第一道防线。面试时记住万能公式:acks=all + min.insync.replicas=2 + replication.factor=3 = 金融级可靠性。然后根据业务场景说清楚'为什么埋点用acks=1、交易用acks=all',面试官会觉得你对可靠性有分层认知,而不是无脑all。

下一篇聊Consumer端的问题:Flink消费Kafka突然全停了,Rebalance到底怎么回事?

你们核心Topic的acks配的啥?有没有因为acks配错丢过数据?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器