服务治理
2026/10/11大约 5 分钟
服务治理
服务拆开后,实例会不断上下线、配置要能热更新、调用要有超时与兜底、发布要能灰度。这些「拆出去之后才出现的问题」,统称服务治理。
1. 治理地图
服务治理不是单一技术,而是一组能力。下图是常见的能力清单:
| 能力 | 解决的问题 | 常见组件 |
|---|---|---|
| 注册与发现 | 实例地址动态变化,调用方如何找到它 | Nacos、Eureka、Consul、etcd |
| 配置中心 | 配置与代码分离、动态生效 | Nacos、Apollo、Spring Cloud Config |
| API 网关 | 统一入口、路由、鉴权、限流 | Spring Cloud Gateway、Kong、APISIX |
| 负载均衡 | 请求分发到多个实例 | Ribbon(客户端)、LB(服务端) |
| 超时与重试 | 慢请求不拖垮调用方 | 框架内置、Resilience4j |
| 熔断与限流 | 依赖故障或过载时保护自己 | Sentinel、Resilience4j、Hystrix |
| 灰度发布 | 新版本小流量验证 | 网关路由、功能开关 |
| 鉴权与安全 | 谁可以调用谁 | OAuth2、JWT、mTLS |
| 分布式链路 | 跨服务问题定位 | 见 可观测性 |
2. 注册与发现
问题:服务实例的 IP 和端口是动态的(扩缩容、重启、容器调度),调用方不能把地址写死。
做法:
- 服务启动时向注册中心登记「我在哪、健康与否」;
- 调用方从注册中心拉取(或订阅)可用的实例列表;
- 注册中心通过心跳剔除不健康实例。
# Nacos 服务注册(Spring Cloud Alibaba 示意)
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848- Nacos:注册 + 配置一体,AP 模型(也有 CP 模式),国内常用。
- Eureka:经典 AP 实现,已成维护状态。
- Consul / etcd:CP 模型,基于共识,适合强一致协调场景。
注册中心的 CAP 取舍
注册中心通常选 AP:宁可短暂返回略旧的服务列表(可用性优先),也不要因为它不可用导致整个调用链瘫痪。这与 CAP 与 BASE 的取舍直接相关。
3. 配置中心
配置三要素:外部化、集中管理、动态刷新。
# Nacos 配置,配合 @RefreshScope 实现热更新
# Data ID: order-service-prod.yaml
order:
timeout-ms: 3000
retry:
max-attempts: 3@Component
@RefreshScope // 配置变更时自动刷新该 Bean
public class OrderProperties {
@Value("${order.timeout-ms}")
private long timeoutMs;
}要点:
- 配置应与代码分离,同一份镜像靠不同配置跑在不同环境。
- 敏感信息(数据库密码、密钥)用加密存储或独立密钥管理,不要明文进配置中心。
- 变更要有审计与回滚,避免「改错配置导致全站事故」。
4. API 网关
网关是所有外部流量的统一入口,承担横切关注点:
# Spring Cloud Gateway 路由与限流示意
spring:
cloud:
gateway:
routes:
- id: order-route
uri: lb://order-service # lb:// 走服务发现负载均衡
predicates:
- Path=/api/order/**
filters:
- StripPrefix=1网关常见职责:路由转发、鉴权(校验 token)、限流、灰度、协议转换、日志埋点。
要点:网关是关键路径上的单点,必须自身高可用,且不能塞入过重业务逻辑——网关一挂,全站不可用。
5. 超时、重试与熔断
这是治理里最容易被忽视、也最容易出事故的部分。
5.1 超时
先定超时,再谈重试。没有超时的调用会让线程无限等待,最终耗尽连接池与线程池。
- 上游超时必须大于下游处理时间加网络开销;
- 调用链上的超时应逐层递减,避免最底层还在跑、上面已经放弃。
5.2 重试
重试必须遵守三条纪律:
- 被调方必须幂等——否则重试 = 重复扣款;
- 要有退避(指数退避 + 抖动),避免「重试风暴」同时打爆下游;
- 要有预算/上限——限制重试次数与放大倍数。
5.3 熔断与限流
- 熔断:当依赖的失败率或慢调用比例超过阈值,打开断路器,后续请求直接快速失败(fail-fast),不再傻等;经过一段时间进入半开状态试探恢复。
- 限流:限制自己的入口速率,保护自身不过载。详见 限流降级熔断。
// Resilience4j 熔断示意
@CircuitBreaker(name = "inventoryService", fallbackMethod = "fallback")
public StockInfo getStock(String sku) {
return inventoryClient.query(sku);
}
public StockInfo fallback(String sku, Throwable t) {
// 降级:返回兜底数据或稍后重试提示
return StockInfo.unknown(sku);
}6. 灰度发布
新版本不能一次性全量放开。常见策略:
| 策略 | 做法 | 特点 |
|---|---|---|
| 蓝绿部署 | 两套环境,切流量 | 切换快、可秒级回滚,但资源翻倍 |
| 金丝雀(Canary) | 小比例流量先到新版本,逐步放大 | 风险可控,需观测配套 |
| 功能开关(Feature Flag) | 代码里按开关决定行为 | 无需重新部署即可开关功能 |
| 按维度路由 | 按用户 ID/地域/设备分流 | 精准灰度,便于对比 |
没有回滚预案的发布等于裸奔
任何发布都要能快速回滚:保留上一个可用版本、数据库变更要向后兼容(可加不可删)、有明确的回滚触发指标。
7. 实践要点与常见坑
- 超时没设或设得太长:一个慢依赖拖垮整个线程池。
- 重试放大故障:下游已经过载,上游还疯狂重试,形成雪崩。
- 网关塞业务:把风控、聚合逻辑都放网关,网关变成新的「大单体」。
- 配置热更新引发的事故:改了限流阈值/超时却没人知道,要有变更审计。
- 级联健康检查:健康检查失败导致实例被摘除,进而触发更多重试——要设好就绪探针。
- 注册中心脑裂:AP 模型下可能返回已下线实例,靠客户端的容错与重试兜底。
8. 小结
- 服务治理是一整套能力:注册发现、配置中心、网关、负载均衡、超时重试、熔断限流、灰度发布。
- 先定超时,再谈重试;重试必须配幂等、退避与预算。
- 熔断保护依赖、限流保护自己,二者常配合网关使用。
- 发布必须可灰度、可观测、可回滚。
- 治理的目标是让不确定性可控,而不是追求零故障。