一、服务注册与发现
1.1 Eureka(Netflix)
核心概念
-
服务注册:微服务启动时向 Eureka Server 注册自己的网络地址(IP + Port + 服务名)
-
服务发现:消费者从 Eureka Server 拉取服务提供者列表,通过 Ribbon 进行负载均衡调用
-
心跳机制:客户端每 30 秒发送一次心跳,90 秒未收到则剔除服务
面试重点
Q: Eureka 的自我保护机制是什么?
A: 当 15 分钟内超过 85% 的客户端心跳异常时,Eureka 进入自我保护模式,不再剔除服务。
目的是防止网络分区故障导致服务大规模下线(CAP 中的 AP 体现)。
Q: Eureka 与 Zookeeper 的区别?
A: Eureka 追求 AP(可用性+分区容错),Zookeeper 追求 CP(一致性+分区容错)。
Eureka 有自我保护机制,Zookeeper 使用 ZAB 协议保证强一致性。
关键配置
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka1:8761/eureka,http://eureka2:8762/eureka
instance:
lease-renewal-interval-in-seconds: 30 # 心跳间隔
lease-expiration-duration-in-seconds: 90 # 过期时间
1.2 Nacos(Alibaba)
优势对比
| 特性 | Eureka | Nacos |
|---|---|---|
| 一致性 | AP | AP/CP 可切换 |
| 配置中心 | 不支持 | 内置支持 |
| 健康检查 | 客户端心跳 | TCP/HTTP/MySQL 多种方式 |
| 负载均衡 | Ribbon | 内置 + Ribbon |
| 生态 | Spring Cloud Netflix | Spring Cloud Alibaba |
Nacos 注册中心原理
-
临时实例:通过心跳维持(类似 Eureka),AP 模式
-
永久实例:服务端主动探测,CP 模式(Raft 协议)
-
服务订阅:客户端长轮询(Long Polling)获取配置变更
// Nacos 服务注册示例
NamingService naming = NamingFactory.createNamingService("localhost:8848");
naming.registerInstance("user-service", "192.168.1.100", 8080);
二、配置中心
2.1 Spring Cloud Config
架构
-
Config Server:从 Git/SVN 读取配置文件
-
Config Client:启动时从 Server 拉取配置
-
刷新机制:依赖 Bus 消息总线 + Webhook 实现动态刷新
痛点
-
配置实时性依赖手动刷新或 Webhook
-
无灰度发布支持
-
无配置权限管理
2.2 Nacos Config
核心特性
-
动态刷新:客户端长轮询,配置变更实时推送(1 秒延迟)
-
灰度配置:基于 Namespace + Group + DataId 隔离
-
历史版本:支持配置回滚
-
权限控制:RBAC 模型
bootstrap.yml
spring:
cloud:
nacos:
config:
server-addr: localhost:8848
namespace: dev # 环境隔离
group: DEFAULT_GROUP
file-extension: yaml
shared-configs:
- data-id: common.yaml
group: DEFAULT_GROUP
refresh: true
@RefreshScope 原理
@RefreshScope
@RestController
public class ConfigController {
@Value("${user.name}")
private String userName;
}
底层通过代理对象实现:配置变更时销毁旧 Bean,重新创建并注入新值。
2.3 Apollo(携程)
架构设计
-
Config Service:提供配置读取接口,客户端长轮询
-
Admin Service:提供配置管理接口(Portal 调用)
-
Portal:Web 管理界面
-
Meta Server:Eureka 注册中心(内置)
优势
-
支持多环境、多集群
-
完善的灰度发布、版本管理
-
配置变更审计日志
三、服务网关
3.1 Zuul(Netflix)
过滤器类型
-
PRE:请求路由前(认证、限流)
-
ROUTING:路由请求到微服务
-
POST:请求返回后(日志、统计)
-
ERROR:错误处理
性能瓶颈
-
基于 Servlet 阻塞 IO,单线程处理请求
-
高并发场景性能较差(已被 Spring Cloud Gateway 取代)
3.2 Spring Cloud Gateway
核心优势
-
Reactive 非阻塞:基于 WebFlux + Netty,高并发性能优异
-
动态路由:支持通过配置中心实时更新路由规则
-
集成度高:内置熔断、限流、重试
核心概念
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service # lb: 负载均衡
predicates:
- Path=/api/user/**
- Method=GET
- Header=X-Request-Id, \d+
filters:
- StripPrefix=1
- AddRequestHeader=X-Request-From,Gateway
- CircuitBreaker=name=userCB,fallbackUri=forward:/fallback
Predicate 断言工厂
| 断言 | 说明 |
|---|---|
| Path | 路径匹配 |
| Method | HTTP 方法匹配 |
| Header | 请求头匹配 |
| Query | 查询参数匹配 |
| Before/After/Between | 时间匹配 |
| RemoteAddr | IP 匹配 |
| Weight | 权重分流 |
Filter 过滤器
-
GatewayFilter:单一路由生效(StripPrefix、AddHeader)
-
GlobalFilter:全局生效(认证、日志、限流)
// 自定义全局过滤器:JWT 认证
@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 || !validateToken(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}@Override public int getOrder() { return -100; } // 优先级}
四、负载均衡
4.1 Ribbon(Netflix)
负载均衡策略
| 策略 | 说明 |
|---|---|
| RoundRobinRule | 轮询(默认) |
| RandomRule | 随机 |
| WeightedResponseTimeRule | 响应时间加权 |
| RetryRule | 重试机制 |
| BestAvailableRule | 最小并发连接 |
| ZoneAvoidanceRule | 区域感知(结合 Eureka 元数据) |
核心原理
-
从 Eureka 获取服务列表(ServerList)
-
通过 IRule 选择实例
-
IPing 健康检查剔除不可用实例
@Bean
public IRule ribbonRule() {
return new WeightedResponseTimeRule(); // 自定义策略
}
4.2 Spring Cloud LoadBalancer
替代 Ribbon
-
支持 Reactive 编程模型
-
缓存服务列表(Caffeine)
-
支持自定义负载均衡策略
// 自定义负载均衡器
public class CustomLoadBalancer implements ReactorServiceInstanceLoadBalancer {
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
// 自定义选择逻辑
return Mono.just(new DefaultResponse(instance));
}
}
五、熔断与限流
5.1 Hystrix(Netflix,已停更)
核心概念
-
熔断器状态:CLOSED(关闭)→ OPEN(打开)→ HALF_OPEN(半开)
-
降级策略:快速失败、静默失败、缓存返回
-
舱壁模式:线程池隔离(默认)或信号量隔离
配置参数
hystrix:
command:
default:
execution:
isolation:
strategy: THREAD # THREAD / SEMAPHORE
thread:
timeoutInMilliseconds: 1000
circuitBreaker:
requestVolumeThreshold: 20 # 10秒内请求数阈值
errorThresholdPercentage: 50 # 错误率阈值
sleepWindowInMilliseconds: 5000 # 熔断持续时间
为什么停更?
-
性能问题:基于线程池隔离开销大
-
功能局限:无自适应限流、无控制台
-
Netflix 转向内部替代方案
5.2 Sentinel(Alibaba)
流量控制规则
| 控制维度 | 说明 |
|---|---|
| QPS | 每秒查询数 |
| 线程数 | 并发线程数 |
| 关联限流 | 当关联资源达到阈值时限流当前资源 |
| 链路限流 | 针对调用链路的入口资源限流 |
熔断策略
-
慢调用比例:慢调用占比超过阈值触发熔断
-
异常比例:异常比例超过阈值触发熔断
-
异常数:异常数超过阈值触发熔断
@SentinelResource(
value = "getUser",
blockHandler = "getUserBlockHandler", // 限流/降级处理
fallback = "getUserFallback" // 异常处理
)
public User getUser(Long id) {
return userMapper.selectById(id);
}public User getUserBlockHandler(Long id, BlockException ex) {
return new User("限流降级");
}
Sentinel vs Hystrix
| 特性 | Hystrix | Sentinel |
|---|---|---|
| 隔离策略 | 线程池/信号量 | 信号量 |
| 熔断策略 | 错误率 | 慢调用/异常比例/异常数 |
| 限流 | 不支持 | 支持 QPS/线程数/热点参数 |
| 控制台 | 简陋 | 强大(实时监控、规则配置) |
| 自适应 | 不支持 | 支持系统自适应保护 |
5.3 Gateway 限流
基于 Redis 的令牌桶算法
spring:
cloud:
gateway:
routes:
- id: rate_limit_route
uri: lb://user-service
predicates:
- Path=/api/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 每秒填充速率
redis-rate-limiter.burstCapacity: 20 # 桶容量
key-resolver: "#{@userKeyResolver}" # 限流维度
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getHeaders().getFirst("X-User-Id")
);
}
六、分布式事务
6.1 Seata(Alibaba)
核心角色
-
TC (Transaction Coordinator):事务协调器,维护全局事务状态
-
TM (Transaction Manager):事务管理器,定义全局事务范围
-
RM (Resource Manager):资源管理器,管理分支事务
四种模式
| 模式 | 原理 | 适用场景 |
|---|---|---|
| AT | 自动补偿(Undo Log) | 简单 CRUD,无复杂 SQL |
| TCC | Try-Confirm-Cancel | 复杂业务,需预留资源 |
| Saga | 长事务,正向+逆向补偿 | 业务流程长,需状态机 |
| XA | 两阶段提交 | 强一致性要求 |
AT 模式原理
1. TM 开启全局事务 @GlobalTransactional
2. RM 执行业务 SQL,记录 Undo Log(前后镜像)
3. 一阶段:直接提交本地事务
4. 二阶段:成功则删除 Undo Log,失败则回滚
@GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
public void createOrder(Order order) {
orderService.create(order); // 分支事务 1
storageService.deduct(order); // 分支事务 2
accountService.debit(order); // 分支事务 3
}
脏写问题解决方案
-
全局锁:一阶段提交前获取全局锁,二阶段释放
-
脏写检查:回滚时对比当前数据与 Undo Log 后镜像
七、链路追踪
7.1 Sleuth + Zipkin
核心概念
-
Trace:一次完整请求链路(全局唯一 TraceId)
-
Span:一次调用单元(SpanId + ParentId)
-
Annotation:时间戳事件(cs/sr/ss/cr)
集成方式
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
spring:
zipkin:
base-url: http://localhost:9411
sender:
type: kafka # 高并发场景用消息队列传输
sleuth:
sampler:
probability: 0.1 # 采样率 10%
7.2 SkyWalking
优势
-
自动探针:无代码侵入(Java Agent)
-
多语言支持:Java、.NET、Node.js、Go
-
性能分析:方法级性能剖析
-
告警机制:支持 Webhook 通知
核心指标
-
CPM:每分钟调用数
-
Avg Response Time:平均响应时间
-
P99/P95:百分位延迟
-
Apdex:应用性能指数
八、服务间通信
8.1 OpenFeign
声明式 HTTP 客户端
@FeignClient(
name = "user-service",
fallback = UserClientFallback.class,
configuration = FeignConfig.class
)
public interface UserClient {
@GetMapping("/users/{id}")
User getUser(@PathVariable("id") Long id);
@PostMapping("/users")
User createUser(@RequestBody User user);
}
性能优化
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 10000
compression:
request:
enabled: true # 开启 Gzip 压缩
response:
enabled: true
httpclient:
enabled: false
okhttp:
enabled: true # 使用 OkHttp(连接池复用)
hystrix:
enabled: true # 开启熔断
8.2 Dubbo(Alibaba)
核心架构
-
Provider:服务提供者
-
Consumer:服务消费者
-
Registry:注册中心(Nacos/Zookeeper)
-
Monitor:监控中心
-
Container:服务运行容器
通信协议
| 协议 | 特点 |
|---|---|
| Dubbo | 默认,NIO 异步,TCP 长连接 |
| RMI | JDK 标准,阻塞 IO |
| Hessian | HTTP 协议,跨语言 |
| gRPC | HTTP/2,ProtoBuf 序列化 |
负载均衡策略
-
Random(默认)
-
RoundRobin
-
LeastActive(最少活跃调用数)
-
ConsistentHash(一致性哈希)
九、消息驱动
9.1 Spring Cloud Stream
核心概念
-
Binder:绑定器(RabbitMQ/Kafka/RocketMQ)
-
Channel:消息通道(Source/Processor/Sink)
-
Binding:桥接 Channel 与外部消息系统
@EnableBinding(Sink.class)
public class MessageConsumer {
@StreamListener(Sink.INPUT)
public void handle(String message) {
System.out.println("Received: " + message);
}
}
9.2 RocketMQ
消息类型
-
普通消息:同步/异步/单向发送
-
顺序消息:全局有序 / 分区有序(HashKey)
-
延时消息:18 个固定延迟级别
-
事务消息:Half Message + 本地事务 + 回查
// 事务消息
TransactionMQProducer producer = new TransactionMQProducer("group");
producer.setTransactionListener(new TransactionListener() {
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
// 执行本地事务
return LocalTransactionState.COMMIT_MESSAGE;
}@Override public LocalTransactionState checkLocalTransaction(MessageExt msg) { // 事务回查 return LocalTransactionState.COMMIT_MESSAGE; }});
十、高频面试题汇总
Q1: Spring Cloud 与 Dubbo 的区别?
答:
-
通信方式:Spring Cloud 基于 HTTP(REST),Dubbo 基于 RPC(TCP)
-
生态完整性:Spring Cloud 是一站式解决方案(网关、配置、熔断),Dubbo 需自行集成
-
性能:Dubbo RPC 性能优于 HTTP,但 HTTP 更易调试和跨语言
-
注册中心:Spring Cloud 可用 Eureka/Nacos,Dubbo 常用 Zookeeper/Nacos
-
适用场景:Spring Cloud 适合快速构建微服务,Dubbo 适合高性能、大规模服务治理
Q2: 微服务拆分原则?
答:
-
DDD bounded context:按业务领域拆分
-
高内聚低耦合:服务间依赖最小化
-
数据独立性:每个服务独立数据库
-
团队规模:遵循"两个披萨原则"(6-10 人维护一个服务)
-
演进式拆分:从单体逐步拆分,避免过度设计
Q3: 分布式事务如何解决?
答:
-
最终一致性:消息队列 + 本地事务表 + 定时补偿
-
强一致性:Seata AT/XA 模式(性能损耗大)
-
TCC:业务层实现 Try/Confirm/Cancel
-
Saga:长事务拆分,失败时执行补偿操作
-
最大努力通知:如支付回调,允许失败重试
Q4: 服务雪崩怎么解决?
答:
-
熔断:Hystrix/Sentinel 快速失败
-
限流:网关层 QPS 限制、热点参数限流
-
降级:非核心功能关闭,保证核心链路
-
隔离:线程池隔离、舱壁模式
-
超时设置:合理设置 RPC 超时时间
-
缓存:多级缓存减少数据库压力
Q5: 如何设计高可用微服务架构?
答:
-
多活部署:同城双活 / 异地多活
-
注册中心集群:Eureka 对等复制、Nacos Raft 集群
-
配置中心高可用:Apollo 多环境部署、Nacos 集群
-
网关层:多节点 + Nginx/Keepalived 负载均衡
-
数据库:读写分离、分库分表、主从复制
-
监控告警:Prometheus + Grafana + Alertmanager
十一、技术选型建议
| 场景 | 推荐方案 | 备选方案 |
|---|---|---|
| 注册中心 | Nacos | Consul、Eureka |
| 配置中心 | Nacos / Apollo | Spring Cloud Config |
| 服务网关 | Spring Cloud Gateway | Kong、APISIX |
| 熔断限流 | Sentinel | Hystrix(已过时) |
| 分布式事务 | Seata AT | TCC 自研、Saga |
| 链路追踪 | SkyWalking | Zipkin、Jaeger |
| 消息队列 | RocketMQ | Kafka、RabbitMQ |
| 服务通信 | OpenFeign + Ribbon | Dubbo、gRPC |