SpringCloud微服务架构面试题库(带答案)
生成时间:2026-05-24 20:33
【面试题】1. Nacos作为注册中心,它的AP和CP模式怎么选择?底层原理是什么?
【标准答案】Nacos支持AP和CP两种模式切换,关键看业务对一致性的要求。
选择标准:
- AP模式(可用性优先):适合临时实例,比如常规微服务。允许短暂的数据不一致,优先保证服务可用,适合对实时性要求不高但需要高可用的场景。
- CP模式(一致性优先):适合持久化实例,比如数据库、配置中心等核心基础设施。必须保证数据强一致性,宁可短暂不可用也不返回错误数据。
底层原理: Nacos 1.x用Raft协议实现CP模式,Leader节点负责写操作,Follower同步日志达成一致;AP模式用Distro协议,每个节点独立处理读写,通过异步复制最终一致。Nacos 2.x重构后用自研的JRaft和Distro v2,性能更好。
面试加分点: 说一句"我们生产环境一般用AP模式,因为服务发现允许秒级延迟,但必须保证高可用",体现实际经验。
【面试题】2. Sentinel和Hystrix的熔断原理有什么区别?实际项目怎么选?
【标准答案】两者都是熔断降级,但设计理念和实现方式差异很大。
核心区别:
| 维度 | Hystrix | Sentinel |
|---|---|---|
| 隔离策略 | 线程池/信号量隔离 | 信号量隔离(默认)+ 并发线程数控制 |
| 熔断状态机 | 三态:关闭→打开→半开 | 三态:关闭→打开→半开,但支持更多规则 |
| 限流算法 | 信号量计数 | QPS/并发线程数,支持滑动窗口、令牌桶、漏桶 |
| 动态规则 | 需配置中心配合 | 原生支持控制台动态推送 |
| 资源消耗 | 线程池模式开销大 | 轻量,无线程池开销 |
实际选择建议:
- 新项目直接选Sentinel:功能更全(限流+熔断+热点参数限流+系统自适应保护),社区活跃,阿里维护。
- 老项目用Hystrix:如果已经稳定运行,迁移成本高,可以继续用,但Hystrix已停止维护。
- Resilience4j:如果追求轻量和函数式编程风格,可以选它,但功能不如Sentinel丰富。
面试加分点: "我们用Sentinel,配合Nacos做规则持久化,控制台可视化做得很好",体现实战经验。
【面试题】3. Spring Cloud Gateway如何实现灰度发布?具体方案是什么?
【标准答案】灰度发布核心是路由规则的动态控制,Gateway通过Filter和Predicate组合实现。
主流方案:
方案一:基于请求头的灰度
spring:
cloud:
gateway:
routes:
- id: service-v1
uri: lb://user-service-v1
predicates:
- Path=/api/user/**
- Header=X-Gray-Version, v1
- id: service-v2
uri: lb://user-service-v2
predicates:
- Path=/api/user/**
- Header=X-Gray-Version, v2方案二:基于权重的灰度 用Weight断言,比如90%流量走v1,10%走v2,观察稳定后逐步扩大。
方案三:基于注册中心元数据 服务注册时带上version标签,Gateway根据元数据路由,结合Nacos或Eureka的元数据功能。
生产级方案:
- Nacos配置中心存储灰度规则(版本、权重、白名单用户)
- Gateway动态刷新路由配置
- 监控指标对比(错误率、RT、QPS)决定是否扩大灰度比例
- 出问题秒级回滚
面试加分点: "我们用Nacos配置中心配合Gateway,实现分钟级灰度发布,有问题一键回滚",结合实际场景更打动人。
【面试题】4. Seata的AT模式和TCC模式有什么区别?各自适合什么场景?
【标准答案】两者都是分布式事务解决方案,但实现机制和适用场景完全不同。
AT模式(Automatic Transaction):
- 原理:基于数据库本地事务+全局锁,第一阶段执行本地事务并记录undo_log,第二阶段异步提交或回滚。
- 优点:零侵入,不需要改业务代码,框架自动处理。
- 缺点:依赖数据库事务,有全局锁竞争,高并发性能下降明显。
- 适用场景:普通业务、对一致性要求不是特别高、能接受短暂脏读。
TCC模式(Try-Confirm-Cancel):
- 原理:业务代码显式编写三个阶段,Try预留资源、Confirm提交、Cancel回滚。
- 优点:资源锁定粒度小,性能好,最终一致性可控。
- 缺点:代码侵入性强,需要自己写补偿逻辑,开发成本高。
- 适用场景:高并发核心业务、资源竞争激烈、需要精确控制一致性的场景(如库存、账户)。
选择建议:
- 80%场景用AT模式,开发效率高,够用。
- 核心资金/库存场景用TCC,性能好、控制细。
- 跨公司/跨平台用Saga模式或本地消息表。
面试加分点: "我们订单扣库存用TCC,普通订单状态更新用AT,区分核心和非核心业务",体现架构思维。
【面试题】5. Redis分布式锁用什么实现?Redisson和SET NX EX有什么区别?
【标准答案】Redis分布式锁主流两种实现,Redisson是生产级推荐方案。
SET NX EX方式(原生Redis命令):
SET lock:key unique_value NX EX 30- 优点:简单直接,一条命令原子执行。
- 缺点:
- 锁续期需要自己实现(看门狗机制)
- 无法实现可重入锁
- 集群模式下可能多个节点同时获得锁(AP模型的坑)
- 解锁需要Lua脚本保证原子性
Redisson方式(框架封装):
RLock lock = redisson.getLock("myLock");
lock.lock(); // 自动续期
lock.unlock();- 优点:
- 自动续期(Watchdog看门狗,默认30秒,后台线程每10秒续期)
- 支持可重入锁
- 支持RedLock(集群模式锁安全)
- 支持公平锁、读写锁、闭锁等丰富锁类型
- 解锁原子性保证
- 缺点:框架依赖,学习成本稍高。
生产环境建议:
- 单机Redis:直接用Redisson。
- Redis Cluster/Sentinel:用Redisson的RedLock模式保证安全性。
- 超高并发场景:考虑Zookeeper分布式锁,CP模型强一致更安全。
面试加分点: "我们用Redisson,它的看门狗机制很好用,不用操心锁过期被别人抢走",说明踩过坑有经验。
【面试题】6. OpenFeign超时重试怎么配置?为什么有时候会触发多次重试?
【标准答案】OpenFeign的超时配置分两层,理解清楚才能避免坑。
配置方式:
feign:
client:
config:
default:
connectTimeout: 5000 # 连接超时5秒
readTimeout: 10000 # 读取超时10秒重试机制: OpenFeign默认使用Retryer.Default,最多重试5次,间隔从100ms开始指数退避。
为什么会多次重试?
- 默认重试器生效:没配置时,超时或网络异常会自动重试。
- Ribbon重试叠加:如果用了Ribbon做负载均衡,Ribbon本身也有重试逻辑,可能和Feign重试叠加,导致实际调用次数=Feign重试×Ribbon重试。
- 服务端慢响应:readTimeout触发后,客户端已经重试,但服务端请求还在队列里,造成重复请求。
生产配置建议:
feign:
client:
config:
default:
connectTimeout: 3000
readTimeout: 5000
retryer: feign.Retryer.NEVER_RETRY # 关闭Feign层重试
ribbon:
MaxAutoRetries: 1 # 同实例重试1次
MaxAutoRetriesNextServer: 1 # 切换实例重试1次
OkToRetryOnAllOperations: false # 只重试GET,不重试POST面试加分点: "我们关闭Feign重试,只用Ribbon层重试,并且只对GET请求重试,幂等性更可控",体现对重试机制的深入理解。
【面试题】7. 微服务链路追踪怎么做?TraceId和SpanId是怎么传递的?
【标准答案】链路追踪是微服务可观测性的核心,TraceId和SpanId的传递机制是关键。
主流方案:
- Sleuth + Zipkin:Spring Cloud生态默认方案,集成简单,适合中小规模。
- SkyWalking:性能好,无侵入,可视化强,适合大规模生产。
- Micrometer Tracing + Jaeger:Sleuth的替代品,Spring Boot 3.x官方推荐。
TraceId/SpanId传递原理:
- 入口请求:Gateway或第一个服务生成TraceId(全局唯一,贯穿整个调用链)和SpanId(当前服务标识)。
- HTTP传递:通过HTTP Header传递,约定Header名称:
X-Trace-Id或X-B3-TraceIdX-Span-Id或X-B3-SpanIdX-Parent-SpanId
- 跨服务调用:OpenFeign/RestTemplate自动拦截器把Header透传到下游。
- 异步场景:线程池需要手动传递MDC(Mapped Diagnostic Context),或用
@Async配合TaskDecorator自动传递。
关键代码:
// 异步线程池传递TraceId
ExecutorService executor = Executors.newFixedThreadPool(10);
executor.submit(MDC.getCopyOfContextMap(), () -> {
// 子线程自动继承父线程TraceId
});面试加分点: "我们用SkyWalking,异步场景封装了TaskDecorator,TraceId透传问题踩过坑",展示实战经验。
【面试题】8. Nacos配置中心怎么做热更新?多环境配置怎么管理?
【标准答案】Nacos配置中心的核心价值是热更新,多环境管理是生产必备。
热更新原理:
- 客户端启动时建立长轮询连接(默认30秒)。
- 配置变更后,Nacos推送变更通知。
- 客户端收到通知,拉取最新配置。
@RefreshScope注解的Bean会重新创建,注入新值。
热更新配置:
@RestController
@RefreshScope // 关键注解,配置变更自动刷新
public class ConfigController {
@Value("${app.config.value}")
private String configValue;
}多环境管理方案:
方案一:Namespace隔离
namespace: dev -> 开发环境
namespace: test -> 测试环境
namespace: prod -> 生产环境每个Namespace完全独立,配置隔离干净。
方案二:Group分组
namespace: public
group: DEFAULT_GROUP -> 默认配置
group: DEV_GROUP -> 开发配置
group: PROD_GROUP -> 生产配置同一Namespace下用Group区分。
方案三:Data ID后缀
application-dev.yaml
application-test.yaml
application-prod.yamlSpring Boot原生Profile机制,Nacos支持。
生产推荐: Namespace隔离环境,Group区分项目或模块,层次清晰,权限好控制。
面试加分点: "我们用Namespace隔离环境,配合权限控制,开发和生产完全隔离",说明有生产治理意识。
【面试题】9. Spring Cloud Gateway如何做统一鉴权?JWT Token怎么传递到下游服务?
【标准答案】Gateway作为流量入口,统一鉴权是标配,JWT Token传递是关键环节。
统一鉴权方案:
方案一:Gateway Filter鉴权
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (StringUtils.isEmpty(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 验证JWT
Claims claims = JwtUtil.parseToken(token);
// 把用户信息透传到下游
ServerHttpRequest request = exchange.getRequest().mutate()
.header("X-User-Id", claims.get("userId").toString())
.header("X-User-Name", claims.get("username").toString())
.build();
return chain.filter(exchange.mutate().request(request).build());
}
@Override
public int getOrder() {
return -100; // 优先执行
}
}方案二:集成OAuth2 用Spring Security + OAuth2资源服务器,Gateway做Token校验,下游服务无状态。
JWT Token传递到下游:
- 透传Token:Gateway不做解析,直接把Header传给下游,下游服务自己校验。
- 解析后传递:Gateway解析JWT,提取用户信息放到Header(如X-User-Id),下游服务直接使用,不用再解析。
生产建议:
- 高频接口用方案二(解析后传递),减少下游重复校验开销。
- 敏感操作用方案一(透传Token),下游二次校验保证安全。
面试加分点: "我们用方案二,Gateway解析JWT后把用户ID放到Header透传,下游服务不用再解析,性能更好",体现性能优化意识。
【面试题】10. 消息队列如何保证消息不丢失?Spring Cloud Stream怎么实现可靠消费?
【标准答案】消息可靠性是分布式系统的难点,需要从生产端、Broker端、消费端三方面保证。
消息不丢失方案:
1. 生产端保证
- 开启确认机制(ACK):消息发送后等待Broker确认。
- 消息持久化:发送前先落库,确认成功后删除,失败重试或告警。
// RocketMQ示例
producer.send(message, new SendCallback() {
@Override
public void onSuccess(SendResult result) {
// 确认成功,删除本地消息表记录
}
@Override
public void onException(Throwable e) {
// 重试或告警
}
});2. Broker端保证
- 开启同步刷盘(性能换可靠性)。
- 主从同步复制,主节点挂了从节点有数据。
- RocketMQ默认异步刷盘+异步复制,可配置SYNC_FLUSH和SYNC_MASTER。
3. 消费端保证
- 关闭自动提交offset,业务处理成功后手动提交。
- 幂等性设计:消息ID去重,防止重复消费。
@StreamListener(Sink.INPUT)
public void handleMessage(Message<String> message) {
String messageId = message.getHeaders().getId().toString();
if (redisTemplate.opsForValue().setIfAbsent("msg:" + messageId, "1", 1, TimeUnit.DAYS)) {
// 首次消费,处理业务
processBusiness(message.getPayload());
} else {
// 重复消息,跳过
log.warn("重复消息: {}", messageId);
}
// 手动确认
acknowledgment.acknowledge();
}Spring Cloud Stream配置:
spring:
cloud:
stream:
rocketmq:
bindings:
input:
consumer:
enable: true
orderly: true # 顺序消费
messageModel: CLUSTERING # 集群模式
bindings:
input:
group: order-group # 同一group保证负载均衡+不重复消费
consumer:
auto-commit-offset: false # 关闭自动提交面试加分点: "我们用本地消息表+定时任务补偿,保证最终一致性,RocketMQ事务消息也用过",说明有完整解决方案经验。
总结
本轮面试题覆盖:
- 服务注册与发现:Nacos AP/CP模式(题1)
- 熔断限流降级:Sentinel vs Hystrix(题2)
- API网关:Gateway灰度发布(题3)、统一鉴权与Token传递(题9)
- 分布式事务:Seata AT/TCC模式(题4)
- 分布式锁:Redis分布式锁与Redisson(题5)
- 服务调用:OpenFeign超时重试(题6)
- 链路追踪:TraceId/SpanId传递(题7)
- 配置中心:Nacos热更新与多环境管理(题8)
- 消息队列:消息可靠性保证(题10)
每道题都包含:技术原理+对比分析+生产经验+面试加分话术,适合冲刺面试。