本轮 SpringCloud微服务架构面试题库(带答案)
生成时间:2026-05-21 21:24
【面试题】1. Eureka的自我保护机制是什么?什么场景下会触发?生产环境要不要关闭?
【标准答案】Eureka的自我保护机制是一种容错设计,核心思想是:宁可保留错误的服务注册信息,也不要盲目注销任何健康服务。
触发条件:当Eureka Server在短时间内丢失超过85%的心跳(默认阈值),会认为网络分区故障发生了,此时进入自我保护模式,不再剔除任何服务实例。
为什么需要它:如果Eureka Server和微服务之间网络抖动,但服务本身是健康的,没有自我保护的话,服务会被错误剔除,导致服务不可用。有了自我保护,即使心跳丢失,服务注册信息仍会保留,等网络恢复后服务继续可用。
生产环境建议:不建议关闭。虽然自我保护会导致下线服务仍显示在注册表中,但相比错误剔除健康服务,这个代价是可接受的。可以通过调整阈值(eureka.server.renewal-percent-threshold)来优化触发灵敏度。
【面试题】2. Ribbon有哪些负载均衡策略?实际项目中怎么选择?
【标准答案】Ribbon提供7种核心策略:
常用策略:
- 轮询(RoundRobin):默认策略,按顺序依次调用,适合服务器性能相近的场景
- 随机(Random):随机选择,简单但分布不够均匀
- 加权轮询(WeightedResponseTime):根据响应时间动态分配权重,响应快的节点获得更多请求,适合服务器性能不均的场景
- 最少并发(BestAvailable):选择并发请求最少的实例,适合长连接场景
- 重试(Retry):在轮询基础上增加重试,适合对可用性要求高的场景
实际选型建议:
- 服务器性能相近:轮询即可
- 服务器配置差异大:加权轮询
- 接口响应时间差异明显:WeightedResponseTime自动调节
- 需要高可用:轮询+重试组合
自定义策略:实现IRule接口,在choose方法中编写自己的负载均衡逻辑,比如根据请求参数路由到特定服务实例(灰度发布场景)。
【面试题】3. OpenFeign的超时重试配置怎么做?有哪些坑需要注意?
【标准答案】超时配置:
ribbon:
ReadTimeout: 5000 # 读取超时
ConnectTimeout: 1000 # 连接超时
feign:
client:
config:
default:
connectTimeout: 1000
readTimeout: 5000重试机制:
- Ribbon默认重试:同一实例最大重试1次,切换实例最大重试1次(MaxAutoRetries=1, MaxAutoRetriesNextServer=1)
- 禁用重试:MaxAutoRetries=0, MaxAutoRetriesNextServer=0
常见坑点:
- 双重超时问题:如果用了Hystrix,Hystrix的超时要大于Ribbon超时+重试次数,否则Ribbon还在重试,Hystrix已经熔断了
- 幂等性问题:重试只适合GET请求,POST请求重试可能导致重复提交,需要业务层做幂等处理
- 重试风暴:如果下游服务响应慢,大量请求重试会放大压力,需要合理配置重试次数
- 配置不生效:Ribbon配置要放在application.yml,而不是bootstrap.yml,且必须在服务启动前加载
【面试题】4. Sentinel的限流算法有哪些?各自适用场景是什么?
【标准答案】Sentinel支持三种核心限流算法:
1. QPS限流(直接拒绝):
- 超过阈值直接拒绝,返回Blocked异常
- 适合API网关、秒杀场景,快速失败,保护系统不被压垮
2. 冷启动限流(Warm Up):
- 系统启动时缓慢增加流量,避免瞬间高并发压垮冷系统
- 阈值从阈值/3(默认)逐步提升到最大阈值
- 适合秒杀系统刚启动、缓存预热场景
3. 恒定等待限流(排队等待):
- 请求在队列中排队,匀速通过
- 适合削峰填谷,比如消息处理、定时任务
- 设置超时时间,超时后拒绝
限流模式选择:
- 直接拒绝:追求快速响应,允许部分失败
- Warm Up:保护冷系统,平滑启动
- 排队等待:请求必须全部处理,可以接受延迟
关联限流:当关联资源达到阈值时,限流当前资源。比如:查询接口和写入接口关联,写入繁忙时限流查询,保护数据库。
【面试题】5. Spring Cloud Gateway的过滤器链执行顺序是怎样的?如何自定义全局过滤器?
【标准答案】过滤器分类:
- 前置过滤器(Pre):请求转发前执行,如参数校验、鉴权、限流
- 后置过滤器(Post):响应返回后执行,如添加响应头、日志记录、跨域处理
- 全局过滤器(GlobalFilter):对所有路由生效
执行顺序:
- 过滤器通过order值排序,值越小优先级越高
- Pre过滤器按order升序执行
- Post过滤器按order降序执行(与Pre相反)
自定义全局过滤器示例:
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 验证token逻辑
return chain.filter(exchange); // 放行
}
@Override
public int getOrder() {
return 0; // order值越小越先执行
}
}关键点:
- GlobalFilter + Ordered接口实现
- chain.filter(exchange)表示放行,继续执行下一个过滤器
- return之前可以添加Post逻辑(通过Mono的then方法)
- 优先级高的过滤器要放在前面,比如鉴权在限流之前
【面试题】6. Nacos配置中心如何实现配置热更新?应用端需要做什么?
【标准答案】热更新原理:
Nacos配置热更新基于长轮询机制:
- 客户端向Nacos Server发起长轮询请求(默认30秒超时)
- 如果配置有变化,Server立即返回最新配置
- 如果无变化,请求挂起,直到超时或配置变更
- 客户端收到响应后,更新本地缓存,触发配置变更事件
应用端实现方式:
方式一:@RefreshScope注解
@RestController
@RefreshScope
public class ConfigController {
@Value("${app.config}")
private String config;
@GetMapping("/config")
public String getConfig() {
return config;
}
}- 加上@RefreshScope后,配置变更时Bean会重新创建,属性自动更新
- 注意:只支持@Value注解,不支持@ConfigurationProperties的类
方式二:配置监听器
@Component
public class ConfigListener implements ApplicationListener<NacosConfigReceivedEvent> {
@Override
public void onApplicationEvent(NacosConfigReceivedEvent event) {
// 配置变更时执行逻辑
String newConfig = event.getContent();
}
}注意事项:
- @RefreshScope有性能开销,Bean会被代理,按需使用
- 配置变更粒度:dataId维度,不支持单个属性监听
- 多环境配置:通过namespace和group隔离
- 灰度发布:结合元数据实现按比例推送
【面试题】7. Sleuth链路追踪如何生成和传递TraceId?采样策略怎么配置?
【标准答案】TraceId生成:
- Sleuth默认使用64位随机数生成TraceId
- 格式:16进制字符串,如:5e5a8c3d9f2e1b0a
- 整个调用链路唯一,贯穿所有服务
SpanId生成:
- 每个服务实例生成自己的SpanId
- 格式同TraceId,作用域为单个服务
传递机制:
- HTTP调用:通过HTTP Header传递(X-B3-TraceId、X-B3-SpanId)
- 异步消息:通过消息Header传递(MQ消息头)
- 框架自动完成传递,业务代码无感知
采样策略配置:
spring:
sleuth:
sampler:
probability: 0.1 # 采样率10%采样策略选择:
- 全采样(probability=1.0):适合测试环境,问题定位精准
- 低采样(probability=0.01~0.1):生产环境推荐,减少存储和性能开销
- 自定义采样:实现Sampler接口,根据业务逻辑决定是否采样
性能影响:
- 采样率100%:每个请求生成Trace/Span,有一定性能开销(内存、网络、存储)
- 采样率过低:可能遗漏问题请求,排查困难
- 建议:生产环境0.1~0.3,核心链路可以调高
【面试题】8. Seata的AT模式原理是什么?为什么推荐使用?
【标准答案】AT模式原理:
AT模式是Seata推荐的非侵入式分布式事务方案,核心机制:
一阶段:
- 执行业务SQL,记录数据快照(before image)
- 提交本地事务,释放锁
- 记录after image,生成回滚日志(undo log)
- 向TC(事务协调者)注册分支事务
二阶段:
- 全局提交:异步删除undo log,立即返回(性能高)
- 全局回滚:根据undo log反向生成SQL恢复数据
为什么推荐AT模式:
- 无侵入:业务代码无需修改,只需加注解@GlobalTransactional
- 性能好:一阶段本地提交,二阶段异步提交,锁持有时间短
- 简单易用:相比TCC不需要写三个接口(try/confirm/cancel)
- 支持主流数据库:MySQL、PostgreSQL、Oracle等
AT模式限制:
- 不支持多表关联的SQL(join)
- 需要主键
- 写隔离:需要全局锁,可能死锁
- 读隔离:默认读未提交,脏读风险(可配置读已提交)
适用场景:大多数业务系统,对一致性要求不是极端严格的场景。
【面试题】9. Redisson分布式锁的看门狗机制是什么?怎么防止锁过期?
【标准答案】看门狗机制:
Redisson分布式锁默认有过期时间(默认30秒),如果业务执行时间超过30秒,锁会自动释放,导致并发问题。看门狗机制就是为了解决这个问题。
工作原理:
- 加锁成功后,Redisson启动一个定时任务(看门狗)
- 每隔过期时间的1/3(默认10秒)检查一次锁
- 如果线程仍持有锁,自动续期(重置过期时间为30秒)
- 业务执行完毕,主动释放锁,看门狗停止
核心源码:
// 加锁时启用看门狗
RLock lock = redisson.getLock("myLock");
lock.lock(); // 默认启用看门狗,过期时间30秒手动设置过期时间:
lock.lock(10, TimeUnit.SECONDS); // 手动设置10秒过期
// 注意:手动设置过期时间会禁用看门狗防止锁过期的最佳实践:
- 业务执行时间不确定:使用默认lock(),让看门狗自动续期
- 业务执行时间确定且较短:手动设置过期时间,禁用看门狗减少开销
- 业务执行时间可能很长:看门狗+业务层超时控制,避免无限续期
常见坑:
- 忘记释放锁:使用try-finally确保unlock
- 看门狗失效:手动设置过期时间会禁用看门狗
- 锁重入:同一个线程多次加锁需要多次释放
【面试题】10. Spring Cloud Stream如何处理消息积压?有哪些优化策略?
【标准答案】消息积压原因:
- 消费速度低于生产速度
- 消费者处理逻辑慢(如数据库慢查询)
- 消费者实例数不足
- 消息堆积在Broker端
处理策略:
1. 增加消费者实例数
- 水平扩容:增加Pod数量
- 注意:实例数不能超过分区数(Kafka partition),否则多出的实例空闲
2. 提升单实例并发数
spring:
cloud:
stream:
bindings:
input:
consumer:
concurrency: 3 # 单实例开3个线程消费3. 异步处理+批量入库
- 消息异步处理,不阻塞主线程
- 批量插入数据库,减少IO次数
- 使用线程池控制并发
4. 降级策略
- 积压严重时,跳过非核心逻辑(如日志记录、统计)
- 持久化消息,延迟处理
5. 分区策略
- 根据业务key分区,保证同一key的消息有序
- 不同分区并行消费,提升吞吐
6. 监控告警
- 监控消费延迟(lag)
- 设置阈值告警,及时发现积压
最佳实践:
- 生产者:控制发送速率,不要超过消费者处理能力
- 消费者:处理逻辑要快,避免阻塞操作
- 架构:削峰填谷,合理设置队列容量和消费者数量
- 兜底:积压严重时,临时增加消费者实例,扩容后自动恢复
生成信息
- 生成时间:2026-05-21 21:24
- 题目数量:10道
- 知识点覆盖:服务注册与发现、负载均衡、服务调用、熔断限流、API网关、配置中心、链路追踪、分布式事务、分布式锁、消息队列