Skip to content

SpringCloud微服务架构面试题库 ​

生成时间:2026-05-21 22:45 题目数量:10道


本轮 SpringCloud微服务架构面试题库(带答案) ​

【面试题】1. Eureka的自我保护机制是什么?什么情况下会触发?生产环境如何处理? ​

【标准答案】自我保护机制是Eureka Server在短时间内丢失大量客户端心跳时,不再剔除服务实例的保护措施。触发条件是当每分钟心跳续租数低于阈值(默认85%)时自动开启。这样设计的目的是防止网络分区时,健康服务被错误剔除。

生产环境的处理建议:

  • 开启自我保护:eureka.server.enable-self-preservation=true(默认开启)
  • 合理配置心跳参数:心跳间隔30秒,续租过期时间90秒
  • 配置多节点Eureka集群,避免单点故障
  • 监控Eureka Server的健康状态,关注Renews threshold和Renews (last min)指标
  • 如果确定服务已下线,可临时关闭自我保护清理实例

核心思想:宁可保留错误的服务实例,也不剔除健康的实例,配合集群部署保证高可用。


【面试题】2. Ribbon和Spring Cloud LoadBalancer有什么区别?为什么推荐使用后者? ​

【标准答案】核心区别在于:

Ribbon:

  • Netflix开源,已进入维护模式(停止迭代)
  • 功能完善,支持多种负载均衡策略
  • 与Spring Cloud深度集成多年,生态成熟
  • 但已不推荐新项目使用

Spring Cloud LoadBalancer:

  • Spring官方替代方案,持续维护
  • 更轻量,移除了Ribbon的冗余功能
  • 支持Reactive编程模型(WebFlux友好)
  • 配置更简洁,与Spring Boot自动配置无缝集成
  • 支持自定义负载均衡策略,实现ReactorServiceInstanceLoadBalancer接口

推荐后者的原因:

  1. Ribbon已停止维护,存在潜在Bug风险
  2. LoadBalancer是Spring官方长期支持方案
  3. 更好的云原生和响应式支持
  4. Spring Cloud 2020+版本已默认使用LoadBalancer

迁移成本很低,主要是依赖替换和少量配置调整。


【面试题】3. OpenFeign的超时重试机制如何配置?如何避免重试导致的重复下单问题? ​

【标准答案】超时配置:

yaml
feign:
  client:
    config:
      default:
        connectTimeout: 5000  # 连接超时5秒
        readTimeout: 10000    # 读取超时10秒
      userService:            # 针对特定服务
        connectTimeout: 3000
        readTimeout: 5000

重试配置: 默认情况下Feign会重试,可通过自定义Retryer控制:

java
@Configuration
public class FeignConfig {
    @Bean
    public Retryer retryer() {
        // 最大重试次数5,初始间隔100ms,最大间隔1s
        return new Retryer.Default(100, 1000, 5);
        // 或者完全禁止重试
        // return Retryer.NEVER_RETRY;
    }
}

避免重复下单的关键策略:

  1. 接口幂等性设计:唯一请求ID(Idempotency-Key),服务端去重
  2. 关闭GET请求重试:GET可重试,POST/PUT/PATCH建议关闭
  3. 分布式锁:关键操作前先获取锁
  4. Token机制:下单前获取Token,服务端消费后失效
  5. 数据库唯一约束:订单号唯一,重复插入失败

最佳实践:非幂等操作关闭重试,配合业务层幂等性设计双重保障。


【面试题】4. Sentinel的熔断状态机三个状态之间如何流转?各状态的作用是什么? ​

【标准答案】Sentinel熔断状态机包含三个状态:

1. CLOSED(关闭状态)

  • 初始状态,请求正常通过
  • 统计请求的成功率、响应时间、异常比例
  • 当指标达到阈值时,切换到OPEN状态

2. OPEN(打开状态)

  • 熔断生效,所有请求直接触发fallback
  • 设置熔断时长(如10秒),期间不检查后端服务
  • 熔断时长结束后,进入HALF-OPEN状态

3. HALF-OPEN(半开状态)

  • 探测状态,允许少量请求(如1个)通过
  • 如果请求成功:说明服务恢复,切换到CLOSED
  • 如果请求失败:说明服务仍异常,重新回到OPEN

流转完整流程:

CLOSED --(异常比例/慢调用比例达阈值)--> OPEN
OPEN --(熔断时长结束)--> HALF-OPEN
HALF-OPEN --(探测成功)--> CLOSED
HALF-OPEN --(探测失败)--> OPEN

三种熔断策略:

  • 慢调用比例:响应时间超过阈值RT的比例
  • 异常比例:异常数占总请求的比例
  • 异常数:一分钟内的异常数量

核心思想:快速失败,保护系统,定时探测恢复。


【面试题】5. Spring Cloud Gateway如何实现灰度发布?具体的路由策略有哪些? ​

【标准答案】核心实现方式:

1. 基于权重的路由策略

yaml
spring:
  cloud:
    gateway:
      routes:
      - id: user-service-v1
        uri: lb://USER-SERVICE-V1
        predicates:
        - Weight=user-group, 80  # 80%流量到v1
      - id: user-service-v2
        uri: lb://USER-SERVICE-V2
        predicates:
        - Weight=user-group, 20  # 20%流量到v2

2. 基于请求头的路由

yaml
predicates:
- Header=X-Gray-Version, v2

适用场景:内部测试、特定用户群体

3. 基于Cookie的路由

yaml
predicates:
- Cookie=gray-user, true

适用场景:白名单用户灰度

4. 基于参数的路由

yaml
predicates:
- Query=version, v2

适用场景:通过URL参数控制版本

5. 自定义灰度路由策略 实现RouteLocator接口,根据业务规则动态路由:

java
public class GrayRouteLocator implements RouteLocator {
    // 从配置中心/Nacos读取灰度规则
    // 根据用户ID、地区、设备类型等维度路由
}

完整灰度发布流程:

  1. 新版本服务注册到Nacos(带上版本标签)
  2. 网关配置灰度路由规则(从小流量开始)
  3. 监控新版本指标(错误率、响应时间)
  4. 逐步扩大流量比例
  5. 全量切换,下线旧版本

关键点:配合Nacos元数据、Sentinel流量控制、完善的监控告警。


【面试题】6. Nacos Config的配置热更新是如何实现的?ConfigListener的工作原理是什么? ​

【标准答案】热更新实现机制:

1. 客户端长轮询

  • Nacos Client定时向Server发起长轮询(默认30秒)
  • Server挂起请求,等待配置变更
  • 配置变化时立即返回,无变化则超时返回304

2. 配置缓存

  • Client本地缓存配置文件
  • 启动时先读本地缓存,再异步拉取最新配置
  • 保证启动速度和网络容错

3. 配置版本对比

  • 每次配置带MD5校验
  • Client发现MD5变化时触发更新

ConfigListener工作原理:

java
@NacosConfigListener(dataId = "application.yml", groupId = "DEFAULT_GROUP")
public void onConfigChange(String newConfig) {
    // 配置变更回调
}

内部流程:

  1. Client注册Listener到本地ListenerManager
  2. 长轮询线程检测到配置变化
  3. 计算新配置MD5与本地不一致
  4. 触发所有注册的Listener回调
  5. 执行业务自定义逻辑

与@RefreshScope配合:

java
@RestController
@RefreshScope  // 配置变更时Bean重建
public class ConfigController {
    @Value("${custom.config}")
    private String config;
}

工作原理:

  • Nacos配置变化 → 触发Environment更新
  • @RefreshScope的Bean被标记为脏
  • 下次访问时重新创建Bean,注入新值

关键点:长轮询保证实时性,本地缓存保证可用性。


【面试题】7. Sleuth如何实现TraceId在微服务调用链中的传递?异步场景下如何保证链路完整? ​

【标准答案】同步调用链传递机制:

1. ThreadLocal存储

  • TraceId和SpanId存储在ThreadLocal中
  • 当前线程共享同一个Trace上下文

2. HTTP Header传递

  • 服务A发起请求时,Sleuth拦截器自动添加Header:
    • X-B3-TraceId:全局唯一追踪ID
    • X-B3-SpanId:当前Span ID
    • X-B3-ParentSpanId:父Span ID
    • X-B3-Sampled:是否采样

3. 服务B接收

  • Sleuth Filter解析Header
  • 创建新Span,关联父Span
  • 继续传递给下游服务

异步场景的解决方案:

1. @Async异步方法

java
@Bean
public TaskExecutor taskExecutor() {
    return new DelegatingSecurityContextExecutor(
        new ThreadPoolTaskExecutor(),
        new LazyTraceExecutor(tracer, executor)
    );
}

2. 线程池手动传递

java
@Autowired
private Tracer tracer;

public void asyncMethod() {
    ExecutorService executor = Executors.newFixedThreadPool(5);
    Runnable task = tracer.withSpanInScope(
        tracer.currentSpan(),
        () -> { /* 业务逻辑 */ }
    );
    executor.submit(task);
}

3. 消息队列场景

  • Spring Cloud Stream自动集成Sleuth
  • TraceId注入到消息Header
  • 消费者自动提取并续链

关键原理:

  • 同步调用:ThreadLocal + HTTP Header自动传递
  • 异步调用:手动包装Runnable/Callable,传递ThreadLocal上下文
  • 消息队列:消息Header作为载体

核心思想:每个调用边界都进行Trace上下文的序列化与反序列化。


【面试题】8. Seata的AT模式和TCC模式有什么本质区别?各自的适用场景是什么? ​

【标准答案】本质区别对比:

维度AT模式TCC模式
侵入性无侵入,自动补偿高侵入,需编写Try/Confirm/Cancel
实现复杂度低,依赖undo_log高,需处理幂等、空回滚、悬挂
性能较好,锁粒度小高,无全局锁,资源预留
一致性最终一致,依赖数据库强一致,业务控制
适用场景传统SQL应用高并发、非数据库资源
限制仅支持数据库事务任意资源(Redis、MQ等)

AT模式原理:

  1. 解析SQL,记录修改前镜像(before image)
  2. 执行业务SQL
  3. 记录修改后镜像(after image)
  4. 生成undo_log插入数据库
  5. 全局提交:删除undo_log
  6. 全局回滚:根据undo_log反向生成SQL恢复数据

TCC模式原理:

  • Try:资源预留(冻结库存)
  • Confirm:确认提交(扣减库存)
  • Cancel:取消释放(解冻库存)

TCC三大问题解决方案:

1. 空回滚(Try未执行,先执行Cancel)

java
// Cancel时检查Try是否执行过
if (tryExecuted.get() == null) {
    // 记录空回滚标记,直接返回
    return;
}

2. 幂等性(重复Confirm/Cancel)

java
// 状态机控制,已处理直接返回
if (status == CONFIRMED || status == CANCELED) {
    return;
}

3. 悬挂(Cancel先于Try执行)

java
// Try时检查是否已有空回滚标记
if (hasEmptyRollbackLog()) {
    return;
}

适用场景建议:

  • AT模式:95%的常规业务,对代码无侵入要求
  • TCC模式:库存扣减、账户余额、高并发金融场景
  • Saga模式:长事务、编排型业务流程

【面试题】9. Redis分布式锁的Redisson看门狗(Watchdog)机制是什么?为什么需要锁续期? ​

【标准答案】为什么需要锁续期:

问题背景:

bash
SET lock:key value NX EX 30  # 加锁,30秒过期

如果业务执行超过30秒:

  • 锁已自动过期释放
  • 其他线程获得锁
  • 原线程执行完毕释放锁(可能释放别人的锁)
  • 导致并发安全问题

Watchdog机制原理:

Redisson的看门狗是一个后台定时任务:

  1. 默认锁过期时间30秒(lockWatchdogTimeout)
  2. 每隔10秒(1/3过期时间)检查锁是否还持有
  3. 如果持有,自动续期到30秒
  4. 业务执行完毕,主动释放锁,看门狗停止

核心代码:

java
RLock lock = redisson.getLock("myLock");
lock.lock();  // 启动Watchdog
try {
    // 业务执行超过30秒也安全
    Thread.sleep(60000);
} finally {
    lock.unlock();  // 释放锁,停止Watchdog
}

手动指定leaseTime时Watchdog不生效:

java
lock.lock(10, TimeUnit.SECONDS);  // 不会自动续期

Watchdog的优势:

  • 自动续期,无需预估业务执行时间
  • 避免业务未完成锁过期
  • 防止死锁(客户端宕机,锁会在过期时间后自动释放)

注意事项:

  • 需要Redisson客户端,原生Redis不支持
  • 看门狗是客户端任务,Redis Server重启会导致锁丢失
  • 集群模式下推荐使用RedLock算法

核心思想:让锁的生命周期与业务执行时间解耦,自动管理锁续期。


【面试题】10. Spring Cloud Stream的消息分组(Consumer Group)如何保证消息只被消费一次? ​

【标准答案】问题背景:

微服务多实例部署时,同一条消息可能被多个实例重复消费:

订单服务实例1 → 收到消息
订单服务实例2 → 收到消息(重复!)

Consumer Group解决方案:

1. 配置消息分组

yaml
spring:
  cloud:
    stream:
      bindings:
        orderInput:
          destination: order-topic
          group: order-group  # 关键配置

2. 工作原理:

  • 同一个group内的多个消费者实例共享订阅
  • 消息队列(如RabbitMQ/Kafka)保证同一group只投递给一个实例
  • 不同group各自独立消费(广播语义)

3. 不同MQ的实现差异:

RabbitMQ:

  • 创建队列命名:order-topic.order-group
  • 多实例绑定同一队列,竞争消费
  • 消息轮询投递给各实例

Kafka:

  • Consumer Group机制,分区分配策略
  • 同一组内,一个分区只能被一个消费者消费
  • 分区数决定并行度

RocketMQ:

  • Consumer Group机制
  • 同一组内消息负载均衡

核心配置示例:

yaml
spring:
  cloud:
    stream:
      function:
        definition: consumeOrder
      bindings:
        consumeOrder-in-0:
          destination: order-topic
          group: order-service-group  # 保证单实例消费
          consumer:
            max-attempts: 3           # 重试次数
      rocketmq:
        bindings:
          consumeOrder-in-0:
            consumer:
              orderly: true            # 顺序消费

补充保证机制:

  • 幂等性设计:业务层去重(消息ID、业务唯一键)
  • ACK机制:消费成功才确认,失败则重试
  • 死信队列:重试失败转入DLQ,人工处理

核心思想:消息分组将竞争消费者模式变为负载均衡模式,保证消息精准投递。


总结 ​

本套面试题涵盖:

  • 服务注册发现(Eureka自我保护)
  • 负载均衡(Ribbon vs LoadBalancer)
  • 服务调用(OpenFeign超时重试)
  • 熔断限流(Sentinel状态机)
  • API网关(Gateway灰度发布)
  • 配置中心(Nacos热更新)
  • 链路追踪(Sleuth TraceId传递)
  • 分布式事务(Seata AT/TCC)
  • 分布式锁(Redisson看门狗)
  • 消息队列(Stream消息分组)

建议复习重点:

  1. 核心原理必须理解透彻
  2. 生产环境最佳实践
  3. 故障场景应对策略
  4. 与面试官互动的实战经验表达