本轮 SpringCloud微服务架构面试题库(带答案)
【面试题】1. Eureka的自我保护机制是什么?生产环境要不要开启?
【标准答案】自我保护机制是Eureka Server在运行期间统计心跳失败比例,如果15分钟内超过85%的节点没有续约,Eureka Server会认为网络出了问题而不是服务挂了,于是不再剔除过期实例,保护注册表信息不丢失。核心思想是"宁可保留可能不健康的服务,也不盲目剔除可用服务"。生产环境建议开启,因为微服务环境下网络抖动很常见,如果关闭自我保护,一次网络闪断就会导致大面积服务被剔除,引发雪崩。但要注意配合客户端的负载均衡重试机制一起用,即使注册表里有少量失效实例,调用方也能通过重试其他节点恢复。
【面试题】2. Sentinel的滑动窗口限流算法是怎么实现的?和令牌桶有什么区别?
【标准答案】Sentinel默认用滑动窗口统计QPS,它把一个时间窗口(比如1秒)划分成多个小格子(默认500ms一个),每个格子独立计数,滑动时只看当前窗口内所有格子的总和。格子越细,统计越平滑,但内存开销越大。和令牌桶的区别:滑动窗口是统计过去的请求数来判断是否超限,属于"事后统计型";令牌桶是预先以固定速率往桶里放令牌,请求拿到令牌才能通过,允许一定的突发流量(桶里有积蓄的令牌时可以瞬间消费)。滑动窗口更严格,不会有突发放行;令牌桶更灵活,适合允许短时突发的场景。Sentinel也支持令牌桶和漏桶,但默认滑动窗口。
【面试题】3. Seata的AT模式执行流程是怎样的?有什么局限性?
【标准答案】AT模式是Seata最常用的模式,对业务零侵入。流程:一阶段——业务SQL执行前,Seata拦截并查询修改前的数据生成before-image,执行业务SQL,再查询修改后的数据生成after-image,组成undo_log写入本地表,然后提交本地事务。二阶段提交——TC通知提交,异步删除undo_log即可,非常快。二阶段回滚——TC通知回滚,根据undo_log的before-image反向补偿,生成反向SQL恢复数据,然后删除undo_log。局限性:①只能用于关系型数据库,依赖SQL解析和undo_log;②全局锁机制会导致热点数据性能下降,因为一阶段本地事务提交后全局锁不释放,其他全局事务写同一行数据要等;③脏读问题,一阶段已提交的本地事务对其他非分布式事务可见但可能被回滚;④SQL支持有限,复杂SQL可能解析失败。
【面试题】4. Spring Cloud Gateway的过滤器链执行顺序怎么控制?全局过滤器和局部过滤器有什么区别?
【标准答案】过滤器执行顺序通过实现Ordered接口或@Order注解控制,数值越小优先级越高。Gateway的过滤器链分三段:pre阶段按order从小到大执行,post阶段按order从大到小执行,形成洋葱模型。全局过滤器(GlobalFilter)对所有路由生效,不需要配置,比如鉴权、限流、日志;局部过滤器(GatewayFilter)只对指定路由生效,在路由配置中通过filters或defaultFilters指定。实际开发中,鉴权和跨域用全局过滤器,业务相关的比如请求头改写、路径重写用局部过滤器。如果需要在局部过滤器里做优先级控制,用OrderedGatewayFilter包装。
【面试题】5. Nacos作为配置中心,配置热更新的原理是什么?@RefreshScope和Nacos监听器有什么区别?
【标准答案】Nacos配置热更新的核心是长轮询机制。客户端启动时向Nacos Server发起长轮询请求(默认30秒超时),服务端如果发现配置变更会立即返回,否则hold住直到超时再返回,客户端收到响应后再次发起长轮询,如此循环。这样配置变更的感知延迟在1秒以内。使用方式两种:①@RefreshScope注解加在类上,配置变更时Spring销毁并重建该Bean,@Value注解的字段会重新注入新值;②通过Nacos监听器手动注册Listener,在onChange回调里处理变更逻辑。区别:@RefreshScope是Spring Cloud的标准方式,整个Bean重建,适合配置变更后需要完整重新初始化的场景;监听器方式更细粒度,只更新需要的字段,性能更好,但需要自己写变更逻辑。生产环境推荐监听器方式,避免Bean重建带来的性能开销和并发问题。
【面试题】6. Redis分布式锁用SET NX EX有什么问题?Redisson是怎么解决的?
【标准答案】SET NX EX的问题是:①锁续期问题——如果业务执行时间超过锁的过期时间,锁自动释放,其他线程拿到锁导致并发冲突;②锁误删——线程A的锁过期后被线程B拿到,线程A执行完后误删了线程B的锁;③不可重入——同一线程无法对同一把锁多次加锁。Redisson的解决方案:①看门狗机制——默认锁30秒过期,后台线程每10秒(过期时间的1/3)自动续期,业务没执行完就一直续,执行完停止续期;②锁value用UUID+线程ID唯一标识,释放时用Lua脚本判断是不是自己的锁,是才删除,保证原子性;③用Redis Hash结构实现可重入,key是锁名,field是UUID+线程ID,value是重入次数,加锁value+1,解锁-1,到0才删除。这三个问题都是生产环境真实踩坑点,面试必问。
【面试题】7. OpenFeign的超时重试配置怎么设置?有哪些坑?
【标准答案】OpenFeign超时分两层:连接超时(connectTimeout)和读取超时(readTimeout),默认分别是10秒和60秒。配置方式:可以在FeignClient级别用@FeignClient(configuration=xxx.class)指定,也可以在配置文件里按服务名细粒度配置(feign.client.config.xxx.connectTimeout/readTimeout)。重试方面,OpenFeign默认不重试(Retryer.NEVER_RETRY),需要自定义Retryer。坑点:①如果同时用了Ribbon/LoadBalancer,Feign的超时会和Ribbon的超时叠加,实际生效的是Ribbon的配置(旧版本),新版本Spring Cloud LoadBalancer下以Feign配置为准;②重试+非幂等接口=灾难,POST请求重试可能导致重复创建数据,必须确保重试只对幂等接口生效;③超时设太短容易误触发重试,设太长影响用户体验,建议读超时根据P99响应时间设置,连接超时1-3秒即可。
【面试题】8. 微服务之间如何安全地传递Token?网关鉴权和服务间调用鉴权怎么设计?
【标准答案】分两层设计。第一层网关鉴权:所有外部请求先到网关,网关校验JWT的签名和有效期,校验通过后把用户信息(userId、role等)放入请求头转发给下游服务,不再传原始JWT避免下游重复解析。第二层服务间调用鉴权:内部服务之间互调用Trusted Header或Service Token。方案一:网关转发时在Header里加X-User-Id、X-User-Role等内部信任头,下游服务直接读取,但前提是内网隔离,外部无法伪造;方案二:每个服务启动时向认证中心申请一个Service Token(类似机器人的JWT),服务间调用时带上Service Token,被调用方校验Token确认调用方身份和权限。关键点:内部信任头必须通过网络策略保证只有网关能设置,服务间不能伪造;Service Token有效期要短,定期轮换;敏感操作要二次校验用户Token而不是只信任Header。
【面试题】9. Zipkin链路追踪的采样策略怎么选?对性能有什么影响?
【标准答案】Zipkin的采样策略核心是控制多少比例的请求被追踪。常见策略:①始终采样(AlwaysSample)——100%采集,适合低流量测试环境,生产环境不推荐;②概率采样(ProbabilityBased)——按比例采样,比如1%或0.1%,适合高流量生产环境;③限速采样(RateLimitingSampler)——每秒最多采集N条,Sleuth支持,流量平稳可控。性能影响:每条Span的采集涉及生成TraceId/SpanId、向Zipkin Server上报(HTTP或Kafka)、以及可能的数据序列化开销。实测1%采样对P99延迟影响在1ms以内,100%采样在高并发下可能导致5-10ms延迟增加和可观的带宽消耗。选型建议:生产环境用概率采样0.1%-1%或限速采样每秒10-50条,出问题时临时调高采样率排查,排查完调回来。上报方式优先用Kafka异步上报,避免HTTP同步上报阻塞业务线程。
【面试题】10. Kubernetes部署微服务和传统虚拟机部署相比,服务注册发现有什么变化?Spring Cloud Kubernetes怎么用?
【标准答案】传统部署用Eureka/Nacos做服务注册发现,服务启动时主动注册,调用方从注册中心拉取地址。K8s部署后多了一个选择——用K8s原生的Service+DNS做服务发现:每个微服务部署为Deployment,暴露为Service,K8s集群内通过<service-name>.<namespace>.svc.cluster.local直接DNS解析,不需要额外注册中心。Spring Cloud Kubernetes就是桥接Spring Cloud和K8s原生能力:①用K8s Service替代注册中心,配置spring.cloud.kubernetes.discovery.enabled=true,Spring Cloud自动从K8s API获取Service列表作为服务实例;②用K8s ConfigMap/Secret替代配置中心,spring.cloud.kubernetes.config.enabled=true自动读取;③用K8s的健康检查替代Spring Boot Actuator。优势:少维护一套注册中心和配置中心,架构更简单。劣势:强依赖K8s,本地开发调试不方便;跨集群调用还是要注册中心。实际很多团队选择K8s内用原生Service发现,跨集群用Nacos,两者共存。