Skip to content

Sentinel 限流熔断与降级

6.1 Sentinel 是什么?

Sentinel 是面向分布式服务架构的流量治理组件。

它可以做:

text
接口限流
熔断降级
热点参数限流
系统保护
授权规则
实时监控

简单理解:

text
Sentinel 是微服务的流量防卫兵。

6.2 Sentinel 核心概念

6.2.1 资源 Resource

资源就是 Sentinel 要保护的对象。

常见资源:

text
一个 Controller 接口
一个 Feign 调用
一个方法
一个网关路由

例如:

text
/order/create
/stock/reduce
GET:http://stock-service/stock/info

6.2.2 规则 Rule

规则就是如何保护资源。

常见规则:

text
流控规则
熔断规则
热点规则
系统规则
授权规则

6.2.3 QPS

QPS 是每秒请求数。

例如:

text
QPS = 1

表示:

text
每秒最多允许 1 个请求通过。
超过的请求会被限流。

6.2.4 并发线程数

线程数限流不是按每秒多少请求,而是按当前正在处理的请求数量限制。

例如:

text
线程数 = 10

表示:

text
同一时刻最多允许 10 个请求正在处理。

6.2.5 熔断降级

当下游服务异常比例过高、慢调用过多时,Sentinel 可以暂时熔断。

流程:

text
正常调用

下游异常增多

达到熔断规则

进入熔断状态

请求快速失败或走 fallback

过一段时间进入半开

尝试恢复调用

成功则关闭熔断,失败则继续熔断

6.3 Sentinel 依赖

在需要保护的服务中引入:

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

如果要结合 Feign,需要同时有:

xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

6.4 配置 Sentinel Dashboard

yaml
spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080

如果 Sentinel Dashboard 是 8858 端口:

yaml
spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8858

6.5 Sentinel 懒加载机制

Sentinel 默认是懒加载。

意思是:

text
服务刚启动时,Sentinel 控制台可能看不到该服务。
必须有接口被访问过,Sentinel 才会上报资源。

操作流程:

text
1. 启动 sentinel-dashboard
2. 启动微服务
3. 访问一次接口
4. 打开 Sentinel 控制台
5. 刷新页面
6. 左侧出现服务名

6.6 接口限流实战

假设接口:

text
http://localhost:8081/order/create?productId=1001&count=2

访问一次后,进入 Sentinel 控制台:

text
order-service -> 簇点链路

找到资源:

text
/order/create

点击:

text
+ 流控

配置:

text
阈值类型:QPS
单机阈值:1
流控模式:直接
流控效果:快速失败

保存后快速刷新接口。

如果出现:

text
Blocked by Sentinel (flow limiting)

说明限流生效。


6.7 自定义限流返回

默认限流返回不友好:

text
Blocked by Sentinel (flow limiting)

可以自定义 BlockExceptionHandler。

java
package com.demo.order.sentinel;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@Component
public class CustomBlockExceptionHandler implements BlockExceptionHandler {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void handle(HttpServletRequest request,
                       HttpServletResponse response,
                       String resourceName,
                       BlockException e) throws Exception {

        response.setStatus(429);
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        response.setContentType("application/json;charset=UTF-8");

        Map<String, Object> body = new HashMap<>();
        body.put("code", 429);
        body.put("message", "请求过于频繁,请稍后再试");
        body.put("resource", resourceName);

        response.getWriter().write(objectMapper.writeValueAsString(body));
    }
}

6.8 Feign 结合 Sentinel 降级

开启 Sentinel 对 Feign 的支持:

yaml
spring:
  cloud:
    openfeign:
      sentinel:
        enabled: true

Feign 接口:

java
package com.demo.order.client;

import com.demo.order.client.fallback.StockClientFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

@FeignClient(
        name = "stock-service",
        fallback = StockClientFallback.class
)
public interface StockClient {

    @PostMapping("/stock/reduce")
    String reduce(@RequestParam("productId") Long productId,
                  @RequestParam("count") Integer count);
}

Fallback:

java
package com.demo.order.client.fallback;

import com.demo.order.client.StockClient;
import org.springframework.stereotype.Component;

@Component
public class StockClientFallback implements StockClient {

    @Override
    public String info() {
        return "库存服务暂时不可用,返回默认库存信息";
    }

    @Override
    public String reduce(Long productId, Integer count) {
        return "库存服务暂时不可用,扣减库存失败,已进入降级逻辑";
    }
}

stock-service 挂掉或超时后,order-service 可以返回兜底结果。


6.9 fallbackFactory 获取异常原因

如果想知道异常原因,可以使用 FallbackFactory

Feign:

java
package com.demo.order.client;

import com.demo.order.client.fallback.StockClientFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

@FeignClient(
        name = "stock-service",
        fallbackFactory = StockClientFallbackFactory.class
)
public interface StockClient {

    @PostMapping("/stock/reduce")
    String reduce(@RequestParam("productId") Long productId,
                  @RequestParam("count") Integer count);
}

FallbackFactory:

java
package com.demo.order.client.fallback;

import com.demo.order.client.StockClient;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;

@Component
public class StockClientFallbackFactory implements FallbackFactory<StockClient> {

    @Override
    public StockClient create(Throwable cause) {
        return new StockClient() {

            @Override
            public String reduce(Long productId, Integer count) {
                return "库存服务异常,降级处理,原因:" + cause.getMessage();
            }
        };
    }
}

6.10 Sentinel 熔断规则理解

常见熔断策略:

text
慢调用比例
异常比例
异常数

慢调用比例

例如:

text
最大 RT:1000ms
比例阈值:0.5
熔断时长:10s
最小请求数:5
统计时长:10000ms

意思:

text
在统计窗口内,至少有 5 个请求。
如果超过 50% 的请求响应时间大于 1000ms,则触发熔断。
熔断持续 10 秒。

异常比例

例如:

text
异常比例:0.5
最小请求数:5
熔断时长:10s

意思:

text
统计窗口内至少 5 个请求。
如果异常比例超过 50%,触发熔断。

异常数

例如:

text
异常数:5
统计时长:10000ms
熔断时长:10s

意思:

text
10 秒内异常数量达到 5 次,触发熔断。

6.11 Sentinel 规则持久化

注意:

text
Sentinel Dashboard 手动配置的规则默认保存在内存中。
服务重启后规则可能会丢失。

生产环境一般需要规则持久化:

text
Sentinel Dashboard

Nacos Config

微服务监听规则配置

常见规则类型:

text
流控规则
降级规则
热点参数规则
系统保护规则
授权规则

Released under the MIT License.