Skip to content

微服务面试题 - 2026-06-19 19:29 ​

生成时间:2026-06-19 19:29 | 共 10 题 | 难度递进(基础→进阶→高阶)


【面试题】1. 微服务拆分时,"按组织架构拆分"听起来很玄学,但这背后其实是康威定律。康威定律到底说的是什么?它为什么能指导微服务边界划分? ​

【标准答案】康威定律的核心就一句话:系统的架构一定会复刻团队的沟通结构。如果两个团队天天扯皮、沟通成本很高,那他们负责的模块之间边界一定模糊、耦合一定重。反过来推导就是——你想让系统边界清晰,先把团队边界划清晰。实际操作就两步:第一,先画组织架构图,每个小团队认领一个限界上下文;第二,团队之间能异步协作就异步协作,别什么事情都拉会对齐。所以微服务拆分不是技术问题,是组织问题。面试官爱听你说"拆分服务前先看团队能不能独立交付",这比讲 DDD 概念打动多了。

【面试题】2. 服务注册中心的健康检查有"客户端心跳上报"和"服务端主动探测"两种模式。它们各自的优缺点是什么?Nacos 和 Consul 分别用哪种? ​

【标准答案】客户端心跳上报就是服务自己每隔几秒告诉注册中心"我还活着",Nacos 用这个。好处是轻量,不占用注册中心的网络探测带宽;缺点是如果服务线程卡死但心跳线程还活着,会出现"假活"。服务端主动探测是注册中心定期去 ping 服务实例的健康端点,Consul 用这个。好处是探测结果更真实;缺点是当实例数量上万时,探测压力全压在注册中心上,会打爆。生产上 Nacos 采用的是客户端心跳 + 临时实例机制,客户端不续约就自动踢掉,简单可靠。你被问到的时候,多提一句:选型不是非此即彼,大厂做法是双检——客户端心跳做基础、外部监控做兜底。

【面试题】3. 服务网关本身就是所有流量的入口,一旦宕机整个系统不可用。网关的高可用部署方案有哪些?怎么做到扩缩容时不丢流量? ​

【标准答案】网关的高可用核心是"无状态 + 前端负载均衡"。设计方案:网关本身不存任何业务状态,所有路由规则从配置中心动态拉取。前面挂一层 Nginx/LVS 或者直接用 K8s 的 Service 做四层负载,网关可以水平扩缩。关键点在于优雅下线——网关要下掉的时候,先通知前端的负载均衡把自己摘掉,然后等待正在处理的请求全部返回再真正关机。Spring Cloud Gateway 的 server.shutdown=graceful 配合 K8s 的 preStop hook 就能实现。面试官想听到你关注的点是:网关扩缩容不是单纯加减 Pod,必须配合前端的健康检查和摘流机制,否则就会出现 502。

【面试题】4. 配置中心做灰度发布是什么原理?比如我想先把一个数据库连接池参数的改动只推给 10% 的实例验证,怎么做? ​

【标准答案】配置灰度的核心是"标签路由 + 配置版本管理"。Apollo 的做法:给实例打标签(比如 tag=canary),然后在配置发布时选择"灰度发布"、指定匹配的标签,只推给这批灰度实例。Nacos 的做法类似,通过配置的灰度发布功能指定 IP 列表或标签。实际操作流程:先发灰度配置→观察监控指标 5-10 分钟→确认没问题再全量发布→有问题一键回滚到上一个版本。面试时最重要的加分点是——你提一嘴配置中心必须支持"版本回滚",灰度的自信来源于可以秒级回退,不是来源于灰度本身。没有回滚能力的灰度发布就是自欺欺人。

【面试题】5. 面试官常问"CAP 怎么选",但很多人上来就说 CP 或 AP。其实分区容错 P 在分布式系统中是必然发生的,真正的选择只有 CP 和 AP。请用两个具体业务场景说明:什么场景必须 CP、什么场景可以 AP?架构上怎么实现这个选择? ​

【标准答案】CP 的典型场景是银行账户余额——不看到最新的余额就不能让你转账,宁愿暂时不可用也不能让数据错。实现方式上,用 Raft 协议保证强一致性(如 etcd/TiKV),写操作必须过半节点确认。AP 的典型场景是社交媒体的点赞数——你看到 999 还是 1001 个赞根本无所谓,但不能因为几个节点挂了就看不到帖子。实现上,用最终一致性模型(Gossip 协议),允许短暂不一致。关键认知:CAP 不是"系统选 CP 还是 AP",而是"每一次操作按什么策略处理"。一个系统里可以有 CP 操作(转账)也有 AP 操作(查询用户昵称),用不同的一致性级别处理不同业务。

【面试题】6. 可靠消息最终一致性方案里,本地消息表是怎么工作的?如果定时任务扫到一条未投递的消息,但下游服务挂了,这条消息会怎么被处理? ​

【标准答案】本地消息表的做法:业务操作和消息记录在同一个本地事务里写入,比如"创建订单 + 插入一条消息记录(状态=待投递)",保证原子性。然后一个独立的定时任务轮询本地消息表,把待投递的消息发到 MQ。发送成功则更新状态为已完成,失败则重试。重试机制有指数退避——第一次失败等 1 秒、第二次等 2 秒、第 N 次等 N×2 秒。超过最大重试次数后标记为"投递失败"并告警,人工介入。关键设计点两个:一是消息表要有唯一业务 ID 做幂等,下游消费端必须做幂等处理;二是定时任务的扫描分页不能太大,单次扫 100 条左右就够了,避免和业务抢数据库连接。面试官最看重的是你对"幂等"和"重试边界"的理解。

【面试题】7. 服务雪崩是怎么一步一步传播的?从第一个服务变慢到最终全站崩溃,中间的传播路径是怎样的?每一层有什么阻断手段? ​

【标准答案】雪崩的传播链条:A 服务变慢→调用 A 的 B 服务的线程被 A 占住不释放→B 的线程池打满→调用 B 的 C 服务也跟着超时→C 的线程池也打满→一层层传导下去,几分钟内全站不可用。阻断手段对应每一层:第一道是超时——A 服务自己设好合理的超时时间,别让调用方无限等;第二道是熔断——B 发现调 A 连续失败,直接熔断、快速失败,不清空自己的线程池;第三道是限流——即使 B 熔断了,C 对 B 的调用也要限制并发数,防止 B 恢复时被瞬间流量冲垮;第四道是降级——返回兜底数据而不是抛异常。面试官会追问"你实际设置过哪些参数",你就说:连接超时 1 秒、读取超时 2 秒、熔断的 minimumRequestCount 设 10、错误率阈值 50%。

【面试题】8. 雪花算法生成的 ID 依赖机器时钟,如果时钟回拨了怎么办?美团的 Leaf 和百度的 UidGenerator 分别怎么解决这个问题的? ​

【标准答案】雪花算法时钟回拨是最经典的坑。解决方案有三条路线:第一条,抛异常等恢复——检测到时钟回拨直接拒绝生成、等时钟追上来再恢复,简单但粗暴,不适合高并发;第二条,借用未来的号段——美团 Leaf 的雪花模式,如果时钟回拨了,就临时借用上一个毫秒还没用完的号段继续发号,毫秒内 sequence 耗尽才等待;第三条,不依赖时钟——百度的 UidGenerator 用的是数据库号段预分配 + 本地缓存,完全不依赖机器时钟,从根源上就回避了时钟回拨问题。面试亮点是你能说出三种方案的适用场景:中小项目随便用原生雪花算法 + NTP 时间同步就够;大厂高并发场景上 Leaf 或 UidGenerator;金融级的再考虑用递增序列号。

【面试题】9. SkyWalking 号称"零代码侵入"就能采集链路追踪数据,它底层是怎么做到的?Java Agent 的字节码增强是什么原理? ​

【标准答案】SkyWalking 的核心是 Java Agent 技术。JVM 启动时加载一个 skywalking-agent.jar,通过 -javaagent 参数注入。Agent 利用 JVM 的 Instrumentation API,在类加载时拦截字节码,对目标方法做"插桩"——比如在 Spring MVC 的 DispatcherServlet.doDispatch() 方法前后插入埋点代码,自动记录入口 Span。对 Dubbo、Feign 这些远程调用框架也一样,拦截它们的发送和接收方法,自动创建 Exit Span 和 Entry Span,然后拼接成一条完整的 Trace。整个过程对业务代码完全透明,你一行代码不用写。面试官想听到的加分点是:你清楚 Agent 只修改框架层和中间件层的字节码,不修改业务类的字节码,所以不会引入诡异的业务 bug。

【面试题】10. 凌晨三点,告警群里炸了——"订单服务大量 5xx、注册中心显示一半实例被踢下线"。你一查发现是订单服务的 JVM 发生了 Full GC,每次 GC 停顿超过 15 秒,导致心跳超时被 Nacos 摘除。你怎么快速止血?根本原因怎么排查? ​

【标准答案】止血分三步:第一步,把被踢掉的实例强制恢复上线(Nacos 控制台手动改实例状态),或者紧急扩容两台实例先顶住流量;第二步,加启动参数 -XX:+DisableExplicitGC 防止业务代码里有人调了 System.gc();第三步,导出 heap dump 和 GC 日志,重启。根本原因排查:看 GC 日志定位是 Young GC 频繁还是 Full GC 频繁。如果是 Full GC 频繁,用 MAT/JProfiler 分析 heap dump,常见原因就三个——大对象分配(比如一次性查几万条数据返回)、内存泄漏(ThreadLocal 没清理、静态集合一直往里塞)、元空间满了(动态生成太多类)。监控层面的改进:Grafana 加一个 GC 停顿时间告警,停顿超过 5 秒就预警,别等心跳超时才发现。面试官想听的是你的"止血优先、事后复盘"的思路,而不是上来就分析 GC 算法。