Appearance
Java-分布式与中间件
大类:架构与分布式 · 共 20 题 · 检索页定位
选择题(7)
q130 · 中等
为了尽量保证 Kafka 消息不丢失,下列配置与做法的组合正确的是?
A. 生产端 acks=0 提高吞吐,Broker 端单副本部署,消费端先提交 offset 再处理消息
B. 生产端 acks=all 并开启重试与幂等,Broker 端多副本且设置 min.insync.replicas,消费端处理成功后再提交 offset
C. 生产端同步发送即可,Broker 端 min.insync.replicas 等于副本总数,消费端开启自动提交 offset
D. 只要 Broker 开启了持久化,生产端和消费端都无需任何额外配置
参考答案要点
- 生产端:acks=all + 失败重试 + 幂等生产者;更高可靠用本地消息表/Outbox 保证"业务落库+发消息"原子性
- Broker 端:多副本 + min.insync.replicas + 合理刷盘策略,依赖 ISR 机制
- 消费端:处理成功后再提交 offset/ACK,失败消息进重试或死信队列
- acks/副本数/同步刷盘都会降低吞吐:可靠性与性能的 trade-off
- unclean.leader.election.enable 的风险权衡
来源:[interview.javaguide.cn](https://interview.javaguide.cn/high-performance/message-queue-interview-questions.html)
q131 · 中等
Kafka 之所以能做到极高的吞吐量,与下列哪项机制的关系最小?
A. 顺序写磁盘并充分利用操作系统 Page Cache
B. 使用零拷贝(sendfile)技术传输数据
C. 分区并行 + 批量发送与压缩、批量拉取
D. 每条消息被消费后立即同步刷盘落盘
参考答案要点
- 顺序写 + Page Cache 是 Kafka 磁盘读写高性能的核心
- 零拷贝减少内核态与用户态之间的数据拷贝
- 分区并行、批量发送压缩、批量拉取、消费组并行消费
- 逐条同步刷盘会显著降低吞吐,与高吞吐目标相反;可靠性主要靠多副本而非逐条刷盘
- 消费端拉取(pull)模式便于批量消费与流控
来源:[interview.javaguide.cn](https://interview.javaguide.cn/high-performance/message-queue-interview-questions.html)
q473 · 中等
Kafka 某主题有 4 个分区,消费组 A 启动了 6 个消费者实例订阅它。下列说法正确的是?
A. 6 个消费者平均分摊数据,每个消费者拿到约 4/6 个分区的消息
B. Kafka 会把每个分区的数据复制给多个消费者以提高消费吞吐
C. 消费者数量超过分区数量时会抛异常,消费组无法正常启动
D. 分区是消费组内并行消费的基本单位:组内每个分区只会分配给一个消费者,4 个分区最多让 4 个消费者有活干,多出的 2 个空闲;要提升并行度只能增加分区数——而「全量数据复制」发生在不同消费组之间(组间广播、组内单播)
参考答案要点
- 正确答案 D. 消费组内分区数决定最大并行度;消费者多于分区时多余实例闲置,组间才各自拿到全量数据
- A 分区只能整体分配给组内某个消费者,不能按 4/6 拆分
- B 组内一分区一消费者是 offset 语义与分区内顺序的基础,组内不做复制
- C 只是闲置不报错,这也是扩容消费端前要先评估分区数的原因
来源:[kafka.apache.org](https://kafka.apache.org/documentation/#intro_consumers)
q474 · 中等
关于 RocketMQ 4.x 的延迟消息(delayTimeLevel),下列说法正确的是?
A. 只能从 18 个固定级别中选择(1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h);实现是 broker 先把消息暂存到内部延迟 Topic 的对应级别队列,定时服务到期后投回目标 Topic;任意精度的定时消息要靠 5.x 的 Timer 机制
B. 可以指定任意延迟时长,精确到毫秒
C. 延迟消息缓存在消费端,由消费者的本地定时器到期后触发消费
D. 延迟级别是写死在源码里的常量,不能通过 broker 配置调整
参考答案要点
- 正确答案 A. 4.x 开源版默认 messageDelayLevel 共 18 级,SCHEDULE_TOPIC_XXXX 按 level 分队列,到期由定时任务重新投递
- B 任意毫秒级定时是 RocketMQ 5.x(时间轮+TimerLog)的能力;C 延迟由 broker 侧管理,与消费者无关
- D 级别可通过 broker 配置 messageDelayLevel 自定义后重启生效
来源:[rocketmq.apache.org](https://rocketmq.apache.org/zh/docs/4.x/producer/04message3/)
q475 · 中等
RabbitMQ 要做到端到端消息不丢,生产端、Broker、消费端各自需要做什么?正确组合是?
A. 生产端开启 confirm 确认;Broker 侧声明持久化队列并用持久化投递模式(delivery mode 2);消费端关闭自动确认,处理成功后手动 basicAck
B. 生产端用事务保证,broker 默认自动落盘,消费端 autoAck=true 提高吞吐且更安全
C. 生产端无需任何确认机制,只要消费端手动 ack 消息就绝不会丢
D. 三端任选其一做到即可,例如只开生产端 confirm 就万无一失
参考答案要点
- 正确答案 A. 三段链路各守一段:confirm 保证消息已被 broker 接受(持久消息需落盘后才回 ack);durable 队列+持久消息保证 broker 重启后仍在;手动 ack 保证消费端处理完成前 broker 不删消息
- B 事务相比 confirm 吞吐约降 250 倍;autoAck=true 在处理完成前就算确认,消费端崩溃消息即丢,官方明确视为 unsafe
- C/D 每一端只覆盖自己那段:生产端不 confirm 则 broker 落盘前宕机就丢且无感知;缺手动 ack 则消费段会丢
来源:[rabbitmq.com](https://www.rabbitmq.com/docs/confirms)
q476 · 中等
关于 Dubbo 的集群容错模式,下列说法正确的是?
A. failfast 是默认模式,失败后自动重试 2 次
B. failover 模式重试次数不设上限,直到调用成功为止
C. failover 是默认模式:失败自动切换到其他提供者重试,默认 retries=2(不含首次,合计最多调用 3 次),适合读或幂等写;非幂等写操作应改用 failfast(只调用一次,失败立即报错)等模式
D. failback 指失败后立即抛出异常,由调用方人工介入恢复
参考答案要点
- 正确答案 C. 官方文档:默认 cluster=failover、retries=2;failover 会自动换节点重试,用于更新等非幂等操作有重复执行风险
- A 默认是 failover,failfast 快速失败不重试;B 重试次数可配置且有默认值 2
- D failback 是失败自动记录、后台定时重发(失败自动恢复)
来源:[dubbo.apache.org](https://dubbo.apache.org/zh-cn/docs/advanced/fault-tolerent-strategy/)
q477 · 困难
Seata AT 模式的一阶段做了什么?与传统 XA「两阶段持锁」的关键差异是?
A. 一阶段只记录 undo_log 不执行业务 SQL,业务 SQL 延迟到二阶段执行
B. 一阶段提交后本地锁一直持有到全局事务结束,与 XA 完全相同
C. AT 模式回滚靠重放正向 SQL 补偿
D. 一阶段在同一个本地事务中提交业务 SQL 与前后镜像 undo_log,随后即释放本地锁与连接;二阶段全局提交只需异步删除 undo_log,全局回滚则用 undo_log 反向补偿(生成反向 SQL 恢复前镜像)——锁持有时间远短于 XA
参考答案要点
- 正确答案 D. AT 的核心:一阶段本地事务直接提交并释放锁,回滚能力由 undo_log 的前后镜像保证,这是它与 XA 最大的性能差异点
- A 业务 SQL 在一阶段就真实执行并提交;B AT 一阶段完成即释放本地锁(回滚时再重新获取),不是持有到全局结束
- C 回滚基于 before image 生成反向 SQL,不是重放正向 SQL
来源:[seata.apache.org](https://seata.apache.org/zh-cn/docs/user/mode/at/)
简答题(9)
q029 · 简单
分布式锁有哪几种常见实现(Redis、ZooKeeper、数据库)?对比它们的优缺点,以及 Redis 锁要处理好的几个经典问题。
参考答案要点
- 数据库:唯一约束/for update,简单但性能差、无超时自动释放的优雅方案
- Redis(setnx+过期):高性能、实现简单;问题:误删他人锁(需唯一值+Lua校验)、锁过期业务未完(看门狗续期)、主从切换丢锁(RedLock争议)
- ZK:临时顺序节点+watch,可靠性强一致性;性能低于Redis、运维复杂
- 选型:绝大多数场景Redis+Redission(看门狗)够用;强一致要求才ZK
- 能提Martin Kleppmann与Antirez的RedLock之争是强加分
来源:seed
q030 · 中等
消息队列怎么保证消息不丢?从生产、存储、消费三个环节分别说。又怎么处理消息重复和顺序问题?
参考答案要点
- 生产端:confirm机制(同步/异步确认)+失败重试+本地消息表兜底
- 存储:刷盘策略(同步刷盘vs异步)、集群多副本(Raft/主从同步复制)、Kafka的acks=all与min.insync.replicas
- 消费:手动ack、消费失败重试+死信队列、幂等消费(唯一键/状态机/去重表)
- 重复必然存在(at-least-once),方案靠消费端幂等不是消灭重复
- 顺序:同key路由同分区/队列,单线程或内存队列保证分区内有序
- 能讲「不丢和exactly-once的代价trade-off」而不是背配置
来源:seed
q132 · 中等
消息队列为什么会重复消费?消费端应如何设计幂等?
参考答案要点
- 重复来源:消费处理后未及 ACK 即宕机、ACK 丢失、消费超时或重平衡导致分区重分配、生产者重试但上一次实际已成功
- 投递语义:At Least Once 最常用,重复不可避免,幂等是消费端的责任
- 幂等手段:业务唯一键去重表、数据库唯一索引、状态机校验、Redis 短期去重(带过期时间)
- 不要只依赖 MQ 消息 ID 去重,应使用业务唯一键(如订单号+事件类型)
- 幂等记录应含 PROCESSING/SUCCESS/FAILED 状态与过期时间,处理"一直处理中"的超时接管
来源:[interview.javaguide.cn](https://interview.javaguide.cn/high-performance/message-queue-interview-questions.html)
q327 · 中等
Redis 的 RDB 与 AOF 持久化各自原理与优缺点是什么?生产上如何选择与配置?
参考答案要点
- RDB:定时快照,fork 子进程 + 写时复制(COW);文件紧凑恢复快,但快照间隔内宕机丢数据多,fork 大内存实例有停顿风险
- AOF:追加写命令日志,appendfsync everysec 折中(最多丢约 1 秒);文件大需要重写(bgrewriteaof 同样要 fork);新版为 Multi-Part AOF
- 混合持久化(4.0+):RDB 全量做头 + AOF 增量追加,恢复快且丢失少,生产推荐开启
- trade-off:性能与数据安全的取舍;纯缓存可容忍丢失的场景可关持久化或仅 RDB
- 注意:主从 + 哨兵/集群的高可用不能替代持久化——机器全部重启后没有持久化数据就回不来
来源:[javaguide.cn](https://javaguide.cn/high-performance/high-performance-interview-questions.html)
q328 · 中等
Redis 的主从复制、哨兵、Cluster 三种模式分别解决什么问题?如何选型?
参考答案要点
- 主从复制:数据热备 + 读写分离,解决读扩展;故障切换需人工,主库写能力与容量仍受单机限制
- 哨兵:监控 + 自动故障转移(quorum 选主),解决高可用;容量与写吞吐仍不能水平扩展
- Cluster:16384 slot 分片 + gossip 去中心化,数据与读写双向水平扩展,自带主从与故障转移;多 key 操作与事务受限(可用 hash tag),客户端须支持集群协议
- 选型:容量小于单机内存且要高可用选哨兵;数据量或写入超单机选 Cluster;读多写少主从 + 读副本即可
- 注意:主从异步复制存在丢数据窗口;Cluster resharding 与 gossip 通信对极小集群是额外负担
来源:[javaguide.cn](https://javaguide.cn/high-performance/high-performance-interview-questions.html)
q329 · 中等
Kafka、RocketMQ、RabbitMQ 如何选型?从吞吐、延迟、功能特性与典型场景分别说明。
参考答案要点
- Kafka:百万级吞吐,分区并行 + 顺序写 + 零拷贝,流生态强(Flink/日志采集);延迟消息与重试队列能力弱,适合日志管道、大数据事件流
- RocketMQ:十万级吞吐、毫秒低延迟,业务特性全:事务消息、定时消息、重试/死信队列、消息轨迹,国内电商交易链路主流
- RabbitMQ:万级吞吐、延迟低,exchange 路由灵活、管理界面友好;Erlang 运维门槛高,适合中小规模业务与复杂路由场景
- 选型三问:吞吐量级要求?是否需要事务/延迟/重试特性?团队运维能力与生态匹配度?
- trade-off:吞吐与功能丰富度往往反向;Pulsar(存算分离、多租户、地域复制)是新选项但运维复杂
来源:[github.com](https://github.com/doocs/advanced-java)
q330 · 困难
解释 Kafka 的 ISR 机制:ISR、HW(高水位)与 LEO 的关系,它们如何影响消息可靠性与消费可见性?acks=all 与 min.insync.replicas 如何配合?
参考答案要点
- LEO:每个副本下一条待写入的位置;ISR:与 leader 保持同步的副本集合,落后超过 replica.lag.time.max.ms 会被剔除
- HW(高水位):ISR 中最小的 LEO,消费者只能读到 HW 之前的消息,保证已被 ISR 全部持久化的数据才对消费者可见
- 可靠性配合:acks=all 要求写入被 ISR 全部确认;min.insync.replicas 规定 ISR 最少副本数,低于则拒绝写入(用可用性换一致性)
- 推荐组合:acks=all + min.insync.replicas=2 + replication.factor=3,不丢数据且可容忍一台 broker 故障
- trade-off:ISR 收紧(剔慢副本)提升可用性但削弱耐久性;unclean.leader.election 允许落后副本选主会丢数据,生产禁用
来源:[github.com](https://github.com/doocs/advanced-java)
q331 · 困难
RocketMQ 事务消息的实现原理是什么(半消息、本地事务、回查)?它解决的核心问题与局限是什么?
参考答案要点
- 流程:生产者先发半消息(对消费者不可见)→ 执行本地事务 → 按结果 Commit 或 Rollback;Broker 未收到二次确认时定时回查生产者的事务状态
- 解决的核心问题:本地事务与消息发送的原子性——先事务后发消息会丢消息,先发消息后事务则回滚时消息已外泄,半消息把两步变成原子
- 回查:生产者需实现回查接口,依据本地事务执行结果表返回状态;回查有次数上限,超限默认丢弃必须监控告警
- 局限:只保证生产者到 Broker 方向的原子性,消费侧仍需幂等与重试;不等于跨消费者分布式事务
- 对比本地消息表:事务消息把消息落地与扫描交给 Broker,业务少维护一张表,但要正确实现回查逻辑
来源:[github.com](https://github.com/doocs/advanced-java)
q332 · 中等
Kafka 消费组的 Rebalance 是什么?什么时候触发?为什么大促时频繁 rebalance 会引发消费停顿,如何优化?
参考答案要点
- 触发条件:消费者加入/退出(崩溃、处理超时被踢出组)、订阅的 topic 或分区数变化、组协调者切换
- 影响:rebalance 期间整组停止消费(类似 Stop The World);大促时消费慢 → 超时被踢 → 再平衡 → 更慢,形成恶性循环
- 参数优化:max.poll.interval.ms 大于最坏处理耗时、调小 max.poll.records、合理设置 session.timeout.ms 与心跳间隔
- 架构优化:处理逻辑异步化配合 pause/resume 控制拉取节奏;避免大促期间频繁扩缩容
- 减少触发:静态成员资格(group.instance.id)让重启不触发 rebalance;协作式分配(cooperative-sticky)把全量再平衡改为增量
- 监控:消费组 Lag 与 rebalance 次数指标告警
来源:[github.com](https://github.com/doocs/advanced-java)
场景题(4)
q133 · 困难
电商订单系统大促峰值下单 5 万 QPS,下游的履约、积分、短信系统各自只能承受几千 QPS,要求订单创建成功后各下游动作最终一致、不能丢消息。请设计异步化解耦方案并说明中间件选型理由。
参考答案要点
- 引入消息队列削峰解耦:峰值流量先入队,下游按自身能力消费,用最终一致换取主链路稳定
- 选型 trade-off:Kafka 吞吐最高,适合日志/埋点/流处理;RocketMQ 事务消息、延时消息、顺序消息完善,更适合订单类业务事件;RabbitMQ 路由灵活但吞吐一般
- 订单落库与消息发送的原子性:本地消息表(Outbox)或 RocketMQ 事务消息(半消息+回查)
- 消费端幂等(业务唯一键);有顺序要求的下游按订单 ID 路由到同一队列/分区串行消费
- MQ 自身成为关键依赖:集群高可用部署、积压监控、扩容预案(消费并行度受分区数限制)
- 链路变长带来排障成本:TraceId 透传到消息属性、消息轨迹、对账补偿兜底
来源:[interview.javaguide.cn](https://interview.javaguide.cn/high-performance/message-queue-interview-questions.html)
q315 · 困难
面试官要求现场设计一个简易 RPC 框架(类 Dubbo):服务端暴露接口,客户端像本地调用一样消费。请给出核心组件与调用流程(动态代理、序列化、网络通信、注册中心、负载均衡、超时重试),并说明各组件的关键设计选择与常见的坑。
参考答案要点
- 调用流程:客户端动态代理拦截 → 从注册中心订阅地址并负载均衡选一台 → 序列化请求 → Netty 长连接发送 → 服务端反序列化反射调用 → 结果异步转同步返回
- 序列化:在 hessian2/kryo/protobuf 间选型,关注跨语言、性能与反序列化安全漏洞;接口要版本兼容
- 注册中心:服务注册/订阅/变更通知;客户端本地缓存地址列表,注册中心故障时用缓存兜底继续调用
- 负载均衡:随机/轮询/一致性哈希/最少活跃调用;重试只对幂等操作,重试预算要保证下游超时小于上游剩余时间
- 异步与线程模型:CompletableFuture 异步调用,IO 线程与业务线程池分离;连接数与线程池队列设上限防雪崩
- trade-off 与坑:同步简单但阻塞;长连接复用高性能但要处理粘包拆包与心跳空闲检测;优雅停机(先摘注册再 drain)避免流量打到关闭中的实例
来源:[java.doocs.org](https://java.doocs.org/distributed-system/distributed-system-interview)
q316 · 困难
订单状态流转消息用 Kafka 传递,同一订单先后产生 已支付→已发货 两条消息,消费端偶发先处理已发货再处理已支付,导致状态回退被拒或数据错乱;同时消费组重平衡后出现重复消费。请分析乱序与重复的成因,并给出保证单订单消息顺序 + 幂等消费的完整方案。
参考答案要点
- 乱序成因:未按 key 分区导致同订单消息分散多分区并行;生产端重试 + max.in.flight 大于 1 导致批次乱序;单分区内消费端多线程并发处理
- 顺序保证:以订单 ID 为消息 key 路由到同一分区;生产端开启幂等并限制 max.in.flight(或设为 1);消费端单分区单线程,或按 key 再哈希到内存队列串行
- 重复成因:处理完未提交 offset 就宕机、重平衡分区移交;at-least-once 语义下重复不可避免
- 幂等消费:消费前执行带前态条件的状态机 UPDATE(where status=前态),或以消息 ID 建去重表(唯一索引),重复消息直接 ACK 跳过
- 乱序兜底:状态机拒绝非法迁移并告警;消息带版本号/事件时间,旧事件直接丢弃
- trade-off:按 key 串行降低并行度,热点 key 需拆分;去重表增加写放大换确定性;重平衡抖动可用静态成员与协作式分配缓解
来源:[java.doocs.org](https://java.doocs.org/distributed-system/distributed-system-interview)
q317 · 中等
大促后 Kafka 消费组积压 8000 万条消息,下游处理逻辑含外部 RPC 调用,消费 Lag 持续增长,业务要求 2 小时内清完且不压垮下游。请给出处置方案:消费能力评估、扩容手段(消费者数与分区数的关系)、跳过或转储策略,以及事后如何预防。
参考答案要点
- 瓶颈定位:先看消费 TPS 与生产 TPS 差距、消费线程是否阻塞在 RPC、是否频繁重平衡;一个分区只能被组内一个消费者消费,消费者数超过分区数无益
- 扩容:增加分区 + 消费者(评估 key 顺序性被破坏的影响);单消费者内多线程并行(注意处理完再提交 offset);批量聚合调用降 RPC 次数
- 下游保护:消费端按下游容量限速;临时转储——把消息搬运到更大分区数的新 topic 再大规模并行消费
- 极端策略:过期消息(如超时通知类)经业务确认后可直接丢弃或落库存档再跳过 offset;跳 offset 是高危运维操作必须留痕审批
- trade-off:清积压速度 vs 下游安全;顺序性 vs 并行度(扩分区破坏 key 顺序)
- 预防:容量按峰值生产 TPS × 安全系数规划;Lag 阈值告警;定期压测定容;丢弃/降级策略配置化
来源:[java.doocs.org](https://java.doocs.org/distributed-system/distributed-system-interview)