分布式面试65问深度解析:CAP、锁、事务与Netty全攻略
分布式面试是 Java 后端绕不过去的一道坎。无论是大厂还是中大型互联网公司只要涉及高并发、微服务、海量数据存储面试官一定会从缓存一致性、分布式锁、事务、ID 生成、网络通信、存储拆分这几个方向连续追问。单纯背八股文已经不够用关键是能讲清楚“为什么这样设计”和“遇到问题怎么排查”。这篇文章围绕 2026 年分布式面试最高频的 65 问做一次系统梳理把 Netty、分布式锁、分布式事务、分库分表、分布式 ID、分布式基础理论拆开讲透。每个模块都给出核心知识点、面试官常见的追问方向、可落地的回答思路末附代码示例和判断标准尽量把面试中“卡壳”的地方补上。1. 分布式面试六大模块速览先看清楚分布式面试到底考什么再逐个击破。模块核心考察点高频关键词面试难度分布式基础CAP、BASE、一致性哈希、脑裂一致性、可用性、分区容错中Netty线程模型、零拷贝、粘包拆包、心跳EventLoop、ByteBuf、Pipeline中高分布式锁Redis 锁、ZooKeeper 锁、数据库锁原子性、续期、可重入、红锁高分布式事务2PC、TCC、Saga、本地消息表强一致性、最终一致性、幂等高分库分表垂直拆分、水平拆分、路由、扩容分片键、全局表、ID 取模中高分布式 ID雪花算法、号段模式、Leaf趋势递增、时钟回拨、bit 位分配中这六个模块不是孤立的。面试官经常把一个业务场景串起来问例如“订单系统分库分表后ID 怎么生成分布式锁怎么用跨库事务怎么处理”所以每个模块不但要懂还要能关联起来回答。2. 分布式基础理论CAP、BASE 与一致性哈希2.1 CAP 定理三个里面选两个CAP 说的是分布式系统中一致性Consistency、可用性Availability、分区容错性Partition tolerance最多同时满足两个。面试官第一个追问通常是“为什么不能三个都满足”回答思路网络分区是分布式系统的客观现实。一旦分区发生节点之间的通信会失败。如果保证一致性就必须拒绝读写请求此时可用性不满足如果保证可用性节点可以继续对外服务但可能返回旧数据此时一致性不满足。因此在分区发生时只能在 C 和 A 之间做选择。第二个追问是“你们系统选 CP 还是 AP”标准回答框架需要强一致性的场景选 CP例如库存扣减、订单状态、账户余额。可以接受短暂不一致、但必须持续可用的场景选 AP例如商品详情、用户浏览记录、Feed 流。补充一句更容易加分“实际上大多数互联网产品是 AP 为主配合异步对账和数据补偿来收敛最终一致性。完全 CP 的系统通常只出现在金融核心链路。”2.2 BASE 理论BASE 是 Basically Available、Soft state、Eventually consistent 的简称核心思想是接受暂时的不一致通过异步手段让数据在某个时间点达到一致。面试官一般会问“BASE 和 ACID 有什么区别”回答思路ACID 是单机数据库的事务保证强调强一致性。BASE 是分布式系统的设计取舍强调可用性和最终一致性。实践中两者常常共存核心账户操作走 ACID跨系统通知走最终一致性。2.3 一致性哈希扩容时的迁移最小化一致性哈希解决的问题是普通取模路由在节点数量变化时大量 key 需要重新映射导致缓存雪崩效果明显。讲解模版假设有 3 台缓存节点key 按 hash(key) % 3 路由。节点从 3 台加到 4 台时约 75% 的 key 会落到新节点上旧数据大面积失效。一致性哈希把哈希值组织成一个环节点和 key 都映射到环上key 沿顺时针找最近的节点。新增节点只影响该节点的后继区间内的数据迁移量显著减少。面试追问“一致性哈希为什么引入虚拟节点”因为真实节点少时哈希环上节点分布不均数据倾斜严重。给每个物理节点创建几十到上百个虚拟节点让它们在环上均匀分布同时当一个物理节点挂掉后负载由多个虚拟节点分担避免单个节点压力过大。3. Netty 必背知识点与高频面试题3.1 Netty 是什么为什么用它Netty 是一个基于 Java NIO 的异步事件驱动网络框架屏蔽了原生 NIO 编程的复杂性提供稳定可扩展的高并发网络通信能力。面试回答模板原生 NIO 编程需要自己处理 Selector、Channel、Buffer、多线程模型、半包粘包等问题开发成本和维护成本都很高。Netty 把这些问题封装成统一的 API提供了更合理的线程模型、丰富的编解码器和成熟的内存管理机制所以很多中间件底层都用它比如 Dubbo、RocketMQ、Elasticsearch、Sentinel 的通信层。3.2 Netty 线程模型Reactor 模式面试经常直接画图问“Netty 的 BossGroup 和 WorkerGroup 是怎么配合工作的”讲清楚这条链路即可BossGroup 接收客户端连接把接收到的 Channel 注册到 WorkerGroup。WorkerGroup 负责后续的读写事件处理。每个 EventLoop 是一个线程内部不断执行 select 和 processSelectedKeys。Netty 默认使用主从 Reactor 多线程模型一个 BossGroup 处理 accept 事件多个 WorkerGroup 处理 read/write 事件。追问方向“一个 EventLoop 处理多个 Channel会不会阻塞”回答思路EventLoop 本质是单线程串行执行任务如果某个 Channel 的业务处理耗时过长会阻塞同一个 EventLoop 上的所有 Channel。所以耗时操作必须丢到业务线程池不能直接放在 handler 里同步执行。3.3 粘包与拆包TCP 是流式协议没有消息边界。发送方写两条消息接收方可能一次读到两段完整消息也可能读到半条消息。面试问法“Netty 怎么解决粘包拆包”回答思路通过编解码器解决。固定长度FixedLengthFrameDecoder。分隔符LineBasedFrameDecoder、DelimiterBasedFrameDecoder。长度字段LengthFieldBasedFrameDecoder最常用。这里必须能写一段配置代码pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4)); pipeline.addLast(new StringDecoder(StandardCharsets.UTF_8)); pipeline.addLast(new ServerBizHandler());需要解释每个参数含义maxFrameLength 是最大帧长度lengthFieldOffset 是长度字段偏移量lengthFieldLength 是长度字段字节数lengthAdjustment 是长度修正值initialBytesToStrip 是解码后跳过的字节数。3.4 零拷贝Netty 的零拷贝和操作系统层面的零拷贝概念不完全一样。回答维度文件传输场景使用 FileRegion底层基于 sendfile数据从内核空间直接发到网卡减少一次用户态拷贝。ByteBuf 支持堆外内存 DirectBuffer数据在 JVM 堆外直接读写减少堆内存与内核空间的复制。CompositeByteBuf 可以把多个 ByteBuf 组合成逻辑上连续的缓冲区避免合并数据时的拷贝。面试追问“DirectBuffer 为什么能减少拷贝缺点是什么”回答DirectBuffer 直接使用操作系统内存在 IO 读写时省略堆内存和 native 内存之间的复制。缺点是分配和释放成本比堆内存高如果使用不当会造成 native 内存泄漏所以 Netty 提供了内存池 PooledByteBufAllocator 进行管理和复用。3.5 心跳检测与空闲处理Netty 内置 IdleStateHandler 可以检测读空闲、写空闲、读写空闲。配置示例pipeline.addLast(new IdleStateHandler(30, 0, 0, TimeUnit.SECONDS));参数含义30 秒没读到数据触发 READER_IDLE 事件。业务 handler 里重写 userEventTriggered 方法收到空闲事件后关闭连接或者发送心跳包。面试官会问“心跳失败后怎么办”回答连续超过阈值未收到心跳服务端将连接标记为失效主动关闭释放资源。客户端收到关闭后按重连策略重新连接。注意心跳与业务超时要区分开心跳只负责连接活性探测业务超时由业务层控制。3.6 Netty 内存泄漏排查Netty 使用引用计数管理 ByteBuf忘记 release 会造成内存泄漏。面试追问“怎么排查 Netty 内存泄漏”回答思路开启 Netty 自带的内存泄漏检测级别。在启动参数中配置-Dio.netty.leakDetection.levelparanoidparanoid 级别会做更严格的采样检测日志中出现 LEAK 关键字时再结合单元测试和 heap dump 定位在哪一步没有 release。4. 分布式锁Redis、ZooKeeper、数据库三选一分布式锁全链路考题是最容易在面试中深度展开的部分。面试官通常先问“分布式锁有哪些实现”然后追问“Redis 锁的坑”再追问“ZooKeeper 锁和 Redis 锁怎么选”。4.1 分布式锁要满足的四个条件回答任何分布式锁实现之前先给出判断标准互斥性任意时刻只有一个客户端能持有锁。死锁避免持有锁的客户端崩溃后锁能自动释放。安全性释放锁时只能释放自己持有的锁不能误删其他客户端的锁。可重入性同一个线程能否重复获取同一把锁。4.2 Redis 实现分布式锁SETNX 过期时间Redis 分布式锁最基础的实现是SET lock_key unique_value NX PX 30000NX 表示 key 不存在时才设置保证互斥。PX 设置过期时间防止客户端崩溃导致死锁。unique_value 是客户端唯一标识释放锁时先比较再删除。释放锁必须用 Lua 脚本保证原子性if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end为什么不能用简单的 del因为线程 A 的锁如果过期了线程 B 获取了同一把锁此时 A 再去 del 会把 B 的锁删掉。所以必须校验 value。4.3 Redis 锁的续期问题锁的过期时间设短了业务没执行完锁就过期另一个线程趁虚而入。设长了持有锁的客户端挂了其他线程要等很久。回答方案看门狗自动续期。客户端在获取锁后启动一个定时任务如果业务还在执行每隔一段时间给锁续期释放锁时取消续期任务。Redis 官方 Java 客户端 Redisson 就是这个机制默认 watch dog 超时时间是 30 秒每 10 秒检查一次并续期到 30 秒。4.4 Redlock 算法的争议Redlock 是 Redis 作者提出的多节点分布式锁算法要求向大多数 Redis 节点依次加锁超过半数成功才算加锁成功。面试官会追问“Redlock 可靠吗”需要如实知道它的争议点Redis 主从切换时锁在旧 master 上还没同步到新 master新客户端可能同时获得锁。Redlock 依赖同步时钟如果多台机器时钟跳跃过大会导致锁同时过期。业界有不少分布式系统专家认为 Redlock 不是强一致锁更推荐 ZooKeeper 或 etcd 这类带多数派协议的系统。因此建议面试回答高并发但允许极小概率并发冲突的场景用 Redis 锁对一致性要求非常高的场景用 ZooKeeper 或 etcd。4.5 ZooKeeper 实现分布式锁ZooKeeper 分布式锁基于临时顺序节点客户端在锁目录下创建临时顺序节点。判断自己是否是最小序号节点。如果是获得锁。如果不是监听比自己序号小的节点删除事件。节点删除后重新检查是否有资格获得锁。临时节点保证了客户端崩溃后节点自动删除不需要设置过期时间避免了 Redis 锁过期时间难控制的死锁问题。ZooKeeper 锁的问题在性能每次加锁解锁都要多次网络 RTT高并发下吞吐比 Redis 低。4.6 数据库实现分布式锁最简单的数据库锁创建 lock 表唯一索引约束 lock_name获取锁时插入记录释放锁时删除记录。问题很明显频繁插入删除对数据库压力大。没有锁过期机制应用崩溃后需要人工处理。不具备可重入性。建议回答时把数据库锁定位为“早期方案中可用的轻量实现”现在生产环境很少单独使用。5. 分布式事务从 2PC 到 Saga5.1 事务模型对比方案一致性类型适用场景代码侵入度协调者2PC强一致数据库单事务跨多个节点低有3PC强一致减少阻塞低有TCC最终一致需要业务补偿高有Saga最终一致长流程事务高有本地消息表最终一致跨系统异步通知中无5.2 2PC 两阶段提交2PC 有两个阶段Prepare 阶段协调者向所有参与者发送 prepare 请求参与者执行本地事务但不提交返回 ready 或 not ready。Commit 阶段如果所有参与者都 ready协调者发送 commit所有参与者提交事务。如果有任何一个参与者 not ready协调者发送 rollback。2PC 最大的问题同步阻塞参与者持有数据库资源锁等待协调者指令。单点风险协调者宕机后参与者无法决策。数据不一致commit 阶段部分参与者成功部分失败没有回滚机制。5.3 TCCTry-Confirm-CancelTCC 把每个业务操作拆成三个方法Try预留资源检查业务。Confirm真正执行业务。Cancel回滚释放资源。以订单加库存为例Try冻结库存数量。Confirm扣减冻结库存。Cancel释放冻结库存。面试官喜欢追问 TCC 的幂等性和空回滚Confirm 和 Cancel 操作必须支持幂等靠事务 ID 和状态字段实现。空回滚Try 没有真正生效时收到 Cancel 请求不能报错要记录状态再返回成功。悬挂问题Cancel 先于 Try 到达要拒绝 Cancel 或标记为已回滚。5.4 Saga 长事务Saga 是一系列本地事务的编排每个步骤有对应的补偿操作。执行第 n 个事务失败时反向执行第 n-1 到第 1 步的补偿。Saga 有两种实现模式事件编排每个服务监听事件并决定下一步无中心控制器。命令编排中心协调器发起每一步操作。Saga 的弱点是隔离性差中间步骤产生的数据在事务完成前对其它系统可见需要业务层面提前做对冲。5.5 本地消息表 消息队列本地消息表是很多互联网系统最终一致性落地的方案业务操作和消息写入本地同一个事务。异步任务扫描消息表把消息发送到 MQ。消费者处理消息后回调确认可靠消费。这个方案好处是事务只涉及本地数据库不引入强一致协调者性能可控。要注意消费端幂等消息重复投递是常态必须用唯一业务 ID 做去重。6. 分库分表拆分策略、路由与扩展6.1 什么时候分库分表面试官会问“数据量多大时考虑分库分表”回答思路先看单库单表是否出现明显瓶颈。当单表数据量超过一定水平、索引 B 树层级加深、查询性能明显下降或者写入并发过高、单库连接成为瓶颈时才考虑分库分表。更合理的判断依据是当前业务增速和资源消耗已经无法通过加索引、加缓存、归档旧数据解决。分库分表能带来什么分散数据库连接压力。降低单表索引层级提升查询性能。减少单个数据库的磁盘和 IO 压力。6.2 垂直拆分与水平拆分垂直拆分按业务模块拆库例如用户库、订单库、商品库。拆的是表和业务的维度。水平拆分同一个表按规则拆到多个库多张表。拆的是数据行常见方式范围分片按时间或 ID 区间拆。哈希取模按 user_id 取模。一致性哈希配合虚拟节点减少扩容迁移。6.3 分片键选择分片键是分库分表最关键的设计。选择标准查询频率最高的字段优先。尽量保证数据分布均匀。避免跨分片查询。典型方案订单表按 user_id 分片同一用户订单落在同一分片查询用户订单不跨分片。但按订单 ID 查询时就需要带 user_id 条件或者维护订单 ID 和 user_id 的映射关系。6.4 全局表与广播表某些表的数据量很小几乎只读例如省份、国家、商品分类。每个分片都需要完整数据可以做全局表// ShardingSphere 配置示例 spring.shardingsphere.rules.sharding.broadcast-tablest_dict全局表在每个分片都有完整副本查询时在本地分片直接命中不需要跨库 join。6.5 跨分片查询问题分库分表后join、排序、聚合、分页都可能跨分片。回答思路尽量避免跨分片 join把 join 逻辑上移到应用层。全局排序和分页需要先拉取所有分片的数据在应用内存中排序合并数据量大时性能差。更常见的做法是限制深度分页走 Redis 缓存或者按照业务条件缩小范围。聚合统计可以用异步任务提前汇总避免实时全分片聚合。6.6 扩容的两种策略水平扩容是分库分表最麻烦的问题。原方案如果用的是 ID 取模节点从 4 扩到 8rehash 代价很高。两种实用方案一致性哈希 虚拟节点迁移量可控但范围查询支持有限。双倍扩容节点数翻倍例如 4 库扩 8 库每个旧库只迁移一半数据到新库迁移逻辑简单。面试提一句“先做平滑迁移再切换读写流量最后下线旧节点”就能体现工程经验。7. 分布式 ID雪花算法与号段模式7.1 分布式 ID 的要求全局唯一。趋势递增或单调递增优化数据库索引写入。高可用低延迟。尽量附带业务信息。7.2 雪花算法 Snowflake雪花算法核心结构是 64 位 long第 1 位符号位固定 0。第 2 到 42 位毫秒时间戳。第 43 到 52 位机器 ID。第 53 到 64 位同一毫秒内自增序号。一次生成示例Java 简版public class SnowflakeIdWorker { private long workerId; private long sequence 0L; private long lastTimestamp -1L; public synchronized long nextId() { long timestamp System.currentTimeMillis(); if (timestamp lastTimestamp) { throw new RuntimeException(Clock moved backwards); } if (timestamp lastTimestamp) { sequence (sequence 1) 4095; if (sequence 0) { timestamp waitNextMillis(lastTimestamp); } } else { sequence 0L; } lastTimestamp timestamp; return ((timestamp - 1288834974657L) 22) | (workerId 12) | sequence; } private long waitNextMillis(long lastTimestamp) { long timestamp System.currentTimeMillis(); while (timestamp lastTimestamp) { timestamp System.currentTimeMillis(); } return timestamp; } }7.3 雪花算法的坑时钟回拨时钟回拨会导致生成的 ID 重复。处理方案短时间回拨等待时钟追上最后生成时间。长时间回拨切换为从数据库或 Redis 获取号段。更稳妥的做法是用机器最新记录的时间戳和当前时间对比回拨阈值内拒绝服务超过阈值自动降级到备用生成策略。7.4 号段模式与 Leaf号段模式是批量获取一段 ID 区间例如一次取 1000 个 ID 缓存在内存中用完了再向数据库申请下一段。数据库只记录 max_id 和 step写压力很小。美团 Leaf 是分布式 ID 的代表方案Leaf-segment基于号段。Leaf-snowflake基于雪花算法并解决时钟回拨。面试可以提到Leaf-snowflake 在启动时从 ZooKeeper 注册机器节点获取机器 ID运行时如果检测到时钟回拨会根据回拨时间长短决定是否拒绝请求。8. 分布式系统经典追问与工程实践8.1 幂等设计跨系统事务和 MQ 消费里幂等是安全问题。面试回答框架幂等键用唯一业务标识例如 orderId、paymentId。去重表在数据库中加唯一索引第二笔请求插入失败直接返回成功。状态机校验只允许特定状态流转例如支付单只能从待支付变为已支付。8.2 熔断、降级与限流面试官会问“系统里某个下游服务慢了怎么办”。回答思路限流挡住流量进入系统常见算法有令牌桶、漏桶。熔断下游错误率达到阈值直接断开调用快速失败。可以参考 Sentinel 或 Hystrix 的熔断器状态机。降级非核心功能在资源紧张时直接降级例如搜索推荐列表返回兜底数据。三者配合限流挡上游熔断防下游降级保核心。8.3 分布式系统链路排查面试题问“线上接口突然变慢怎么排查”。排查顺序先看监控大盘QPS、响应时间、错误率、GC 指标。再看调用链找到耗时集中在哪个服务。看数据库慢查询、Redis 慢日志和网络指标。用线程 dump 检查是否有锁竞争或线程阻塞。检查是否依赖了外部接口外部接口超时时间是否合理。回答里要强调链路追踪、Metrics 和日志三件套在分布式系统里是必需品而不是可选优化。9. 分布式面试回答思路与避坑建议9.1 先给结论再给细节面试官问你“Redis 锁和 ZooKeeper 锁怎么选”。错误回答直接开始讲 Redis 锁怎么实现、ZooKeeper 节点怎么创建讲完二十秒还没到比较。较好回答“选型取决于一致性要求。如果能接受极小概率的锁失效我选 Redis性能高、实现简单如果核心金融链路要求锁严格互斥我选 ZooKeeper它基于顺序节点和临时节点天然支持强一致锁。下面是两种实现的对比……”先给结论再展开细节信息密度高面试官容易抓到重点。9.2 注意两个容易暴露基础薄弱的点第一个是讲分布式事务时把 2PC 和 TCC 混为一谈。TCC 不是 2PC 的替代品它是业务层面的补偿方案2PC 是数据库层面的协议。第二个是讲分库分表时不提分片键选择。只说“按 ID 取模”是不够的要说明为什么选这个分片键、查询场景怎么覆盖、扩容怎么做。9.3 用真实项目经验补充回答如果简历里有订单、支付、交易、消息推送等场景尽量把每个理论知识点挂到项目上。例如订单 ID 用 Leaf-snowflake因为需要趋势递增而且能保证全局唯一。突然流量高峰时秒杀接口用了 Redis 分布式锁加本地缓存核心库存扣减走数据库乐观锁。订单状态同步用本地消息表加 RocketMQ消费端按订单 ID 做幂等。订单表分库后按用户的 buyer_id 分片查询订单列表时不做跨库 join。有项目细节支撑的分布式面试回答比单纯列举理论容易得分得多。9.4 常见追问方向速查模块高频追问关键判断标准分布式基础CAP 中 P 为什么不能放弃分区是客观可能发生的不能假设网络永远可靠Netty粘包拆包能用长度字段方案解释并说明参数含义分布式锁Redis 锁过期了怎么办看门狗续期、RedLock 争议、ZC 选择分布式事务TCC 空回滚和幂等能解释悬挂问题与状态机设计分库分表分片键选错了怎么办分片键尽量不可变变更代价大分布式 ID时钟回拨能说清等待、拒绝、降级三种策略10. 总结与下一步分布式面试不是靠背题能过关的核心还是在理解设计取舍。先把 CAP 和 BASE 想清楚再逐个攻破 Netty 线程模型、Redis 锁的续期问题、TCC 的空回滚、分库分表的扩容策略、雪花算法的时钟回拨这五道题过了分布式面试的大框架就没有明显短板。建议把本文提到的模块拆成 5 份知识卡片按两天一个模块的节奏复习。每个模块写完一个模拟面试回答录下来或者写下来对比标准答案找差距。最容易踩的坑是每个模块都只懂皮毛面试官追问两句就掉链子所以阶段性的模拟追问训练比单纯阅读更有效。后续可以继续深入的方向Kafka 或 RocketMQ 的消息可靠性设计、ZooKeeper 的 ZAB 协议和 Raft 的对比、ShardingSphere 的具体配置实战、Seata 的 AT 模式源码解读。每一项都能和本文的某个模块连起来继续深挖。收藏本文换个主题再来一轮比刷十套题更踏实。