Skip to content

Java分布式架构面试题库 ​

生成时间:2026-05-21 22:17


【面试题】1. BASE理论的核心是什么?它和CAP有什么关系? ​

【标准答案】 BASE是Basically Available(基本可用)、Soft State(软状态)、Eventually Consistent(最终一致性)的缩写。核心思想是:在分布式系统中,我们不需要每时每刻都保证强一致性,可以通过放松一致性要求来换取更高的可用性和性能。

和CAP的关系:CAP告诉你"必须三选二",BASE告诉你"怎么在AP的框架下做到可接受的一致性"。CAP是原则,BASE是实践指南——当系统选择了AP架构(比如电商大促场景),BASE提供了落地的方法论:基本可用指系统出故障时可以降级(比如返回兜底数据)、软状态指中间状态可以被接受(比如订单"处理中"状态)、最终一致指不要求实时一致但保证最终会一致。面试加分点:举一个例子——双11下单时库存可能有延迟,用户看到"有货"但实际可能已售罄,系统事后补偿退款,这就是BASE的典型应用。


【面试题】2. Zookeeper分布式锁的临时节点和Watch机制是怎么保证锁的正确性的? ​

【标准答案】 Zookeeper分布式锁的核心是临时顺序节点:客户端在锁目录下创建临时顺序节点(EPHEMERAL_SEQUENTIAL),节点名会自动追加序号,比如/lock-000001、/lock-000002。判断是否获得锁的逻辑是:检查自己是不是序号最小的节点,是则获得锁,不是则监听前一个节点的删除事件。

Watch机制保证正确性的关键:当客户端释放锁(断开连接或主动删除节点)时,临时节点自动删除,触发后一个节点上的Watch回调,后一个节点收到事件后再次检查自己是否最小,是则获得锁。为什么用Watch监听前一个节点而不是监听所有节点?——避免"惊群效应":如果所有等待节点都监听锁节点,锁释放时所有客户端都被唤醒争抢,造成网络风暴;监听前一个节点实现了"公平排队",只唤醒一个客户端。临时节点的意义:客户端崩溃时节点自动删除,不会死锁。这和Redis锁比,Zookeeper的锁更"重"但一致性更强。


【面试题】3. 2PC两阶段提交有什么问题?3PC是如何改进的?生产环境真的用吗? ​

【标准答案】 2PC的核心问题有三个:第一,同步阻塞——所有参与者在Prepare阶段锁定资源后一直等待Coordinator决策,期间资源无法释放,高并发下性能急剧下降;第二,单点故障——Coordinator在发送Commit命令前崩溃,所有参与者一直阻塞在Prepare状态,资源被锁死;第三,数据不一致——Coordinator发送Commit后网络故障,部分参与者收到Commit执行提交,部分没收到继续阻塞,造成数据不一致。

3PC的改进:引入CanCommit阶段先询问"能不能提交"但不锁资源,降低阻塞时间;引入超时机制,参与者等不到命令时自动超时释放;把2PC的一个阻塞点拆成两个,降低单点故障影响。但生产环境基本不用3PC——理论上的改进抵不住复杂性增加,真正的一致性问题3PC也解决不了。实际生产用的是TCC、Saga、Seata这些方案,2PC/3PC是理论模型,知道原理即可。


【面试题】4. 美团Leaf号段模式的原理是什么?和Snowflake相比有什么优缺点? ​

【标准答案】 Leaf-segment的核心原理:放弃依赖时钟,改用数据库号段预取。数据库维护一张表,记录biz_tag和max_id、step,比如max_id=1000,step=1000。服务启动时从数据库预取一个号段(比如1001~2000),把max_id更新为2000,之后在内存中直接发号,不需要每次请求都访问数据库。号段快用完时,异步去数据库取下一个号段,实现双Buffer切换——一个Buffer发号,另一个Buffer预加载,保证发号无毛刺。

和Snowflake的对比:Snowflake依赖时钟,有时钟回拨问题,但ID严格递增且时间有序;Leaf-segment不依赖时钟,高可用性强,但ID不是严格递增(号段用完才跳到下一个号段,中间有空洞),也不具备时间语义。实际选型:对ID连续性要求不高、追求高可用的业务用Leaf-segment(比如订单号、用户ID);需要时间有序、且能容忍时钟回拨风险的用Snowflake。面试加分点:Leaf还有Leaf-snowflake模式,结合两者优势,用Zookeeper管理WorkerID,解决时钟回拨问题。


【面试题】5. Redis Cluster的16384个槽是怎么分配的?为什么是16384而不是65536? ​

【标准答案】 Redis Cluster采用虚拟槽分区:整个集群划分为16384个槽,每个Key通过CRC16(key) % 16384计算落在哪个槽,每个节点负责一部分槽位。客户端可以连接任意节点,节点返回MOVED重定向到正确节点,客户端会缓存槽位映射减少重定向次数。

为什么是16384而不是65536:关键在于心跳包大小。Redis Cluster节点之间通过Gossip协议交换信息,每个槽位用一个bit表示(归属自己或不归属),16384个槽=16384bit=2KB,65536个槽=8KB。集群规模上千节点时,心跳包大小差异巨大——2KB vs 8KB,对网络和内存的影响显著。而且16384个槽在大多数场景下已经足够,节点数小于等于16384时每个节点至少一个槽。面试加分点:说清楚槽位映射存在哪——客户端缓存槽位映射表,收到MOVED时更新,ASK重定向是迁移期间的临时状态,不走缓存。


【面试题】6. 分布式Session有几种方案?JWT无状态方案有什么优缺点? ​

【标准答案】 四种主流方案:第一,Session复制——每个节点都存全量Session,节点间同步Session数据,优点是天然高可用,缺点是内存浪费、同步延迟、集群规模受限;第二,Session粘性——通过Nginx的ip_hash或sticky cookie把同一用户请求固定到一个节点,优点是简单,缺点是节点挂了Session丢失、负载不均衡;第三,Session集中存储——把Session存到Redis/Memcached,所有节点都去Redis读写,优点是可靠性高、扩容方便,缺点是Redis单点风险(通过Redis集群解决);第四,JWT无状态——不存Session,把用户信息编码到Token里,服务端无状态验证签名即可。

JWT的优缺点:优点是完全无状态,服务端不需要存储Session,天然适合分布式和微服务;Token自包含用户信息,减少数据库查询。缺点:Token一旦签发无法主动失效(只能等过期),注销/改密码场景麻烦;Token体积大(包含用户信息),每次请求都要携带;Token泄露风险高,必须用HTTPS。实际选型:传统单体应用用Session+Redis集中存储;微服务架构、对状态不敏感的场景用JWT;安全要求高的场景结合两者——JWT存非敏感信息,敏感操作再查Session。


【面试题】7. 令牌桶和漏桶算法的区别是什么?分布式限流应该选哪个? ​

【标准答案】 核心区别在于处理突发流量的能力。漏桶算法:请求像水滴进桶,以恒定速率从桶底漏出(处理),桶满了就丢弃。本质是强行平滑流量,不管上游多猛,下游处理速率恒定——适合保护下游系统不被冲垮,但无法应对突发流量。令牌桶算法:以固定速率往桶里放令牌,请求来了拿令牌,有令牌就处理,没令牌就拒绝或等待。桶有容量上限,可以积累令牌——适合允许一定程度的突发流量。

分布式限流怎么选:大多数场景用令牌桶。原因:真实业务流量是有波动的,漏桶会强行削峰导致用户体验差;令牌桶在桶里有存量令牌时可以应对突发,更符合业务需求。Redis+Lua实现分布式令牌桶的思路:用Redis存储令牌数量和上次更新时间,每次请求时用Lua脚本原子性地计算令牌补充、扣减、返回是否通过。实际落地可以用Redisson的RRateLimiter或Guava RateLimiter(单机),分布式场景推荐Sentinel或Redis+Lua自研。面试加分点:提到滑动窗口——更精细的控制,适合需要严格QPS限制的场景,但实现复杂度更高。


【面试题】8. Paxos算法的核心流程是怎样的?为什么说Raft是"简化版Paxos"? ​

【标准答案】 Paxos有三个角色:Proposer(提案者)、Acceptor(接受者)、Learner(学习者)。核心流程分两阶段:第一阶段Prepare,Proposer生成提案编号N,向多数派Acceptor发送Prepare(N)请求;Acceptor收到Prepare(N)后,如果N大于之前见过的所有提案编号,就承诺不再接受编号小于N的提案,并返回已接受的提案值(如果有)。第二阶段Accept,Proposer收到多数派响应后,如果没有提案值就用自己的,如果有就用响应中编号最大的那个值,发送Accept(N, V)给Acceptor;Acceptor接受后,提案达成共识。

为什么Raft是"简化版Paxos":Paxos的核心问题是难理解和难实现——角色边界模糊、多Proposer并发时可能活锁、工程落地复杂。Raft做了三个简化:第一,强Leader模型——所有提案都由Leader发起,Follower只接受Leader的提案,消活锁;第二,日志连续——日志索引连续递增,Leader保证日志复制顺序,简化一致性检查;第三,分阶段清晰——Leader选举、日志复制、安全性三个子问题拆开讲,工程落地有明确路径。面试官问"你懂Paxos吗"时,核心就是答出两阶段Prepare+Accept、多数派承诺、提案编号比较这三个点。


【面试题】9. Zookeeper的Watch机制有什么特点?为什么不适合做大规模配置推送? ​

【标准答案】 Watch机制的三个核心特点:第一,一次性触发——Watch被触发后立刻失效,客户端需要重新注册。这意味着如果客户端处理事件时又发生了变更,可能会丢事件,需要自行处理;第二,异步通知——Watch事件是异步推送给客户端的,客户端收到通知时数据可能已经变了;第三,不保证顺序——多个Watch事件的触发顺序不保证,需要客户端自己处理。

不适合大规模配置推送的原因:第一,一次性触发导致重新注册风暴——假设10万个客户端监听同一个节点,节点变更触发10万个Watch,客户端收到事件后又发10万个重新注册请求,Zookeeper瞬间压力爆炸;第二,通知延迟和带宽压力——大规模推送时网络成为瓶颈;第三,客户端重连时全量Watch重注册。解决方案:配置推送用长轮询(Nacos)或长连接推送(Apollo),或者用Zookeeper但配合本地缓存+版本号比对,减少Watch注册频率。面试中要强调:Zookeeper的核心定位是协调服务(选主、分布式锁、服务发现),配置推送只是附带能力,大规模场景要换专用工具。


【面试题】10. XXL-Job的调度中心高可用是怎么实现的?任务执行失败有哪些容错机制? ​

【标准答案】 XXL-Job调度中心高可用:调度中心是无状态的,多个实例通过数据库竞争锁(数据库行锁)来决定谁来执行调度。数据库存储任务信息、执行日志、锁信息,调度中心启动时通过SQL竞争锁(select ... for update),拿到锁的成为活跃调度器,其他 standby。活跃调度器崩溃后,数据库锁自动释放,standby节点竞争成为新的活跃节点。本质是通过数据库实现了"主备切换",简单但有效——适合中小规模,大规模场景可以用Redis或Zookeeper替代数据库锁。

任务执行失败的容错机制:第一,失败重试——可配置重试次数,执行器返回失败后调度中心自动触发重试;第二,故障转移——执行器集群模式下,某个执行器失败后可以转发到其他执行器;第三,错过重做——调度中心宕机期间错过的任务,恢复后可以补执行(可配置);第四,超时控制——任务执行超时后强制终止(通过线程池超时+Future.cancel实现),避免任务卡死。面试加分点:提到"分片广播"模式——一个大任务拆成多个分片,不同执行器处理不同分片,适合大数据量批处理场景,比如分库分表后的数据迁移。