Skip to content

【面试题】1. Consul 和 Nacos 的健康检查机制有什么本质区别?多数据中心场景下怎么选型? ​

【标准答案】Consul 用 Agent 模式,每个节点跑一个 Consul Agent,健康检查在 Agent 本地执行,支持 Script、HTTP、TCP、gRPC 多种检查方式,延迟低但依赖 Agent 进程存活。Nacos 的健康检查分临时实例和持久实例:临时实例用心跳上报,客户端主动发心跳给服务端,服务端超时未收到就剔除;持久实例由服务端主动探测。两者最关键的区别:Consul 强一致性(Raft),更适合多数据中心、需要 KV 存储和 ACL 的运维场景;Nacos 的 AP+CP 可切换,更适合国内 Spring Cloud 体系,跟配置中心一体化用着方便。选型上:多数据中心+强一致需求选 Consul,国内微服务体系一体化选 Nacos。

【面试题】2. 网关层怎么做统一鉴权?JWT 无状态方案和 OAuth2 集中鉴权各有什么坑? ​

【标准答案】网关统一鉴权的核心是在请求到达业务服务前完成身份校验,把用户信息写入 Header 往下透传。JWT 方案:客户端带 Token,网关验签后解析出 userId、角色等信息,优点是无状态、不依赖认证中心,缺点是 Token 无法主动失效,只能靠短过期+黑名单补救,适合内部服务间调用。OAuth2 方案:网关拦截请求后去认证中心校验 Token,优点是支持集中管控、Token 可随时吊销,缺点是每次请求都多一次网络调用,需要缓存 Token 校验结果降低延迟。实战里大部分用混合方案:对外用 OAuth2+网关做用户登录态校验,内部服务间调用用 JWT 做轻量鉴权,各取所长。

【面试题】3. Apollo 的配置发布机制是怎么设计的?配置发布后怎么做到实时生效和快速回滚? ​

【标准答案】Apollo 配置发布分三步:用户在 Portal 编辑配置 → 点击发布后配置写入 ConfigDB → Config Service 通过长轮询通知客户端。客户端和服务端之间维持一个 HTTP 长连接(默认 60s 超时),服务端有变更时立刻返回,没变更就 hold 住,避免了客户端频繁轮询的开销。发布时可以选灰度:先对部分实例生效,观察没问题再全量推。回滚靠版本管理——每次发布产生一个 Release 记录,点"回滚"其实是用历史 Release 重新发布一次,本质上是创建一个指向旧配置的新 Release,不是真正的时间穿越。这个设计让回滚跟发布走同一个通道,风险可控、操作简单。

【面试题】4. Paxos 协议的核心思想是什么?为什么 Raft 比 Paxos 更容易工程实现? ​

【标准答案】Paxos 的核心是"多数派达成一致":一个提案只要被超过半数节点接受,就算通过,后续任何提案都能通过 Learn 阶段感知到这个值。它把共识拆成 Prepare、Accept、Learn 三个阶段,但 Lamport 论文里只定义了单值共识,多值共识靠 Multi-Paxos 工程补丁,各实现之间有差异,理解和调试成本都很高。Raft 的核心思想是"强领导+日志复制":Leader 收到请求→写本地日志→复制到 Follower→多数确认→提交。它把共识拆成 Leader 选举、日志复制、安全三个独立子问题,每个都清晰易懂。Raft 赢在两点:一是可理解性(论文明确说这是设计目标),二是落地确定性(etcd、TiKV 等直接按论文实现,不会各自魔改)。面试官想听的是:Paxos 是理论奠基,Raft 是工程落地。

【面试题】5. SAGA 分布式事务的"编排模式"和"协同模式"有什么区别?长事务场景下各自怎么处理补偿? ​

【标准答案】SAGA 的核心是把一个大事务拆成多个本地事务,每个本地事务配一个补偿操作,失败时逆序补偿。编排模式(Orchestration)有一个 Saga 管理器统一调度:管理器按顺序调服务 A→B→C,哪步失败就从失败点往前逆序调补偿。优点是流程清晰、集中管控,缺点是管理器变成单点和耦合点。协同模式(Choreography)是事件驱动:A 成功发事件→B 监听执行→B 成功发事件→C 监听执行,失败也发事件触发补偿。优点是松耦合、无中心节点,缺点是流程散落各处难追踪。长事务场景里编排更可控,配合状态机记录每步执行状态,挂了恢复时从断点继续;协同需要配合事件溯源,重放事件恢复状态。实战里多数选编排,因为运维看得见、排查有抓手。

【面试题】6. Dubbo 的 RandomLoadBalance 带权重的随机算法是怎么实现的?和 Nginx 的加权轮询有什么不同? ​

【标准答案】Dubbo 的 RandomLoadBalance 不是简单的 random.nextInt(权重和),而是做了两层优化:第一层判断权重是否全部相等,相等就直接随机;第二层如果权重不等,先用 random.nextInt(总权重) 得到一个偏移量,然后遍历 Provider 列表,用偏移量依次减去每个 Provider 的权重,减到 0 以下就选中那个 Provider。本质是让随机数落在权重区间里。Nginx 的加权轮询更精妙,用的是 smooth weighted round-robin,每个节点维护 currentWeight,每次选当前 weight 最大的节点,选中后减去总有效权重再继续,这样权重大的节点被选中的次数多但分布平滑,不会连续砸一个节点。两者区别:Dubbo 随机适合请求量均匀的场景,实现简单;Nginx 平滑加权适合长连接、需要精确控制流量比例的场景。

【面试题】7. Hystrix 的断路器三种状态之间怎么切换?半开状态的设计巧妙在哪? ​

【标准答案】Hystrix 断路器有三种状态:关闭(正常放行)→ 打开(快速失败)→ 半开(试探性放行)。核心转换逻辑:关闭状态下,统计时间窗口内失败率达到阈值(默认 50%)且请求数满足最小阈值(默认 20),断路器跳变到打开状态;打开状态下,所有请求直接走 fallback,等待一个 Sleep Window(默认 5s)后转入半开;半开状态是最巧妙的设计——只放行一个请求去试探下游,成功了就切回关闭,失败了继续打开。这相当于一个"侦察兵"机制:既不会让所有请求都去撞墙,又能自动探测服务是否恢复。跟 Sentinel 的区别在于 Sentinel 是滑动窗口统计+渐进式恢复,没有显式的半开状态,而是通过慢启动逐步放量。

【面试题】8. Redis 集群/哨兵模式下分布式锁为什么不能用单实例?Redlock 怎么解决又被 Martin 质疑了什么? ​

【标准答案】Redis 单实例做锁问题很明显:主节点加锁成功,还没同步到从节点就宕机了,哨兵把从节点提为主,新主上没有锁数据,另一个客户端可以再加一把锁,出现锁互斥失效。Redlock 方案:同时向 N 个独立 Redis 实例加锁(N 通常为 5),只要超过半数(N/2+1)加锁成功且总耗时小于锁过期时间,就算获取锁成功。但 Martin Kleppmann 的核心质疑是:Redlock 把分布式锁当一致性协议用,但它依赖过期时间来保证安全,一旦出现 GC 停顿或网络延迟导致锁过期而客户端还不知道,安全保证就失效了。正确的做法是配合 fencing token:每次加锁带一个递增序号,写入存储时校验序号,被超时的旧客户端写不进去。争议的底层共识是:分布式锁只能保证互斥的效率,不能保证数据的正确性。

【面试题】9. 百度 UidGenerator 的 CachedUidGenerator 是怎么用 RingBuffer 提升 ID 生成性能的?和 Leaf 的 Segment 双 Buffer 有什么异同? ​

【标准答案】CachedUidGenerator 的核心是用 Disruptor 的 RingBuffer 做预加载:启动时把一批 UID 填满环形数组,消费端异步取 ID,取一个就触发一个填充事件,往 RingBuffer 里补一个,始终保持缓冲区是满的。这样业务线程拿 ID 时几乎没有等待,因为 UID 已经躺在内存里了。Leaf Segment 双 Buffer 思路类似但实现更简单:用两个 Segment 交替使用,当前 Segment 快用完时(比如 10%),异步加载下一个号段到备用 Segment,当前用完直接切换。两边的共同点是"用空间换时间、预加载削峰":RingBuffer 粒度更细(每个槽一个 ID)、实时性更好;双 Buffer 粒度粗但实现简单、维护成本低。中低 QPS 场景双 Buffer 足够了,极高并发(比如每秒几十万 ID)才需要 RingBuffer。

【面试题】10. 康威定律怎么指导微服务团队组织?业务中台、架构组、业务研发组之间如何划分边界和协作? ​

【标准答案】康威定律核心就一句话:系统架构是组织沟通结构的镜像。组织怎么分团队,系统就怎么拆模块。应用到微服务:一个跨职能小团队(5-8人)独立负责一个限界上下文,团队拥有该服务的全部——开发、测试、运维、发布,没有跨团队依赖的阻塞。三个角色的边界:业务研发组对业务领域最熟,负责业务服务的需求落地和日常迭代;架构组负责基础设施(注册中心、网关、监控、CICD),给业务组提供平台和规范,但不替业务组写代码;业务中台是争议最大的——做得好了是公共能力复用,做得不好就是瓶颈。关键原则:中台只沉淀真正稳定的共性能力,不能因为"以后可能会复用"就提前收拢;业务组对中台能力有使用权,但中台的优先级和路线图要由业务需求驱动,不能反过来让业务等中台排期。落地诀窍就是一条:服务的边界跟着团队的边界走,而不是反着来。