Skip to content
Home
Go back

Spring Cloud Sentinel:给微服务装上保险丝

回顾:当前链路的风险

到上一篇为止,我们的微服务调用链路是这样的:

外部请求 → Gateway(8080) → order-service(8082) → [Feign] → payment-service(8081/8083)

这条链路跑起来很顺畅,但它有一个致命假设:payment-service 永远可用。

真实生产环境不是这样的。payment-service 可能因为数据库慢查询、第三方支付接口超时、或者单纯流量太大而响应变慢。一旦它慢了,order-service 调用它的线程就会卡住;新的请求还在不断进来,线程越积越多,最终 order-service 也被拖垮。然后调用 order-service 的上游跟着遭殃——雪崩来了。

雪崩效应

想象一个供应链系统:采购服务调入库服务,入库服务调校验服务。如果校验服务因为某个外部接口超时,响应从 50ms 变成 5s:

  1. 入库服务调用校验的线程开始堆积
  2. 入库服务的线程池用完,开始拒绝新的请求
  3. 采购服务调用入库也失败了
  4. 整个系统从前到后全部瘫痪

问题的根源不是某一个服务挂了,而是挂掉的那一个没有被隔离——它的故障沿着调用链传染给了所有依赖它的服务。

Sentinel 就是来切断这种传染的。

Sentinel 是什么

Sentinel 是阿里巴巴开源的流量控制与熔断降级组件。它的名字直译就是「哨兵」——站在流量入口,决定哪些请求放行、哪些请求拒绝、哪些请求降级处理。

它提供三种核心能力:

能力问题手段
熔断下游服务不可用时还不断发请求检测失败率 → 打开断路器 → 快速失败
限流流量超过系统承载能力设定 QPS 阈值,超出的直接拒绝
降级服务不可用时要给用户一个交代返回预设的兜底结果,不抛异常

更关键的是:Sentinel 提供了一个可视化的 Dashboard 控制台,你可以在上面实时修改规则,不需要重启服务。熔断阈值从 50% 调到 30%,点一下发布,立刻生效。

核心概念

熔断(Circuit Breaker)

断路器有三种状态:

  1. 关闭(Closed):正常状态,请求正常通过。Sentinel 在后台统计每个资源的失败比例
  2. 打开(Open):失败比例达到阈值,断路器打开,所有对该资源的调用直接拒绝,不再发给下游
  3. 半开(Half-Open):一段时间后,断路器放一个请求过去试探。如果成功,回到关闭状态;如果失败,继续打开

这就是物理世界中保险丝的逻辑:正常导通,电流过大时断开,过一会试探性恢复。

限流(Rate Limiting)

设定每秒钟最多通过多少个请求,超过的直接拒绝。比如支付接口最多承受 100 QPS,你设置 80 QPS 作为限流阈值,留 20 的缓冲。限流的关键在于:不是等系统已经扛不住了再动手,而是主动控制流量,让系统始终在安全区间内运行。

降级(Fallback)

当熔断或者限流发生时,你不能直接给用户返回 500 错误。降级就是准备一个「兜底结果」:比如支付服务熔断了,返回「支付系统繁忙,请稍后重试」,并记录订单稍后补扣。用户体验虽然打了折扣,但比直接报错好得多。

动手:给 order-service 加 Sentinel 保护

引入依赖与 Dashboard

order-servicepom.xml 中加入:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

添加 Sentinel Dashboard 连接配置(application.yml):

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080

下载并启动 Sentinel Dashboard(一个独立的 Spring Boot 应用):

java -jar sentinel-dashboard.jar --server.port=8080

默认用户名密码都是 sentinel

配置熔断规则

在 Feign 接口上配置 fallback:

@FeignClient(name = "payment-service", fallback = PaymentClientFallback.class)
public interface PaymentClient {

    @GetMapping("/pay")
    String pay();
}

编写 fallback 实现:

@Component
public class PaymentClientFallback implements PaymentClient {

    @Override
    public String pay() {
        return "Payment service is currently unavailable. Please try again later.";
    }
}

现在 @FeignClientfallback 会自动生效:当 payment-service 调用失败比例达到阈值,Sentinel 会自动切到 PaymentClientFallback 的兜底实现。

配置熔断规则

在 Sentinel Dashboard 中找到 payment-service 资源,添加降级规则:

这条规则的意思是:最近 5 个请求中,如果超过 50% 的响应时间大于 100ms,触发熔断,10 秒内所有请求走 fallback。

验证

启动 payment-serviceorder-service 和 Sentinel Dashboard。

正常访问 http://localhost:8082/order

Order created. Payment successful from port: 8081

现在停掉 payment-service,再次访问:

Order created. Payment service is currently unavailable. Please try again later.

注意:返回的不是 500 异常,而是 fallback 里预设的兜底消息。order-service 本身没有崩溃。

打开 Sentinel Dashboard,可以看到 payment-service 的实时流量、熔断状态、以及触发的规则。

小结与下篇预告

这一篇我们给微服务装上了三道保险:

  1. 理解雪崩效应的传播机制——一个服务慢,所有依赖者一起遭殃
  2. Sentinel 的三种核心能力:熔断(断路器状态机)、限流(主动控流)、降级(兜底响应)
  3. 动手:Feign 集成 Sentinel,写 fallback,Dashboard 实时调整规则
  4. 验证:停掉 payment-service,order-service 不崩溃,返回优雅的兜底信息

现在服务是稳了。但稳只解决了一半的问题:如果 order-service 创建订单和 payment-service 扣款这两件事需要保证原子性怎么办?订单创建成功了但扣款失败了,这笔账怎么算?

下一篇,我们进入分布式事务,用 Seata AT 模式解决跨服务的数据一致性问题。



Previous Post
Spring Cloud 系列合集
Next Post
Spring Cloud Gateway:微服务统一入口