Skip to content

SpringCloud微服务架构面试题库 ​

生成时间:2026-05-21 21:39


【面试题】1. Nacos作为注册中心同时支持AP和CP模型,它是如何切换的?底层实现原理是什么? ​

【标准答案】Nacos通过临时实例和持久化实例来区分AP与CP模型。临时实例(ephemeral=true,默认)走AP模式,采用Distro协议——这是一种类似Gossip的最终一致性协议,写操作优先写到本地,然后异步同步给其他节点,不强求所有节点即时一致,但保证了可用性。持久化实例(ephemeral=false)走CP模式,采用Raft协议——写操作必须经过Leader节点,多数节点确认后才返回成功,保证强一致性。切换方式很简单:服务注册时设置ephemeral参数即可,也可以在配置文件中全局指定。实际选型上,业务服务一般用临时实例(AP),因为服务上下线频繁,可用性更重要;数据库、中间件等基础设施用持久化实例(CP),因为这类节点少且不能丢失。面试中如果被追问Raft细节,重点说Leader选举和日志复制两个核心流程就够了。

【面试题】2. Sentinel的滑动窗口限流算法具体是怎么实现的?和令牌桶、漏桶有什么本质区别? ​

【标准答案】Sentinel默认用滑动窗口(LeapArray)做统计:把一个时间窗口(比如1秒)分成多个格子(默认2个,每格500ms),每个格子维护一个计数器,统计QPS时把当前窗口内所有格子的计数加起来。滑动窗口的本质是"固定窗口的改良"——解决了固定窗口在边界处流量翻倍的问题,但粒度受格子数量限制,格子越多越精确但内存开销越大。三者本质区别:滑动窗口统计的是"过去一段时间内的请求数",是直接计数,属于统计型限流;令牌桶是"以固定速率往桶里放令牌,请求拿令牌",允许一定突发流量(桶里有存量令牌时可以瞬间消费);漏桶是"请求进桶,以固定速率流出",严格匀速,不允许任何突发。所以:要允许突发用令牌桶,要严格匀速用漏桶,要做精确统计用滑动窗口。Sentinel选择滑动窗口是因为它最适合做流量监控和规则判断的统计基础,配合排队等待模式也可以实现匀速效果。

【面试题】3. OpenFeign的超时和重试配置在实际生产中怎么设置才合理?有哪些坑? ​

【标准答案】OpenFeign超时分两层:connectTimeout(建立连接超时)和readTimeout(读取数据超时)。配置优先级是:特定服务配置 > 全局默认配置。生产建议:connectTimeout一般设2-3秒足够(网络正常建连很快),readTimeout根据接口P99响应时间设,普通查询3-5秒,批量操作10-30秒。重试配置要特别小心:默认情况下Ribbon的重试是关闭的,但如果你手动开启了重试(retryableStatusCodes或MaxAutoRetries),一定要配合非幂等接口排除——POST/PUT等非幂等请求重试可能导致数据重复写入!正确做法是:1)对GET请求可以开1次重试;2)对非幂等接口禁止重试或用Retryer.NEVER_RETRY;3)切换实例重试(MaxAutoRetriesNextServer)默认1次是合理的,但也要评估下游能否承受。还有一个坑:Feign的超时和Ribbon的超时会取较小值,如果两边都配了可能以你没想到的为准,建议统一在一处配置,推荐用Feign的配置项。

【面试题】4. Seata的AT模式两阶段提交具体执行流程是什么?全局锁是怎么工作的? ​

【标准答案】AT模式是Seata最常用的模式,对业务零侵入,核心靠undo_log回滚日志表。一阶段:业务SQL执行前,Seata拦截并解析SQL,查询修改前的数据(beforeImage),执行业务SQL,再查询修改后的数据(afterImage),生成undo_log记录写入业务库的undo_log表,然后获取全局锁(向TC注册分支事务锁),最后提交本地事务。二阶段提交:TC通知各分支提交,各分支异步清理undo_log即可(因为一阶段已经提交了本地事务,非常快)。二阶段回滚:TC通知各分支回滚,分支根据undo_log的beforeImage反向补偿,同时要校验afterImage和当前数据是否一致(脏写校验),一致才回滚,不一致说明被其他事务改了,需要人工介入。全局锁机制:一阶段本地事务提交后,会向TC申请该行数据的全局锁,其他全局事务要修改同一行必须等锁释放,这就保证了读已提交的隔离性。但本地事务不受全局锁约束,所以AT模式是"读已提交"级别,不是串行化,极端场景可能脏读。面试要点:AT模式性能好(一阶段就提交),但牺牲了严格隔离性;适合大部分业务场景,不适合对一致性要求极高的金融核心链路。

【面试题】5. Spring Cloud Gateway的过滤器链执行顺序是怎样的?如何实现统一的鉴权和日志记录? ​

【标准答案】Gateway过滤器分三种:GlobalFilter(全局生效)、GatewayFilter(绑定到特定路由)、DefaultFilter(配置层面的默认过滤器)。执行顺序由Ordered接口的order值决定,值越小越先执行,pre阶段按order从小到大,post阶段按order从大到小(即先进后出,类似栈)。实际执行流程:请求进入 → 路由匹配 → 执行所有过滤器的pre逻辑 → 转发到下游服务 → 执行所有过滤器的post逻辑 → 返回响应。鉴权实现:写一个GlobalFilter,order设为最小值(如-1)确保最先执行,在pre阶段从请求头取Token,校验JWT签名和过期时间,校验通过则放行(可以在header中追加用户信息传递给下游),校验失败直接setComplete()返回401。日志记录也是GlobalFilter,在pre阶段记录请求信息(方法、路径、时间戳),在post阶段记录响应状态码和耗时。注意坑点:1)GlobalFilter的order不能和框架内置的冲突(如NettyRoutingFilter是Integer.MAX_VALUE);2)不要在过滤器中做阻塞操作,必须用异步方式;3)ServerWebExchange的attributes可以跨过滤器传数据。

【面试题】6. Redis分布式锁用Redisson实现时,看门狗机制是怎么工作的?什么情况下看门狗会失效? ​

【标准答案】Redisson的看门狗(Watchdog)解决的是锁过期但业务还没执行完的问题。当你不指定leaseTime(锁持有时间)时,Redisson默认锁30秒,同时启动一个定时任务(Watchdog),每10秒(30秒的1/3)检查一次:如果持有锁的客户端还活着且锁还被持有,就自动续期到30秒。这样只要业务还在执行,锁就不会过期。看门狗失效的场景:1)手动指定了leaseTime——Redisson认为你自己管理过期时间,不会启动看门狗;2)客户端宕机或进程被kill——看门狗是客户端侧的定时任务,进程没了自然不续期,锁30秒后自动释放(这正是期望行为);3)网络分区导致Redis连接断开——续期命令发不出去,锁会过期;4)业务线程被长时间阻塞(如Full GC、死锁)——虽然客户端还活着,但业务卡住了,如果后续拿到锁继续执行可能导致问题。面试加分点:Redisson还实现了可重入锁(hash结构,field是线程ID,value是重入次数),以及公平锁、读写锁、联锁(MultiLock)等。RedLock算法用于多Redis实例场景,但Martin Kleppmann曾质疑其安全性,面试中可以提这个争议。

【面试题】7. Spring Cloud Sleuth的TraceId和SpanId在服务间调用时是怎么传递的?跨线程场景如何处理? ​

【标准答案】Sleuth在服务间传递追踪信息靠的是HTTP请求头,核心三个头:traceId(全局唯一,贯穿整条调用链)、spanId(当前跨度ID)、parentSpanId(父跨度ID)。调用链路:请求到网关时Sleuth生成traceId和spanId → 通过Feign/RestTemplate发起下游调用时,Sleuth自动拦截请求,把这三个头塞进HTTP Header → 下游服务收到请求后,Sleuth从Header中提取traceId继续沿用,生成新的spanId,parentSpanId设为上游的spanId。这样整条链路的traceId一致,spanId串联起来就构成了调用树。跨线程场景:默认情况下线程切换会丢失追踪上下文,因为ThreadLocal不跨线程。Sleuth提供了两种方案:1)@NewSpan注解——在新线程的方法上标注,Sleuth会自动包装;2)手动包装——用Tracer对象获取当前Span,传给新线程,在新线程中用Tracer继续作用域。更推荐的做法是用Spring的TaskDecorator装饰线程池,Sleuth提供了LazyTraceExecutor,包装你的线程池后自动传递上下文。实际生产中,异步场景的链路断裂是很常见的问题,排查时要注意。

【面试题】8. Nacos Config的配置热更新原理是什么?和Spring Cloud Config相比各有什么优劣? ​

【标准答案】Nacos Config热更新有两种机制:1)长轮询(Long Polling)——客户端发起长轮询请求,服务端如果配置没变就hold住连接最多30秒,期间配置变更则立即返回;客户端收到变更通知后拉取最新配置。2)UDP推送——服务端配置变更后主动推送给客户端,作为长轮询的补充,减少延迟。实际是两种结合:长轮询保证可靠性,UDP加速通知。与Spring Cloud Config对比:Nacos Config天然支持热更新,配置变更秒级生效;Spring Cloud Config需要依赖Git Webhook + /actuator/bus-refresh手动触发或集成Spring Cloud Bus(MQ)广播,热更新链路长且不够实时。Nacos Config有自带管理界面,配置增删改查可视化;Spring Cloud Config依赖Git,配置管理就是Git操作,对运维不太友好。但Spring Cloud Config的优势是天然Git版本管理,回滚就是git revert,审计就是git log,合规性要求高的企业更倾向;Nacos Config也有历史版本功能但不如Git原生。另外Nacos是注册中心+配置中心一体,架构简洁;Spring Cloud Config需要独立部署Config Server,生产环境还要配高可用,运维成本更高。

【面试题】9. 微服务架构下,API网关如何实现灰度发布?有哪些具体的实现方案? ​

【标准答案】灰度发布核心思路:根据请求特征(用户ID、地区、版本号等)将流量路由到不同版本的服务实例。网关层面有三种常见方案:1)基于路由权重——Spring Cloud Gateway可以给同一个服务不同版本配置不同权重,如v1权重80%、v2权重20%,网关按比例随机路由。实现方式是在路由的metadata中设置版本标签,配合WeightedServiceInstanceListSupplier做负载均衡。2)基于请求特征路由——在GatewayFilter中解析请求头/Cookie/参数,根据规则动态路由到指定版本。比如Header中version=2.0就路由到v2实例,否则走v1。Nacos的元数据(metadata)可以标记实例版本,Gateway结合负载均衡器按metadata过滤实例。3)基于Service Mesh——Istio的VirtualService和DestinationRule可以精细控制流量比例和匹配规则,不需要改业务代码,但引入了Mesh的复杂度。生产建议:简单灰度用方案1(权重),精细灰度用方案2(特征路由),大规模多服务协同灰度用方案3。关键注意点:灰度期间数据库变更必须兼容(只加字段不删改),缓存Key要带版本号避免串数据,灰度比例要能动态调整(Nacos配置中心改配置即可)。

【面试题】10. Spring Cloud Alibaba全家桶中,Nacos、Sentinel、Seata三者如何协同工作实现完整的微服务治理?请描述一个完整的请求流转场景。 ​

【标准答案】三者协同构成了"注册发现+流量防护+事务保障"的完整治理体系。完整请求流转:用户请求到达Gateway → Gateway从Nacos获取订单服务实例列表(注册发现)→ 请求经过Sentinel网关限流规则检查(流量入口防护)→ 路由到订单服务 → 订单服务通过Feign调用库存服务(Feign集成Sentinel,调用超时或异常触发降级)→ 库存服务扣减库存 → 订单服务再调用支付服务 → 支付成功,三步操作通过Seata AT模式保证分布式事务一致性(订单创建、库存扣减、支付记录任一失败全部回滚)。每个环节的治理点:Nacos负责服务注册与发现、配置热更新、健康检查,是基础设施层;Sentinel负责流量控制(网关限流)、熔断降级(服务间调用保护)、热点参数限流(防刷)、系统保护(自适应流控),是流量防护层;Seata负责分布式事务一致性,是数据一致性层。三者的集成配置要点:1)Nacos作为Seata的注册中心和配置中心(Seata Server注册到Nacos,事务分组映射到Nacos集群);2)Sentinel的数据源配置到Nacos(流控规则持久化到Nacos,避免重启丢失);3)Sentinel的@SentinelResource注解配合Seata的事务注解使用时,注意降级方法不要参与分布式事务回滚。这套全家桶的优势是一站式解决微服务三大核心问题(发现、防护、一致性),且都由阿里维护,兼容性好、中文文档全。