Kafka 高频面试题

1 阅读36分钟
  • 视角:从面试官(出题人)视角拆解 11 个 Kafka 高频题型——问什么、听到什么算 60/80/95 分、怎么追问、什么是踩坑信号

  • 使用方式

    • 候选人视角:自检"我现在能讲到几分?"→ 哪些点漏了 → 补

    • 真面试场上:判断面试官的追问意图 → 选合适深度回答

    • 不要死背答案:背答案 = 60 分上限。理解评分逻辑才能上 80/95

  • 重要:评分档是累加关系——95 分必须先满足 60 + 80 的全部要求。跳级讲花活但漏了基础 = 直接挂


📑 11 个高频题型目录

  1. 消息丢失怎么排查与防御
  2. Rebalance 风暴怎么避免
  3. acks=all 真的不丢吗
  4. ISR 机制为什么这样设计
  5. 事务 + EOS 端到端怎么实现
  6. Producer 幂等的实现细节
  7. 消息积压 / 消费跟不上怎么办
  8. 设计百万 QPS 消息系统
  9. 顺序消费怎么保证
  10. Kafka 为什么快
  11. Kafka vs RocketMQ vs Pulsar 选型

📊 题型 1:消息丢失怎么排查与防御

面试官内心 OS

"这是 Kafka 题里最高频的,几乎必问。我要看你有没有真的处理过线上丢消息事故,还是只会背 acks=all。"

评分档

分档听到什么
60 分能说出 acks=all + min.insync.replicas=2 + enable.idempotence=true 三件套
80 分+ 拆解三段路径(Producer / Broker / Consumer 各自怎么丢、怎么防)+ 提到 unclean.leader.election + 提到 Consumer "先处理再 commit"
95 分+ 怎么发现真的丢了(不能只看 Lag,要 Outbox 表 / 日终对账 / 端到端埋点)+ ISR 全挂时的兜底 + 资损口径量化

面试官追问树


候选人:"我用 acks=all + min.insync.replicas=2 保证不丢"

   ↓

面试官追问 1:min.insync.replicas=2,3 副本,挂 1 个会怎样?

   候选人答得出 → 进入追问 2

   答不出 → 60 分封顶

   ↓

面试官追问 2:那挂 2 个会怎样?业务怎么兜底?

   答 "Producer 报错让业务侧重试" → 70 分

   答 "本地 disk fallback / 写 DB Outbox 兜底" → 85 分

   答 "+ 监控 UnderMinIsr 告警 + 降级开关临时调 1" → 95 分

   ↓

面试官追问 3:怎么知道真的丢了?

   答 "看 Lag" → 减分(错误,先处理后提交时 Lag=0 但消息已丢)

   答 "端到端埋点 + 日终对账" → 满分

踩坑信号(面试官扣分点)

❌ "acks=all 就一定不丢" → ,min.insync.replicas 不配等于裸奔

❌ "Kafka 写完就 fsync" → ,Kafka 默认依赖 OS PageCache + 副本冗余

❌ "Consumer 自动提交不会丢" → ,自动提交 + 异步处理是经典丢消息姿势

❌ 不提 unclean.leader.election → 减 5 分

❌ 不能给"丢的概率量化"(万分之 X / 百万分之 Y) → 减 10 分

高分加分项

✅ 主动提"sendfile 在 SSL 下退化"+ 兜底

✅ 主动提"跨机房副本放置(rack-aware)"

✅ 主动讲一次自己处理过的真实事故(STAR 模板)

💎 95 分口述范文

消息丢失防御我分三段讲:Producer → Broker → Consumer

Producer 侧acks=all + enable.idempotence=true,保证消息至少写入所有 ISR 副本并去重。但光有 acks=all 不够,必须配合 min.insync.replicas=2,否则 ISR 只剩 leader 一个时 acks=all 退化成 acks=1。同时 unclean.leader.election.enabled=false,杜绝 OSR 副本当选 leader 导致 HW 截断丢数据。Producer 重试用 retries=Integer.MAX_VALUE + delivery.timeout.ms 兜底,max.in.flight.requests.per.connection≤5 保证幂等下顺序。

Broker 侧:3 副本 + rack-aware 部署,跨机架甚至跨 AZ。Kafka 默认不 fsync,依赖 OS PageCache + 多副本冗余。如果 ISR 全挂,我们有两个兜底:一是 Producer 收到 NotEnoughReplicas 异常后写本地磁盘 fallback 文件或 DB Outbox 表;二是监控 UnderMinIsrPartitionCount 指标,告警后人工介入,极端情况可临时把 min.insync.replicas 调成 1。

Consumer 侧:关闭自动提交(enable.auto.commit=false),采用"先处理再手动 commit"模式。如果业务处理失败,不提交 offset,下次重新消费。消费逻辑本身要做幂等(业务唯一键 + upsert / 状态机)。

怎么发现真的丢了——这是最容易被忽略的。不能只看 Consumer Lag,因为"先处理后提交"模式下 Lag=0 但消息可能已经在处理环节丢了。我们用三层检测:①Producer 端埋点记录每条消息的 msgId 到 Outbox 表;②Consumer 端消费后回写确认;③日终对账任务对比 Outbox 和确认表,diff 就是丢失量。线上我们实测丢失率 < 百万分之一,主要来自极端场景(AZ 级故障 + ISR 全挂同时发生)。


📊 题型 2:Rebalance 风暴怎么避免

面试官内心 OS

"看你真做过 200+ 实例的消费组没有。如果没踩过坑,回答会很表面。"

评分档

分档听到什么
60 分能说 "Cooperative Sticky Assignor" + "调大 session.timeout.ms"
80 分+ Static Membership(KIP-345)+ "拉取与处理解耦"线程模型 + 触发原因分类(成员变更 / 心跳超时 / poll 超时)
95 分+ Rebalance 三代协议演进(Eager → Cooperative → KIP-848)+ 监控 NumGroupsPreparingRebalance + 真实事故 STAR

面试官追问树


候选人:"改 Cooperative + Static Membership 就好了"

   ↓

追问 1:Cooperative 比 Eager 好在哪儿?源码层面有什么变化?

   答 "增量 Rebalance" → 70 分

   答 "+ 两阶段 SyncGroup + onPartitionsLost 回调" → 90 分

   ↓

追问 2:Static Membership 配 group.instance.id 后,K8s 滚动重启不触发 Rebalance 的前提是什么?

   答不出 → 减分(前提是重启在 session.timeout.ms 内完成)

   答出 → 进追问 3

   ↓

追问 3:max.poll.interval.ms 为什么不能无脑放大?

   答 "处理慢的消息会挂着不退" → 80 分

   答 "+ 真正应该改的是异步线程池模型" → 95 分

踩坑信号

❌ 答 "用 Range 分配就行" → 直接 60 分以下(Range 是默认但不解决问题)

❌ "调大 session.timeout 到 10 分钟" 但说不出代价 → 减分

❌ 不知道 max.poll.interval.ms 和 session.timeout.ms 区别 → 严重减分

❌ 把"心跳"和"poll 间隔"搞混 → 直接挂

高分加分项

✅ 提 KIP-848(next-gen consumer rebalance protocol,broker 主导)

✅ 主动画出"心跳线程 vs 业务线程"双线模型

✅ 量化:日均 Rebalance 从 50+ 降到 < 5 次

💎 95 分口述范文

Rebalance 问题我从触发原因 → 协议演进 → 实战方案三层讲。

触发原因分三类:①成员变更(Consumer 上下线、K8s 滚动重启);②心跳超时(session.timeout.ms 内没收到心跳,默认 45s);③Poll 超时(max.poll.interval.ms 内没调 poll(),默认 5min,说明业务处理太慢)。很多人把心跳超时和 poll 超时搞混——3.x 后心跳由独立后台线程发送,和业务处理线程解耦。

协议演进三代:第一代 Eager(全量 revoke 再 reassign,停止世界)→ 第二代 Cooperative Sticky(KIP-429,增量 Rebalance,只迁移需要变更的分区,两阶段 SyncGroup)→ 第三代 KIP-848(broker 主导的 Server-side Rebalance,Consumer 不再需要 JoinGroup/SyncGroup 协调,预计 4.0 GA)。

实战方案:①分配策略换 CooperativeStickyAssignor;②开启 Static Membership,配 group.instance.id(推荐用 Pod 名),K8s 滚动重启只要在 session.timeout.ms 内完成就不触发 Rebalance;③不要无脑调大 max.poll.interval.ms——处理慢的消息会挂着不退让整组受影响,正确做法是把拉取和处理解耦:poll 线程只负责拉取放入内存队列,业务线程池异步消费。④监控 kafka.coordinator.group:NumGroupsPreparingRebalance,告警阈值 > 3。

我们线上 200+ 实例的消费组,用这套方案后日均 Rebalance 从 50+ 次降到 < 5 次,P99 消费延迟从 8s 降到 200ms。


📊 题型 3:acks=all 真的不丢吗

面试官内心 OS

"陷阱题。99% 的候选人会答 '不丢'。我等的就是那 1% 能说出'不一定'的人。"

评分档

分档听到什么
60 分答 "不丢"(基础正确,但没看到陷阱)
80 分答 "不一定,min.insync.replicas 不配置时 ack=all = ack=1"
95 分+ unclean.leader.election=true 时,即使 acks=all 也会丢 + ISR 全挂时的多种降级路径

面试官追问树


追问 1:min.insync.replicas 默认值是多少?

   答 "1" → 候选人意识到陷阱了,进追问 2

   答 "2 / 我没注意" → 60 分封顶

   ↓

追问 2:unclean.leader.election=true,acks=all 会丢吗?

   答 "不会" → 错,立刻减分

   答 "会,因为可以选 OSR 当 leader → HW 截断 → 丢" → 90 分

   ↓

追问 3:你怎么向 PM / 业务方解释 "金融级不丢" 不是 100%?

   答 "靠副本数 + 跨机架 + 跨机房,丢的概率降到 X * 10^-N" → 满分

踩坑信号

❌ "acks=all 永远不丢" → 直接 60 分以下

❌ 不知道 min.insync.replicas 默认值 = 1

❌ 不知道 unclean.leader.election 是个开关

❌ 把"不丢"和"高可用"混为一谈

高分加分项

✅ 主动画时间轴:"t1 broker-2 挂 → t2 broker-3 GC 抖出 ISR → t3 broker-1 挂 → 数据丢"

✅ 提 Leader Epoch(KIP-101)修复了 HW 截断丢数据

✅ 给业务方"丢消息概率"的量化公式

💎 95 分口述范文

这是个陷阱题,答案是不一定

陷阱一:min.insync.replicas 默认值是 1。这意味着 acks=all 只要 leader 自己写成功就返回 ack,等价于 acks=1。所以必须显式配 min.insync.replicas=2(3 副本集群)。

陷阱二:unclean.leader.election.enabled=true。即使配了 min.insync.replicas=2,一旦 ISR 全挂,如果允许 OSR(落后副本)当选 leader,新 leader 的 HW 比老 leader 低,会发生日志截断,已提交的消息被丢弃。Kafka 0.11+ 默认 false,但有些老集群升级时没改。

陷阱三:时间窗口。画个时间轴:t1 broker-2 宕机退出 ISR → t2 broker-3 发生 Full GC 30s+ 被踢出 ISR → 此时 ISR 只剩 leader broker-1 → 如果 min.insync.replicas=2,Producer 会收到 NotEnoughReplicasException 写入失败,消息不丢但不可用。如果此时 min.insync.replicas=1,消息只写在 broker-1 → t3 broker-1 也挂了 → 数据丢失。

怎么跟业务方解释"金融级不丢"不是 100%:靠 3 副本 + 跨机架 + 跨 AZ 部署,把"三个副本同时不可用"的概率降到工程可接受范围。假设单机年故障率 1%,3 副本跨机架同时故障概率约 10⁻⁶ 量级。再加 Leader Epoch(KIP-101)修复 HW 截断问题,实际丢消息概率趋近于零,但永远不是零——所以业务层还要有 Outbox + 对账兜底。


📊 题型 4:ISR 机制为什么这样设计

面试官内心 OS

"架构师面试题。看你能不能从 PacificA / Raft / Multi-Paxos 的角度理解 Kafka 的设计哲学。"

评分档

分档听到什么
60 分能说 "ISR 是同步副本集合,HW 取决于 ISR 最小 LEO"
80 分+ ISR 进出条件(replica.lag.time.max.ms)+ ISR 是 PacificA 协议的变种
95 分+ 对比:ISR vs Raft(副本数差异 / 写延迟 / 一致性强度)+ 为什么 KRaft 元数据反而用 Raft 不用 ISR

面试官追问树


追问 1:ISR vs Raft,本质区别是什么?

   答 "ISR 是全副本同步,Raft 是多数派" → 80 分

   答 "+ ISR 副本经济(3 副本容忍 1 故障 vs Raft 5 副本)" → 90 分

   答 "+ ISR 牺牲严格强一致换吞吐 + 副本经济性" → 95 分

   ↓

追问 2:为什么 KRaft 元数据用 Raft,不用 ISR?

   答 "元数据写量小,副本数差异成本可忽略" → 90 分

   答 "+ 元数据需要严格强一致避免 split-brain" → 95 分

   ↓

追问 3:ISR 进出有哪些 corner case?

   答 "replica.lag.time.max.ms 默认 30s 太长" → 70 分

   答 "+ KIP-329 缩短拉取频次后实际进出更稳" → 90 分

踩坑信号

❌ "ISR 就是同步副本" → 浅,没说"动态成员"

❌ 不知道 PacificA → P8 候选人 80 分以下

❌ 答 "ISR 比 Raft 更好" → 错,没有更好,只有适合

❌ 不能解释 "为什么 KRaft 元数据用 Raft"

高分加分项

✅ 一句话总结:"ISR = 全副本同步 + 动态成员;Raft = 多数派同步 + 选主"

✅ 主动提 OSR / 慢副本踢出 / Leader Epoch

✅ 主动展开 HW vs LEO vs LSO 的关系

💎 95 分口述范文

ISR 的设计哲学要从分布式共识协议对比讲起。

ISR 本质是 PacificA 协议的变种:所有副本都参与同步(全副本同步),但成员是动态的——通过 replica.lag.time.max.ms(默认 30s)判断副本是否跟得上,跟不上的踢到 OSR,追上了再加回 ISR。HW(High Watermark)= ISR 中最小的 LEO(Log End Offset),Consumer 只能看到 HW 以下的消息。

对比 Raft:Raft 是多数派同步(quorum),5 副本写 3 个 ack 就算成功。ISR 的优势是副本经济性——3 副本就能容忍 1 个故障(因为要求全副本同步),而 Raft 3 副本容忍 1 故障需要 2/3 确认,虽然数学上一样,但 Raft 的标准部署是 5 副本容忍 2 故障。ISR 的代价是牺牲了严格强一致性(ISR 缩到 1 时退化)换取高吞吐。

为什么 KRaft 元数据用 Raft 不用 ISR:元数据写入量小(Topic/Partition 变更远少于消息写入),副本经济性差异可忽略。但元数据需要严格强一致避免 split-brain(Controller 脑裂会导致整个集群元数据不一致),Raft 的 Leader 选举和日志复制天然保证 linearizability,ISR 的动态成员机制在元数据场景反而是风险。

ISR 进出 corner casereplica.lag.time.max.ms=30s 偏长,GC 抖一下 10s 不会被踢,但真正落后的副本也要等 30s 才踢。KIP-329 优化了 follower fetch 频率,让进出判断更精准。另外 ISR 变更会写 ZK/KRaft 元数据,频繁进出会产生元数据写放大。HW vs LEO vs LSO 三者关系:LEO 是每个副本自己的最新 offset,HW 是 ISR 最小 LEO(Consumer 可见边界),LSO 是最小未完成事务的 offset(read_committed 模式的可见边界)。


📊 题型 5:事务 + EOS 端到端怎么实现

面试官内心 OS

"P8 / 架构师题。EOS 是 Kafka 最复杂的特性之一,能讲清楚说明你真的看过源码 / 文档。"

评分档

分档听到什么
60 分"事务 = 幂等 Producer + transactional.id + 2PC"
80 分+ Transaction Coordinator + Control Records + LSO + Consumer 的 read_committed
95 分+ Flink + Kafka EOS(Checkpoint 2PC Sink)+ "EOS 是基础设施 + 业务层共同保证"的辩证理解

面试官追问树


追问 1:transactional.id 重启后会怎样?

   答 "fence 老事务" → 80 分

   答 "+ 调 initTransactions() 后老 PID 失效,未提交事务自动 abort" → 90 分

   ↓

追问 2:Control Records 是什么?写在哪儿?

   答 "COMMIT / ABORT 标记,写在 Topic 分区里" → 80 分

   答 "+ Consumer 用它来过滤 read_committed 模式下的消息" → 90 分

   ↓

追问 3:Flink Sink 的事务超时该设多大?

   答 "比 Checkpoint 间隔大" → 80 分

   答 "+ 但不能超过 broker 的 transaction.max.timeout.ms(默认 15min)" → 90 分

   答 "+ 否则 broker 会主动 abort 事务,Flink Job 失败" → 95 分

   ↓

追问 4:金融场景下,Kafka 事务能保证业务"恰好一次"吗?

   答 "能" → 错,立刻减分(金融场景需要业务侧配合)

   答 "Kafka 提供基础设施 EOS,业务层还要做幂等键 + 状态机 + 对账" → 95 分

踩坑信号

❌ "Kafka 事务 = 数据库事务" → 严重错误(粒度 / 跨集群 / ACID 都不一样)

❌ 不知道 transactional.id 跨重启如何 fence

❌ 不知道 LSO 和 HW 的区别

❌ "read_committed = 强一致" → 错(只是过滤未提交)

高分加分项

✅ 画出 Flink 2PC Sink 的时序图

✅ 提 Kafka 事务的局限:跨集群事务不支持(这是 RocketMQ / Pulsar 优势点)

✅ 主动讲业务层 Outbox + 对账兜底

💎 95 分口述范文

Kafka 事务和 EOS 我分基础设施层业务层两个维度讲。

基础设施层:Kafka 事务 = 幂等 Producer + transactional.id + 两阶段提交。核心组件是 Transaction Coordinator(每个 transactional.id hash 到一个 __transaction_state 分区的 leader)。流程:①initTransactions() 获取 PID 并 fence 掉同 transactional.id 的老 Producer(老 PID 的未提交事务自动 abort);②beginTransaction() 开启事务;③发送消息到业务 Topic + 发送 offset 到 __consumer_offsets;④commitTransaction() 触发 Coordinator 写 COMMIT Control Record 到所有涉及的分区。Consumer 设 isolation.level=read_committed 后,只能看到 LSO(Last Stable Offset)以下的消息,未提交/已 abort 的事务消息被过滤。

Flink + Kafka EOS:Flink 用 Checkpoint 驱动的 2PC Sink。预提交阶段 Sink 写消息但不 commit;Checkpoint 完成后触发 commit。关键配置:Sink 的 transaction.timeout.ms 必须 > Checkpoint 间隔,但不能超过 broker 的 transaction.max.timeout.ms(默认 15min),否则 broker 主动 abort 事务导致 Flink Job failover。

业务层的辩证理解:Kafka EOS 保证的是"消息从 Topic A 消费 → 处理 → 写入 Topic B"这条链路的 exactly-once。但金融场景下,消息写入 Topic 后还要落 DB、调外部 API、更新缓存——这些 Kafka 事务管不了。所以真正的端到端 exactly-once = Kafka EOS(基础设施)+ 业务幂等键(防重复处理)+ 状态机(防乱序)+ 日终对账(兜底检测)。只靠 Kafka 事务声称"恰好一次"是不够的。


📊 题型 6:Producer 幂等的实现细节

面试官内心 OS

"字节字节字节。字节面试官最爱这种源码题。你说不出 PID / Sequence / 5 batch 缓存就直接挂。"

评分档

分档听到什么
60 分"幂等 = 开 enable.idempotence + Broker 检测重复 → 丢弃"
80 分+ PID(Producer ID)+ Sequence Number 单分区单调递增 + ProducerStateManager 缓存最近 5 batch
95 分+ 为什么是 5 batch(max.in.flight=5 的硬约束)+ PID 过期清理(producer.id.expiration.ms)+ 重启 PID 重新分配的影响

面试官追问树


追问 1:max.in.flight.requests.per.connection 上限为什么是 5?

   答不出 → 70 分封顶

   答 "因为 ProducerStateManager 只缓存 5 batch" → 90 分

   答 "+ 超过 5 broker 没法判断顺序,可能误判重复" → 95 分

   ↓

追问 2:Producer 重启后 PID 变了,幂等还有用吗?

   答 "有" → 错(PID 变了 broker 没法关联老 PID 的请求)

   答 "无,跨重启需要 transactional.id" → 90 分

   ↓

追问 3:Sequence 用 int32 还是 int64?溢出会怎样?

   答不出 → 减分

   答 "int32,溢出可能误判重复,所以长生命周期 Producer 要谨慎" → 95 分

踩坑信号

❌ "幂等就是开个开关" → 60 分封顶

❌ 不知道 PID / Sequence 的作用

❌ "幂等 = 跨重启不重复" → 错(重启 PID 变了不再幂等)

❌ 把幂等和事务混淆

高分加分项

✅ 主动指出"幂等只防 Producer → Broker 单跳重复,不防 Consumer 重复消费"

✅ 提到 ProducerStateManager 的 snapshot 机制

✅ 提到 OutOfOrderSequenceException

💎 95 分口述范文

Producer 幂等的实现我从机制 → 边界 → 陷阱三层讲。

机制:开启 enable.idempotence=true 后,Producer 启动时从 Broker 获取一个 PID(Producer ID),每个 <PID, Partition> 维护一个单调递增的 Sequence Number。Broker 端的 ProducerStateManager 为每个 PID 缓存最近 5 个 batch 的 Sequence。收到消息时:Seq = 期望值 → 正常写入;Seq < 期望值 → 重复,丢弃返回成功(不报错);Seq > 期望值 → 乱序,抛 OutOfOrderSequenceException

为什么是 5 batch:因为 max.in.flight.requests.per.connection 在幂等模式下硬约束为 ≤ 5。最多同时有 5 个 batch 在途,所以 Broker 只需缓存 5 个即可判断重复和乱序。超过 5 个 in-flight 请求,Broker 没法确定中间是否有跳号,可能误判。ProducerStateManager 会定期将状态 snapshot 到磁盘(<partition>/.snapshot 文件),Leader 切换时新 Leader 从 snapshot 恢复。

边界与陷阱:①幂等只防 Producer → Broker 单跳重复,不防 Consumer 端重复消费(Consumer 要自己做业务幂等);②PID 是临时的——Producer 重启后获取新 PID,老 PID 的 Sequence 无法关联,所以幂等不跨重启,跨重启需要 transactional.id;③Sequence 是 int32(0 ~ 2³¹-1),理论上单分区发 21 亿条后溢出归零,可能误判重复,长生命周期 Producer 需要注意;④producer.id.expiration.ms(默认 7 天)控制 PID 过期清理,过期后再发就是新 PID,等于幂等状态重置。


📊 题型 7:消息积压 / 消费跟不上怎么办

面试官内心 OS

"真实生产经验题。没处理过会答得很表面,处理过会有方法论。"

评分档

分档听到什么
60 分"扩 Consumer 数 + 加 Partition"
80 分+ 区分"消费慢"还是"拉得慢"(records-lag-max + fetch-latency)+ 业务侧异步线程池 + max.poll.records 调小
95 分+ 临时止血 vs 长期根治两步走 + 真实事故 STAR + 监控加强

面试官追问树


追问 1:Consumer 数和 Partition 数的关系?

   答 "Consumer 数 ≤ Partition 数,多余的 Consumer 闲置" → 80 分

   答 "+ 如果 Consumer 横向扩不上去,说明分区数不够,要重新设计 Topic" → 90 分

   ↓

追问 2:为什么不能简单调大 max.poll.interval.ms?

   答 "处理慢的消息会挂着不退,影响整组" → 80 分

   答 "+ 正确做法是异步线程池 + 心跳和处理解耦" → 95 分

   ↓

追问 3:临时积压消化完后,怎么避免下次再发生?

   答 "加监控" → 60 分

   答 "+ 容量预估 + 压测 + 业务侧异步化" → 90 分

   答 "+ 沉淀内部规范《Consumer 处理慢消息 5 种姿势》" → 95 分

   ↓

追问 4:扩了 Consumer 还是慢,怎么办?

   答 "加 Partition" → 错(Partition 不能减,扩 Partition 是单向操作)

   答 "先看处理瓶颈在哪:DB?下游 RPC?算力?" → 90 分

踩坑信号

❌ 第一反应"加 Consumer" → 减分(说明没思考瓶颈在哪)

❌ "Partition 越多越好" → 错(Partition 多 → 元数据 / fd 压力 / Rebalance 慢)

❌ 不区分"消费慢"和"拉得慢"

高分加分项

✅ 给积压消化时间公式:积压量 / (新增速率 - 消费速率)

✅ 提 Burrow 监控 + Cruise Control 自动扩缩

✅ 量化结果:"积压消化时间 1h+ → 30min"

💎 95 分口述范文

消息积压我用止血 → 根因 → 根治 → 预防四步法。

第一步止血(5 分钟内):先看 records-lag-max 确认积压量级和增速。区分"消费慢"还是"拉得慢"——fetch-latency 高说明 broker 端有瓶颈(磁盘 IO / 网络),records-consumed-rate 正常但 lag 涨说明是生产端突发流量。

第二步根因:如果是消费慢,max.poll.records 临时调小(比如 500→50),避免单次 poll 拉太多导致处理超时触发 Rebalance(又加重积压)。然后查业务瓶颈:DB 慢查询?下游 RPC 超时?GC 停顿?——80% 的积压根因不在 Kafka 本身。

第三步根治:①如果瓶颈是单条处理慢——上异步线程池,poll 线程只负责拉取放内存队列,Worker 线程池并行消费,手动 commit offset(处理完最小 offset 才提交);②如果瓶颈是 Consumer 数不够——先看 Consumer 数是否 = Partition 数,如果已经打满,需要扩 Partition(注意:Partition 只能加不能减,扩之前评估 Key 分布是否会打破顺序性);③如果是突发流量——上游加 Rate Limiter / 客户端 buffer 削峰。

第四步预防:①积压消化时间公式 积压量 / (消费速率 - 生产速率),负数说明永远追不上,必须扩容;②用 Burrow 监控 Consumer Lag 趋势(比瞬时值更有价值),告警阈值按业务 SLA 设(支付类 Lag > 1000 告警);③季度压测,验证消费能力是否跟得上 2x 峰值流量;④沉淀团队规范:消费端必须异步化、必须手动 commit、单条处理超时 > 1s 必须优化。

我们线上一次积压事故:双十一活动流量 3x,Consumer 处理 DB 写入成为瓶颈。止血阶段临时批量 insert 替代逐条 insert(吞吐提升 8x),积压消化时间从 1h+ 降到 30min。根治阶段上了异步线程池 + DB 分库。


📊 题型 8:设计百万 QPS 消息系统

面试官内心 OS

"P8 系统设计题。看你有没有架构师思维 —— 不只是堆机器,还要分层 + 容灾 + 成本。"

评分档

分档听到什么
60 分算出 partition 数(按吞吐 / 单分区上限)+ 副本 3 + acks=all
80 分+ 容量预估公式 + 跨机架部署 + 监控告警 + 容灾方案 + Producer/Consumer 调优
95 分+ 分层设计(接入层 / 路由层 / 存储层)+ Tiered Storage 成本优化 + 故障演练 + 平台化(多租户 / 自助 / 治理)

面试官追问树


追问 1:100w QPS,单条 1KB,需要多少 broker?

   答 "凭感觉" → 减分

   答 "1GB/s 网络 → 单 broker 25Gbps × 0.6 利用率 ≈ 1.875GB/s 出 → 算上副本 3x = 5.6GB/s → 6 broker 起步 + 余量 2x = 12 broker" → 90 分

   ↓

追问 2:Partition 数怎么定?

   答 "100w / 5w(单分区上限) = 20" → 80 分

   答 "+ 考虑 Consumer 横向扩展空间,至少 20 × 2 = 40,建议 60~100" → 95 分

   ↓

追问 3:怎么应对突发流量 5x?

   答 "提前扩容 + Quota 限流" → 80 分

   答 "+ 削峰:客户端 buffer + 服务端 backpressure + 关键 Topic 优先级" → 95 分

   ↓

追问 4:成本怎么优化?

   答 "压缩 + 副本数差异化" → 80 分

   答 "+ Tiered Storage 冷数据下沉 S3" → 90 分

   答 "+ Follower Fetch 跨 AZ 优化 + 业务收敛" → 95 分

踩坑信号

❌ 不算数 / 凭感觉给数字 → 直接 60 分以下

❌ 不提容灾(机房挂了怎么办) → 减 10 分

❌ 不提监控 / 告警 / 故障演练 → 减 10 分

❌ "全部用 acks=all" → 没有差异化思维(日志类用 acks=1 节省 30% 资源)

高分加分项

✅ 主动画分层架构图(接入 → 路由 → 存储 → 监控)

✅ 提 KRaft 元数据层瓶颈(4000~5000 partition / broker 上限)

✅ 提平台化路径:自助 Topic 申请 + 容量自动评估 + 自愈

💎 95 分口述范文

百万 QPS 消息系统设计我按需求拆解 → 容量计算 → 架构分层 → 容灾 → 成本优化五步讲。

需求拆解:100w QPS,单条 1KB,即 1GB/s 写入。峰值按 3x 预留 = 3GB/s。保留 7 天,总存储 = 3GB/s × 86400 × 7 × 3(副本)≈ 5.4PB。

容量计算:单 broker 万兆网卡 10Gbps ≈ 1.25GB/s,利用率 60% → 有效 750MB/s。写入 1GB/s × 3 副本 = 3GB/s 总写入 → 至少 4 broker。但读(Consumer + Follower fetch)也走网络,按写 : 读 = 1 : 2 → 网络总量 9GB/s → 12 broker。预留 2x 余量 → 24 broker。Partition 数:单分区吞吐上限约 5w QPS → 100w / 5w = 20,但考虑 Consumer 扩展空间和热点 Key 打散,设 60~100 partition。单 broker 4000~5000 partition 上限(KRaft 元数据瓶颈),24 broker × 4000 = 9.6w,远够。

架构分层:①接入层——Proxy / Gateway 做认证鉴权、协议转换、流量染色;②路由层——按业务 Topic 分集群(支付核心 / 日志分析 / 数据同步),避免混部互相影响;③存储层——Kafka Broker + Tiered Storage(冷数据 7 天后下沉 S3,热数据留 SSD);④监控层——Prometheus + Grafana + Burrow,核心指标 Under-replicated Partitions / ISR shrink rate / Consumer Lag。

容灾:跨 AZ 部署 broker.rack 配置,min.insync.replicas=2 + acks=all。日志类 Topic 用 acks=1(吞吐优先,丢一点可接受,节省 30% 资源)。每季度 Chaos Engineering 演练(随机 kill broker、模拟 AZ 故障)。MirrorMaker 2 跨 Region 备份核心 Topic。

成本优化:①Tiered Storage 冷热分离省 60% 存储成本;②Follower Fetch(KIP-392)让 Consumer 就近读同 AZ 副本,减少跨 AZ 流量费;③压缩算法用 LZ4(CPU 低 + 压缩率适中);④多租户 Quota 隔离,防单个业务打满集群。平台化:自助 Topic 申请 → 自动容量评估(根据预估 QPS 算 Partition 数和保留时间)→ 异常自愈(Cruise Control 自动 Rebalance 热点 broker)。


📊 题型 9:顺序消费怎么保证

面试官内心 OS

"极高频基础题。看你能不能分清全局有序 vs 分区有序,以及实际业务中怎么落地。"

评分档

分档听到什么
60 分"同一个 Key 发到同一个 Partition,单 Partition 内有序"
80 分+ 自定义 Partitioner 处理 Key 热点 + max.in.flight.requests.per.connection=1(非幂等模式)或 ≤5(幂等模式)+ Consumer 单线程消费
95 分+ 多线程消费时用内存队列按 Key 分桶保序 + Rebalance 导致重复消费打破语义顺序的应对 + 业务层状态机兜底

面试官追问树


追问 1:Kafka 有没有全局有序?

   答 "有,单分区 Topic" → 80 分

   答 "+ 但单分区吞吐有上限,实际不用;业务上用 Key 分区 + 分区内有序就够" → 90 分

   ↓

追问 2:max.in.flight > 1 会乱序吗?

   答 "会,重试时第二个 batch 先到" → 80 分

   答 "+ 开幂等后 ≤ 5 不会乱序(broker 按 sequence 排序)" → 95 分

   ↓

追问 3:Consumer 多线程怎么保序?

   答 "不能多线程" → 60 分

   答 "按 Key hash 到不同的内存队列,每个队列单线程消费" → 90 分

   答 "+ 队列满时背压 poll 线程 + 业务层用版本号/状态机做最终兜底" → 95 分

   ↓

追问 4:Rebalance 后怎么保证不乱序?

   答不出 → 减分

   答 "Rebalance 可能导致重复消费 → 业务幂等 + 状态机(只允许状态正向流转)→ 即使重复消费也不影响业务语义" → 95 分

踩坑信号

❌ "Kafka 保证全局有序" → 错,只保证分区内有序

❌ 不知道 max.in.flight 对顺序的影响

❌ "Consumer 多线程不影响顺序" → 严重错误

❌ 把"分区有序"等于"业务有序" → 忽略了 Rebalance / 重试 / 多 Consumer 场景

高分加分项

✅ 主动提"订单状态机:CREATED → PAID → SHIPPED,任何逆向转换直接拒绝"

✅ 提 Key 热点问题(大卖家所有订单挤在一个 Partition)→ 二级 Key(sellerId + orderId % N)

✅ 提 Kafka Streams 的内部 repartition 也要保序

💎 95 分口述范文

顺序消费分分区级有序业务级有序两层。

分区级有序:Kafka 只保证单 Partition 内消息有序。Producer 端用相同 Key 发送(比如 orderId),默认 DefaultPartitioner 对 Key 做 murmur2 hash % partitionCount,保证同 Key 同 Partition。但有个坑:非幂等模式下 max.in.flight.requests.per.connection > 1 时,batch-1 失败重试,batch-2 先到 → 乱序。解决:幂等模式下 ≤ 5 不会乱序(broker 按 Sequence 排序重排),非幂等模式只能设 1。

Consumer 端保序:最简单是单线程消费,但吞吐低。多线程方案:poll 线程拉取后按 Key.hashCode() % workerCount 分发到 N 个内存队列,每个队列绑定一个 Worker 线程串行消费。队列满时背压 poll 线程(阻塞 poll 调用),避免 OOM。手动 commit 时只提交已完成最小 offset。

Rebalance 后的乱序/重复:分区重分配后新 Consumer 从 last committed offset 开始消费,已处理但未提交的消息会重复消费。业务层必须有状态机兜底——例如订单状态只允许 CREATED→PAID→SHIPPED 正向流转,重复的 PAID 事件直接幂等忽略,逆向事件直接拒绝。这样即使 Kafka 层面出现重复或乱序,业务语义仍然正确。

Key 热点:大卖家所有订单挤在一个 Partition 导致倾斜。方案是二级 Key:sellerId + "_" + orderId % 8,把同一卖家的订单打散到 8 个 Partition。代价是同一卖家的订单不再全局有序,但单笔订单(orderId 相同)仍然有序,多数业务场景够用。


📊 题型 10:Kafka 为什么快

面试官内心 OS

"基础高频题,字节/美团必问。看你能不能讲清楚 4 个核心优化,而不只是嘴上说'零拷贝'。"

评分档

分档听到什么
60 分"顺序写磁盘 + 零拷贝(sendfile)"
80 分+ PageCache 读写分离 + 批量压缩(RecordBatch)+ 分区并行 + mmap 索引
95 分+ sendfile 在 SSL/加密下退化为用户态拷贝 + PageCache 预读与 read-ahead 调优 + Reactor 线程模型(Acceptor + Processor + RequestHandler 分离)

面试官追问树


追问 1:零拷贝具体怎么工作?

   答 "sendfile 系统调用" → 60 分

   答 "+ 数据从 PageCache 直接 DMA 到网卡,不经过用户态 → 减少 2 次拷贝 + 2 次上下文切换" → 80 分

   答 "+ 前提:非 SSL 连接。SSL 下数据必须到用户态做加解密,sendfile 失效 → 回退到 transferTo + 用户态 buffer" → 95 分

   ↓

追问 1.5:SSL 下零拷贝失效,Java 客户端怎么配置缓解?

   答不出 → 减分

   答 "内网用 `security.protocol=PLAINTEXT` 或 `SASL_PLAINTEXT`,不走 SSL" → 80 分

   答 "+ Broker 配双 listener:`listeners=PLAINTEXT://:9092,SSL://:9093`,内网客户端连 9092(零拷贝生效),公网/跨域客户端连 9093(SSL);Broker 间复制用 `inter.broker.listener.name=PLAINTEXT` 也走明文" → 95 分

   ↓

追问 2:PageCache 和直接写磁盘有什么区别?

   答 "PageCache 在内存里,写入快" → 60 分

   答 "+ Kafka 不自己管缓存(不像 RocketMQ 有 MappedByteBuffer 池),完全交给 OS → 好处是 JVM GC 不受影响 + 重启后缓存还在" → 90 分

   ↓

追问 3:批量压缩怎么节省带宽?

   答 "Producer 端压缩,Broker 原样存储,Consumer 端解压" → 80 分

   答 "+ 压缩是按 RecordBatch 整批压缩(不是单条),压缩率更高 + Broker 端不需要解压(除了 log compaction / 格式检查)" → 95 分

   ↓

追问 4:Kafka 的线程模型是什么?

   答不出 → 减分

   答 "1 Acceptor + N Processor(网络线程)+ M RequestHandler(IO 线程)+ Purgatory 延迟操作队列" → 90 分

   答 "+ Processor 只负责读写 Socket、解析请求放 RequestQueue;RequestHandler 做真正的磁盘 IO → 网络和 IO 解耦" → 95 分

踩坑信号

❌ "Kafka 用了 mmap 所以快" → 不精确,mmap 只用于索引文件(.index / .timeindex),数据文件用 FileChannel

❌ "零拷贝 = DMA" → 不完整,DMA 只是零拷贝的一环

❌ 不知道 SSL 下零拷贝失效

❌ "顺序写比随机写快 100 倍" → 数字来源不明,应该说"顺序写接近内存速度,SSD 上 500MB/s+,随机写 < 1MB/s"

高分加分项

✅ 主动对比 RocketMQ 的 MappedByteBuffer 池 vs Kafka 的 OS PageCache 策略

✅ 提 SSL 下零拷贝失效的三种缓解方案(TLS 卸载 / kTLS / 网络分区隔离)

✅ 提 log.flush.interval.messages / log.flush.interval.ms 不建议配(默认交给 OS 刷盘更高效)

✅ 提 vm.dirty_ratio / vm.dirty_background_ratio 的 OS 层调优

💎 95 分口述范文

Kafka 高吞吐的核心是 4 个机制 + 1 个线程模型

①顺序写:Producer 消息 append-only 追加到 segment 文件尾部,磁盘顺序写接近内存速度(SSD 上 500MB/s+,HDD 也能 100MB/s+)。不做随机写、不做就地更新。

②OS PageCache:Kafka 不自己管内存缓存,完全依赖 OS PageCache。写入时数据进 PageCache → OS 异步刷盘。读取时如果 PageCache 命中就直接返回,不走磁盘。好处:JVM Heap 不膨胀 → GC 压力小;Broker 重启后 PageCache 还在(热数据不丢)。不建议配 log.flush.interval.messages(让 OS 自己决定刷盘时机更高效),数据安全靠多副本保证。OS 层调优:vm.dirty_background_ratio=5 + vm.dirty_ratio=80 + read-ahead 设 128KB。

③零拷贝(sendfile):Consumer 拉取时,数据从 PageCache → 网卡,跳过用户态。标准路径 4 次拷贝 + 4 次上下文切换,sendfile 减至 2 次拷贝 + 2 次切换。但 SSL 连接下失效——数据必须到用户态做 TLS 加解密,回退为普通 transferTo,吞吐下降 30~50%。

Java 客户端怎么控制? Kafka 不走 HTTP/HTTPS,走自有二进制协议,安全层由 security.protocol 控制:

security.protocol加密认证零拷贝场景
PLAINTEXT内网无安全要求
SSL✅ TLS✅ 证书公网/跨域
SASL_PLAINTEXT✅ SASL内网推荐:认证不加密
SASL_SSL✅ TLS✅ SASL公网+强认证

最佳实践——Broker 双 listener

# server.properties
listeners=SASL_PLAINTEXT://:9092,SASL_SSL://:9093
inter.broker.listener.name=SASL_PLAINTEXT

内网 Java 客户端配 security.protocol=SASL_PLAINTEXT 连 9092,零拷贝生效 + SASL 认证不裸奔;公网客户端连 9093 走 SASL_SSL。如果合规要求内网也加密:①Envoy/HAProxy 做 TLS 终结,Broker 仍 PLAINTEXT;②kTLS(Linux 4.13+,JDK 19+ 配 jdk.tls.client.enableKernelTLS=true)内核态 TLS,恢复 80%+ 零拷贝吞吐;③网络分区隔离——Broker 间复制和 Consumer 拉取走内网专线(不加密),只有跨公网的 MirrorMaker / 客户端走 SSL,把 SSL 影响范围缩到最小。

④批量 + 压缩:Producer 端消息按 RecordBatch 批量发送,整批做 LZ4/Snappy/ZStd 压缩。Broker 原样存储压缩后的 batch(不解压),Consumer 端整批拉取再解压。压缩粒度是 batch 而不是单条,相似消息压在一起压缩率更高(通常 4~8x)。Broker 唯一需要解压的场景:Log Compaction 和消息格式版本不一致时的 up-conversion。

⑤Reactor 线程模型:1 个 Acceptor 线程接受连接 → 轮询分配给 N 个 Processor 线程(num.network.threads,默认 3)→ Processor 读 Socket、解析请求、放入 RequestQueue → M 个 RequestHandler 线程(num.io.threads,默认 8)从队列取请求做磁盘 IO → 响应放回 Processor 的 ResponseQueue → Processor 写回 Socket。网络 IO 和磁盘 IO 完全解耦。额外还有 Purgatory(炼狱)组件处理延迟操作(如 acks=all 等待副本同步)。


📊 题型 11:Kafka vs RocketMQ vs Pulsar 选型

面试官内心 OS

"架构师视野题。不是要你背参数对比表,而是看你能不能根据业务场景选出合适的 MQ,并说清楚为什么。"

评分档

分档听到什么
60 分能列出三者的基本差异(Kafka 吞吐高 / RocketMQ 功能丰富 / Pulsar 存算分离)
80 分+ 按场景选型(日志/大数据用 Kafka、交易/金融用 RocketMQ、多租户/云原生用 Pulsar)+ 各自的核心短板
95 分+ 深入架构差异(CommitLog vs Segment / Broker vs BookKeeper)+ 延迟消息 / 事务消息 / 死信队列的实现差异 + 真实选型决策 STAR

面试官追问树


追问 1:Kafka 和 RocketMQ 存储架构有什么本质区别?

   答 "都是写日志" → 60 分

   答 "Kafka 每个 Partition 独立 Segment 文件 → 多 Partition 时变随机写;RocketMQ 所有 Topic 共用一个 CommitLog → 始终顺序写 + ConsumeQueue 做索引" → 90 分

   ↓

追问 2:RocketMQ 哪些功能 Kafka 没有?

   答 "延迟消息" → 70 分

   答 "+ 延迟消息(18 个级别)+ 死信队列 + 消息过滤(Tag / SQL92)+ 事务消息(half message + 回查)" → 90 分

   答 "+ Kafka 要实现延迟消息只能用时间轮 + 内部 Topic 重投递,复杂度高" → 95 分

   ↓

追问 3:Pulsar 的存算分离有什么优势和代价?

   答 "Broker 无状态,扩容快" → 80 分

   答 "+ 存储层 BookKeeper 独立扩展,Broker 故障不丢数据。代价:多一跳网络延迟、运维复杂度更高(要同时管 Broker + BookKeeper + ZK)、社区生态不如 Kafka" → 95 分

   ↓

追问 4:你们公司为什么选了 XX?

   答 "大家都用" → 减分

   答 具体业务场景 + 技术选型矩阵 + 迁移成本考量 → 90 分

踩坑信号

❌ "Kafka 最好" → 没有最好,只有合适

❌ 不知道 RocketMQ 的 CommitLog 架构

❌ "Pulsar 完胜 Kafka" → 忽略了运维成本和生态

❌ 把三者的事务实现混为一谈(Kafka 2PC vs RocketMQ half-message 回查机制完全不同)

高分加分项

✅ 主动画对比矩阵表(吞吐 / 延迟 / 功能 / 运维 / 生态)

✅ 提 Kafka 的 KIP-405 Tiered Storage 正在补存算分离短板

✅ 提 RocketMQ 5.0 grpc 协议 + proxy 模式也在走云原生路线

💎 95 分口述范文

选型我从架构差异 → 功能差异 → 场景匹配 → 真实决策四层讲。

架构差异:Kafka 每个 Partition 一组 Segment 文件,多 Topic/多 Partition 时并发写多个文件,Partition 过多时退化为随机写。RocketMQ 所有 Topic 共享一个 CommitLog,始终顺序写,消费靠 ConsumeQueue 索引文件 → 写入性能稳定但消费时多一次寻址。Pulsar 存算分离:Broker 无状态只做计算,存储层是 Apache BookKeeper(每个 Ledger 分片到多个 Bookie),Broker 挂了换一个即可,零数据迁移。

功能差异:①延迟消息——RocketMQ 原生支持 18 个延迟级别(开源版)/ 任意时间(商业版),Kafka 不支持(需自建时间轮 + 重投递 Topic),Pulsar 原生支持任意延迟;②事务消息——Kafka 用 2PC(Transaction Coordinator),RocketMQ 用 half-message + Broker 主动回查(更适合分布式事务场景),Pulsar 也支持但生态较弱;③死信队列——RocketMQ 原生支持(重试 16 次后进 %DLQ%),Kafka 需自建(消费失败 → 发到 DLQ Topic);④消息过滤——RocketMQ 支持 Tag/SQL92 表达式在 Broker 端过滤,Kafka 只能 Consumer 端自己过滤。

场景匹配:日志采集/大数据实时计算 → Kafka(生态最强,Flink/Spark/HDFS 全链路打通);交易/金融/电商 → RocketMQ(功能丰富、延迟消息/事务消息开箱即用、国内社区活跃);多租户 SaaS / 云原生 → Pulsar(存算分离天然支持弹性扩缩、多租户隔离好)。

真实决策(STAR):我们支付系统选 Kafka,原因:①团队技术栈已有 Kafka 积累,迁移成本低;②支付场景对延迟消息需求不强(用 DB 调度任务替代);③大数据团队用 Kafka 做实时数仓,统一技术栈降低运维成本。但事务消息场景我们没用 Kafka Transaction,而是自建 Outbox + 定时任务投递,比 Kafka/RocketMQ 的事务消息都更可控。


🎯 通用评分逻辑(所有题适用)

1. 三档逻辑


60 分(基础线):能说出标准答案

                 通常是教科书 / 网上博客的那一套

                 简单题 = 60 分及格;高难度题 = 60 分淘汰

80 分(合格线):能拆解 + 给细节

                 知道每个参数的代价 / 默认值 / corner case

                 80 分 = 资深工程师正常水平

95 分(亮眼):有自己的判断 + 真实事故 + 量化结果

              能从架构 / 平台 / 业务 三个维度展开

              95 分 = P8 / Staff 候选人

2. 减分项汇总(任何题都适用)

凭感觉给数字:减 10 分

错把默认值当最佳实践:减 5 分

不能给 corner case:减 10 分

回避追问:"这个我不太清楚"是诚实,"这个不重要"是减分

复述网上答案:被追问立刻露馅

答非所问:减 15 分

抢答 / 不听完问题:减 10 分

3. 加分项汇总

主动暴露陷阱:"这里有个坑..." 比被追问出来强 10 倍

量化结果:所有数字(时间 / 比例 / 成本)都有具体值

真实事故 STAR:S-T-A-R-M-P 模板讲故事

承认不会:不会就说不会,不要硬编

结构化表达:先讲框架 → 再展开细节

类比简化:能用一句类比让初级工程师听懂


🏆 候选人自检 Checklist

面试前,对着 11 个题型自问:

  • 题型 1 消息丢失:你能讲到 80 分吗?(三段路径 + 真实事故)
  • 题型 2 Rebalance:你能讲到 80 分吗?(Cooperative + Static + 异步线程池)
  • 题型 3 acks=all 陷阱:你能识别陷阱吗?(min.insync.replicas / unclean.leader.election)
  • 题型 4 ISR 设计:你能对比 ISR vs Raft 吗?
  • 题型 5 EOS:你能讲清 Kafka 事务 vs Flink 端到端的区别吗?
  • 题型 6 Producer 幂等:你能说出 PID / Seq / 5 batch 吗?
  • 题型 7 积压:你能给"消化时间公式"吗?
  • 题型 8 设计 100w QPS:你能现场算 broker 数 / partition 数吗?
  • 题型 9 顺序消费:你能讲清分区有序 vs 业务有序 + 多线程保序方案吗?
  • 题型 10 为什么快:你能讲清 4 个机制 + SSL 下零拷贝失效吗?
  • 题型 11 MQ 选型:你能按场景选型并说清架构差异吗?

11 个题型至少 8 个能讲到 80 分 → 资深工程师水准。

11 个题型至少 4 个能讲到 95 分 → P8 / Staff 候选人。