微服务面试题 - 2026-06-19 18:14
生成时间:2026-06-19 18:14 | 共 10 题 | 难度递进(基础→进阶→高阶)
【面试题】1. Nacos 的临时实例和持久实例有什么区别?什么时候注册临时、什么时候注册持久?
【标准答案】临时实例是 Nacos 默认模式——服务注册后靠心跳续约,心跳断了 Nacos 直接把它剔掉。持久实例不靠心跳,靠 Nacos 主动探测健康状态,挂了只会标"不健康"但不剔除。根本区别:临时实例是"客户端告诉你我还活着",持久实例是"服务端主动确认你还活着"。选型口诀:Spring Cloud 微服务用临时实例——服务挂了心跳自然停,秒级自动下线,干净利落。中间件(MySQL、Redis、Kafka)用持久实例——它们不会发心跳给 Nacos,但你不能因为它们不心跳就把它们从注册列表删了,得靠健康检查探活。DNS 模式也用持久实例——域名解析要把所有节点始终挂着。一句话:会主动上报心跳的用临时(应用层),不会主动上报的用持久(基础设施层)。坑:持久实例即使挂了不剔,调用方必须自己加熔断——不然请求打到挂了但还"健康"的实例上照样 502。
【面试题】2. CAP 理论说 P(分区容错)必须选,那到底有没有真正的 CA 系统?为什么说"放弃 P"本身就是伪命题?
【标准答案】CAP 理论说 C(一致性)、A(可用性)、P(分区容错性)三者只能同时满足两个。但"放弃 P"在分布式系统里是伪命题——因为网络分区不是"可选"的,是"必然发生"的。只要你有两台机器通过网络通信,网络延迟、丢包、断连就一定会发生——这不是你能决定的,是物理定律决定的。所以你只能在 CP 和 AP 之间选——当网络分区发生时,你是牺牲一致性(AP:允许短暂数据不一致,Nacos/Eureka 选这个)还是牺牲可用性(CP:拒绝部分请求保证数据一致,ZooKeeper 选这个)。那 CA 系统存在吗?存在——单机 MySQL/Oracle,一台机器没有网络通信,天然没有分区问题,C 和 A 都能满足。但一旦你把 MySQL 做成主从集群——网络断了主从之间数据不同步,你就得当机立断:是停写保一致性(CP)还是继续写但主从不一致(AP)。面试定音:分布式系统天生在 CP 和 AP 之间选,CA 只存在于单机系统——所以 CAP 与其说是定理不如说是架构选择的提醒:别天真地以为你两个都能要。
【面试题】3. Spring Cloud Gateway 的 Predicate 和 Filter 是怎么协作完成路由转发的?自定义一个"根据 Header 里的租户 ID 路由到不同服务"怎么写?
【标准答案】Gateway 的路由模型是一条流水线:请求进来→ Predicate 断言工厂匹配→ 命中 Route→ Filter 链处理→ 转发到下游。Predicate 管"这个请求归不归我管"——Path=/order/** 匹配路径、Header=tenant,abc 匹配租户 Header、After=2026-01-01 匹配请求时间。Filter 管"确定归我管之后怎么处理"——AddRequestHeader 加请求头、StripPrefix 去掉路径前缀、RequestRateLimiter 限流。自定义租户路由核心代码:用 RouteLocator + TenantRoutePredicateFactory。Predicate 里解析 request.getHeaders().getFirst("X-Tenant-Id"),匹配就返回 true。Filter 里把请求转发到 lb://order-service-{tenantId}——租户隔离的服务名按约定命名。整个链路:请求带 X-Tenant-Id: shanghai→ Predicate 匹配→ 转发到 order-service-shanghai。一句话总结:Predicate 是筛选器,Filter 是加工链——一个路由 = 一组 Predicate AND 条件 + 一串 Filter 顺序执行。坑:多个 Predicate 之间是 AND 不是 OR,如果要有"或"逻辑得写自定义 Predicate。
【面试题】4. 熔断器的关闭→打开→半开→关闭状态机是怎么工作的?半开状态为什么是熔断器最精妙的设计?
【标准答案】熔断器三部曲:关闭状态——正常放行所有请求,同时统计失败率。当失败率在你设的阈值上(比如 50% 的请求失败),熔断器从关闭→打开。打开状态——直接拒绝所有请求,快速失败,下游服务获得喘息恢复期。关键是打开了就永远关不上了吗?不——打开后有个"休眠窗口"(比如 30 秒),时间到了自动从打开→半开。半开状态——这才是精妙所在:放行少量请求(通常 1~3 个)做探测。如果探测成功→熔断器关闭,恢复正常;探测失败→重新打开,再来一轮休眠。为什么半开是精髓:没有半开你就不知道下游恢复了没有——要么一直开着硬等人工干预,要么开了就全放开结果瞬间又打挂。半开相当于"拿脚趾先试试水温",确认安全了再全身跳下去。三个开关参数:失败阈值(多少失败触发打开)、休眠窗口(开多久后探)、半开探测请求数(探几个)。面试一句:熔断状态机的本质是"受伤→关门养伤→探一下好没好→好了开门接客"——半开就是那个"探一下"。
【面试题】5. TCC 的 Try-Confirm-Cancel 三个阶段各干什么?空回滚和悬挂这两个分布式事务经典问题是什么意思、怎么防?
【标准答案】TCC 是"资源层面的两阶段提交":Try——预留资源,不放锁但把资源标记为"预占"(冻结库存、冻结余额),告诉协调者"我能搞定"。Confirm——协调者说全过了,各服务真正执行(库存真扣、钱真转),确认阶段必须幂等。Cancel——协调者说有服务失败了,各服务释放预占(解冻库存、解冻余额),也必须幂等。两个经典问题:空回滚——Try 还没执行或超时了,Cancel 却来了。比如网络抖动 Try 还在路上、协调者超时直接发 Cancel。这时 Cancel 不能当真去"解冻",因为压根没冻过——Cancel 要查一下 Try 的记录,Try 没执行过 Cancel 就空返回成功。悬挂——Try 在 Cancel 之后才到。Cancel 已经释放了资源,延迟的 Try 又来了又"预占"了一次,结果这预占永远不会被 Confirm 也不会被 Cancel。防法:Try 执行前查一下有没有 Cancel 记录,有的话拒绝——"你已经被否决了"。面试总结:TCC 比 Seata AT 复杂是因为你得手写每个阶段的补偿逻辑——但换来的是资源不挂锁、高并发下的最终一致性。空回滚和悬挂的本质是同一种坑:分布式环境的时序不确定性——先发的请求不一定先到。
【面试题】6. Apollo 和 Nacos 配置中心的核心差异在哪?为什么有些团队用了 Nacos 做注册中心还要单独搭 Apollo?
【标准答案】两个工具都能做配置中心,但基因不同。Nacos 是"注册中心 + 配置中心"二合一——一次部署两个活都干,Spring Cloud Alibaba 原生集成,中小团队零成本开箱。Apollo 是纯配置中心——携程出品,配置治理能力更强。核心差异五点:一、Apollo 有环境隔离 + 集群隔离 + Namespace 三层,Nacos 只有 namespace + group 两层——多环境多集群(dev/fat/uat/pro)时 Apollo 粒度更细。二、Apollo 的配置审核和发布审批机制——开发改配置→ leader 审核→ 灰度发布→ 全量,Nacos 没这流程。对金融、合规场景这是刚需。三、Apollo 的配置变更历史对比和回滚体验更成熟——diff 视图清晰。四、Apollo 客户端支持本地缓存文件——Nacos 也支持但 Apollo 的本地文件容灾策略更完善,配置中心全挂也能启动。五、Nacos 强在"动态服务发现"——同一个工具链管了注册和配置,运维成本低。为啥分开用:注册中心用 Nacos(AP 模式保证可用性),配置中心用 Apollo(精细权限控制 + 审批流)。面试定音:Nacos 是"够用就行",Apollo 是"管得精细"——团队超过 50 人、多环境多集群、配置变更要求审批,Apollo 值回部署成本。
【面试题】7. 一致性哈希在微服务负载均衡和分布式缓存中分别怎么用?为什么加一台缓存服务器只丢 1/N 的数据?虚拟节点又解决了什么?
【标准答案】一致性哈希解决了普通哈希"加一台机器全量数据重新分布"的灾难。普通哈希 hash(key) % N——3 台变 4 台,3/4 的 key 全换位置,缓存瞬间大规模 miss,DB 被打穿。一致性哈希把哈希空间弯成一个环(0~2^32-1),缓存节点按 IP 哈希映射到环上,key 也哈希到环上——key 顺时针找到的第一个节点就是它的归属。加一台新节点只影响它和顺时针下一个节点之间这一小段,其余所有 key 归属不变——所以只丢 1/N 的数据(N 是节点数)。虚拟节点解决节点分布不均匀——两台物理机间可能隔了半圈让一台扛了 70% 的流量。做法:每台物理机映射 150 个虚拟节点散落在环上,key 落到哪个虚拟节点就归属对应物理机——环上分布均匀,保证每台物理机平分流量。微服务里的一致性哈希两层场景:一、Gateway/LoadBalancer 的会话保持——同一 userId 的请求始终路由到同一实例(userId.hashCode() % 虚拟节点);二、分布式缓存的客户端分片——JedisCluster 和 Redisson 的分片路由也是这个原理。面试一句:一致性哈希的本质是把"重新分布"从全量变成局部——代价是加了虚拟节点这一层抽象。
【面试题】8. ZooKeeper 的临时顺序节点怎么实现分布式锁?为什么说 ZK 锁比 Redis 锁更安全?etcd 的 Lease 机制做了什么改进?
【标准答案】ZK 分布式锁流程:所有竞争者都在 /lock 下创建临时顺序节点,ZK 自动编号(/lock/0001, /lock/0002, /lock/0003)→ 每个节点看自己是不是序号最小的→ 是的拿到锁,不是的 watch 前一个节点→ 拿到锁的释放(删除节点或 session 断开)→ ZK 通知下一个等着的节点去竞争。ZK 锁比 Redis 锁安全的核心理由:ZK 是 CP 系统——Leader 宕机了不会脑裂,新选出的 Leader 保证数据一致。客户端 session 断了临时节点自动删除,锁自然释放——没有"客户端以为持了锁但锁已经过期"的问题。Redis 锁的主从异步复制 + 锁过期是阿克琉斯之踵。etcd 的改进:Lease 机制——锁绑定到一个租约,租约过期自动释放,不像 ZK 临时节点绑定 session(session 超时较长)。etcd 用 Raft 协议保证强一致,API 简洁(Go 语言原生 HTTP/gRPC),Watch 机制比 ZK 的 Watcher 一次性注册更友好。选型结论:对一致性要求最高且已有 ZK 基础设施→ ZK 锁;K8s 体系下→ etcd(K8s 本身就依赖 etcd,复用顺便锁);追求极致性能且能接受极小风险→ Redis(Redisson)。面试金句:分布式锁的安全性排序就是存储系统的强一致性排序——etcd(Raft) ≈ ZK(ZAB) > Redis(异步复制)。
【面试题】9. CQRS 的读写分离在微服务中怎么落地?Command 和 Query 各自用什么存储?读侧的数据延迟到底怎么处理?
【标准答案】CQRS 就是把"写"和"读"拆成两条独立通路——不是数据库主从这种物理层,而是架构层的彻底分离。Command 侧(写):接收命令(CreateOrder/CancelOrder),校验业务规则,执行写操作。数据存在写优化库——通常是关系型 DB(强一致、事务),只存最新状态。写完后发布领域事件 OrderCreated。Query 侧(读):监听领域事件,实时(或准实时)更新读模型。数据存在读优化库——ES/Solr(全文搜索)、MongoDB(文档查询)、甚至内存缓存。读侧的数据结构和写侧完全不同——按前端页面需求聚合好了,一个查询接口直接返回,不做 JOIN。数据延迟怎么处理:这是 CQRS 的核心代价。三种策略:一、同步双写——Command 写 DB 后同步更新 ES,延迟 0 但写入慢了;二、异步事件投影——写 DB 后发 MQ 异步更新 ES,延迟几百 ms 但写入快;三、"意向标记"——前端 POST 后立刻返回 202,页面加 polling/"处理中"状态,等 Query 侧就绪了再刷新。大部分业务选异步事件投影——几百 ms 延迟用户无感知,写入性能不能牺牲。面试定音:CQRS 不是"要不要做"的问题,是"复杂到什么程度才值得做"——只有读和写的模型已经严重冲突的时候才上。你一个查询要做 5 张表 JOIN,改一个字段要小心不要打破了查询——这时候就说明该拆了。
【面试题】10. 一个完全没有做防护的微服务系统,按什么优先级和顺序逐步建立起完整的稳定性防护体系?每一步解决了什么问题、如果跳过会有什么后果?
【标准答案】不走弯路的三步递进。第一步:服务注册的健康检查和下线(杀伤力最高、成本最低)。注册中心必须配健康检查 + 自动摘除不健康实例——如果这步没做,一个实例挂了所有请求还往里打,其他健康实例没事,但 1/5 的用户一直 502,其他 4/5 的用户感知不到——这比全挂还危险因为"以为系统是好的"但其实一批用户已经恼了。第二步:熔断 + 舱壁隔离(防止雪崩)。每个服务调用下游都要有熔断——失败率 > 50% 停调 30s。舱壁隔离为每个下游配独立线程池——支付线程池满了不影响积分线程池。跳过这步的后果就是文件 3 里提到的:一个服务变慢→ 上游线程全卡在等待→ 上游的上游也卡→ 整个系统多米诺。第三步:限流 + 降级(终极防线)。网关层限流保系统不超载(Sentinel 配好每个核心接口的 QPS 上限),服务层业务降级(压力大时关非核心逻辑)。限流不做就是洪水冲进来什么都拦不住。三步对应的防护哲学:健康检查 = 防火墙——挡住已死的;熔断舱壁 = 消防墙——火不蔓延;限流降级 = 防洪闸——超过承受力的不进。实施顺序反过来就是血泪教训——很多人上来就搞降级,结果一个服务挂了全集群还是跟着挂,因为连最基本的健康检查都没配。面试一句:稳定性防护跟建防震楼一样——地基(健康检查)→ 隔断墙(熔断舱壁)→ 承重限制(限流降级),顺序不能乱。
考点覆盖:服务注册与发现 | 分布式核心理论(CAP) | 服务网关 | 服务熔断 | 分布式事务(TCC) | 配置中心对比 | 负载均衡(一致性哈希) | 分布式锁(ZK/etcd) | 消息驱动架构(CQRS) | 服务雪崩防护体系