# 06.微服务-Sentinel

# 1.分布式系统可能遇到的问题

  • 流量突发:大量的流量突然打到服务器

  • 雪崩效应:微服务间相互依赖,一旦某个服务响应变慢或出现异常,调用它的上游服务线程会堆积,最终可能导致整个调用链路瘫痪

  • 负载不均:入口流量与负载不平衡


# 2.问题解决方案

容错机制

  • 超时机制:在不做任何处理的情况下,服务提供者不可用会导致消费者请求线程强制等待,而造成系统资源耗尽。加入超时机制,一旦超时就释放资源

  • 服务限流机制:限制用户访问数量为500QPS,超过500QPS就会访问失败,或者排队,也可能是其他的一些策略

  • 隔离:用户的请求不再直接访问服务器,而是根据线程去访问,如果线程满了,就会进行降级处理。

  • 服务熔断:当有大量请求访问服务都失败时,就没必要再让其进行访问了,就可以熔断,可能会让服务缓一会,处于半开状态,再让其进行访问

  • 服务降级:就是当某个服务熔断之后,服务将不再被调用,此时客户端可以自己准备一个本地的fallback(回退)回调,返回一个缺省值。例如:(备用接口/缓存/mock数据)。这样做,虽然服务水平下降,但好在可用,比直接挂掉要强,当然这也要看适合的业务场景。


# 3.Sentinel

Sentinel 是阿里巴巴开源的一款面向分布式服务架构的流量治理组件。它的核心价值在于,以流量为切入点,通过流量控制、熔断降级、系统自适应保护等手段,来保障微服务的稳定性和高可用性。

# 3.1 流控规则初体验

核心依赖

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.8.6</version>
</dependency>
1
2
3
4
5

代码

@Slf4j
@RestController
public class HelloController {

    public static final String RESOURCE_NAME = "hello";

    @RequestMapping("/hello")
    public String hello(){
        initFlowRules();
        Entry entry = null;
        try {
            // sentinel针对资源进行限制
            entry = SphU.entry(RESOURCE_NAME);
            // 被保护的业务逻辑
            return "hello world";
        } catch (BlockException e) {
            log.info("block");
            return "限流了";
        }
    }

    @PostConstruct
    private static void initFlowRules(){
        //流控规则
        List<FlowRule> rules = new ArrayList<>();
        //流控
        FlowRule rule = new FlowRule();
        //设置受保护的资源
        rule.setResource(RESOURCE_NAME);
        //设置流控规则 QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        //设置受保护的资源阈值
        rule.setCount(1);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 3.2@SentinelResource注解

@SentinelResource 核心参数表

参数名 描述与说明
value 资源名称。这是最重要的参数,Sentinel 通过它来识别和关联限流、降级规则,不能为空。
entryType 资源调用方向,默认为 EntryType.OUT(出口流量)。可以标记是入口流量(IN)还是出口流量(OUT)。
resourceType 资源的分类,可以用于更细致的资源管理
blockHandler 限流/熔断降级方法。当触发流控或熔断规则(抛出 BlockException)时,会调用此方法。
blockHandlerClass 指定 blockHandler 方法所在的类。如果降级方法在其他类中,需要配置此项,且该方法必须是 public static 的。
fallback 业务异常降级方法。当原方法抛出 BlockException 的业务异常时,会调用此方法作为兜底。
fallbackClass 指定 fallback 方法所在的类。如果降级方法在其他类中,需要配置此项,且该方法必须是 public static 的。
defaultFallback 默认降级方法。一个通用的 fallback,可以同时作用于多个方法。如果同时配置了 fallback,则 fallback 优先。
exceptionsToIgnore 指定忽略的异常。被列出的异常会被原样抛出,既不会计入异常统计,也不会触发 fallback 逻辑。

注意事项

  • blockHandler对应的方法只能是public

  • SentinelResource注解的方法名和参数一致

  • 可以在参数最后加BlockException区分是什么规则的处理方法

使用示例

1.先增加依赖

<!--@SentinelResource 注解依赖-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-annotation-aspectj</artifactId>
            <version>1.8.6</version>
        </dependency>
1
2
3
4
5
6

2.进行切面配置

@SentinelResource 注解本身只是一个标记,需要 AOP 切面来拦截方法调用并应用限流规则。如果没有配置 SentinelResourceAspect,注解会被完全忽略。

import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SentinelConfig {

    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

3.编写java代码

    @SentinelResource(value = USER_RESOURCE_NAME, blockHandler = "handleException",fallback = "FallbackException")
    @RequestMapping("/user")
    public User user(){
        int a=1/0;
        return new User("qq");
    }
    //1.只能是public,2.与SentinelResource注解的方法名和参数一致,
    // 3.可以在参数最后加BlockException,区分是什么规则的处理方法
    public User handleException(BlockException ex){
        return new User("handleException");
    }

    public User FallbackException(Throwable ex){
        return new User("FallbackException");
    }


    @PostConstruct
    private static void initFlowRules(){
        //流控规则
        List<FlowRule> rules = new ArrayList<>();
        //流控
        FlowRule rule = new FlowRule();
        //设置受保护的资源
        rule.setResource(RESOURCE_NAME);
        //设置流控规则 QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        //设置受保护的资源阈值
        rule.setCount(1);
        rules.add(rule);

        //user流控规则
        FlowRule rule2 = new FlowRule();
        rule2.setResource(USER_RESOURCE_NAME);
        rule2.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule2.setCount(1);
        rules.add(rule2);
        FlowRuleManager.loadRules(rules);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 3.3降级规则

设置降级规则的参数

Field 说明 默认值
resource 资源名,即规则的作用对象
grade 熔断策略,支持慢调用比例/异常比例/异常数策略 慢调用比例
count 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
timeWindow 熔断时长,单位为 s
minRequestAmount 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) 5
statIntervalMs 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) 1000 ms
slowRatioThreshold 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)

半开状态的过程:

  1. 触发熔断(OPEN):当慢调用比例、异常比例等指标达到阈值后,熔断器会进入 OPEN(开启) 状态,此后所有对该资源的请求都会被直接拒绝

  2. 等待恢复(熔断时长):经过一段您设定的时间(即 熔断时长,默认单位是秒)后,熔断器会尝试恢复,从 OPEN 状态转变为 HALF_OPEN(半开) 状态

  3. 探测恢复(HALF_OPEN):在半开状态下,Sentinel 会放行一个请求来做探测

    • 如果这个请求成功了,说明服务已恢复,熔断器变为 CLOSED(关闭) 状态如果这个请求失败了,则说明服务还不稳定,熔断器会再次变为 OPEN 状态,继续熔断,并重新开始计时

代码示例:

@RequestMapping("/degrade")
    @SentinelResource(value = DEGRADE_RESOURCE_NAME, blockHandler = "handleDegrade")
    public String degrade(){
        int a = 1/0;
        return "degrade";
    }
    public String handleDegrade(BlockException ex){
        return "degrade降级了";
    }

    @PostConstruct
    public static void initDegradeRule(){
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule();
        rule.setResource(DEGRADE_RESOURCE_NAME);
        //根据异常数降级
        rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
        //异常数
        rule.setCount(2);
        //最小请求数
        rule.setMinRequestAmount(2);
        //10s(半开状态)
        rule.setTimeWindow(10);
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 3.4 控制台

下载完控制台后,要想使控制台监控到服务必须有以下两个操作(已经启动控制台)

方式一:

1)引入maven依赖

<dependency>
     <groupId>com.alibaba.csp</groupId>
     <artifactId>sentinel-transport-simple-http</artifactId>
     <version>1.8.6</version>
</dependency>
1
2
3
4
5

2)启动时加入 JVM 参数 -Dcsp.sentinel.dashboard.server=consoleIp:port 指定控制台地址和端口。若启动多个应用,则需要通过 -Dcsp.sentinel.api.port=xxxx 指定客户端监控 API 的端口(默认是 8719)。

方式二:也可以用springCloud整合

1)引入maven依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
1
2
3
4

2)配置文件

server:
  port: 8091
spring:
  application:
    name: order-sentinel
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:9090
1
2
3
4
5
6
7
8
9

# 4.流控

# 4.1流控规则

# QPS和线程流控

QPS 流控和并发线程数流控是两种最核心的流量控制策略。它们的核心区别在于:QPS 控制的是“数量”,而并发线程数控制的是“资源占用”。

维度 QPS 流控 并发线程数流控
控制对象 每秒的请求数量 同时处理的请求线程数
触发条件 请求速率超过设定阈值 正在处理的请求线程数超过设定阈值
保护目标 防止流量突增压垮系统 防止慢调用耗尽线程资源
适用场景 突发流量、接口防刷 慢 SQL、第三方 API 耗时、大文件处理
计数器重置 每秒重置 实时统计,不重置
性能开销 极低(滑动窗口计数) 极低(信号量计数)

假设你有一个接口,平均响应时间是 1 秒

配置 QPS 限流(阈值 10) 并发线程数限流(阈值 10)
1 秒内 10 个请求 ✅ 全部通过 ✅ 全部通过(10 个线程同时处理)
1 秒内 20 个请求 ❌ 只通过 10 个,拒绝 10 个 ❌ 同时只处理 10 个,另外 10 个被拒绝
慢查询(3 秒),每秒 5 个请求 ✅ 全部通过(QPS 只有 5) ❌ 累积线程数会超过 10

关键点:QPS 低时,QPS 限流不会触发,但并发线程数限流可能触发!因为慢请求会累积线程。

# 4.2 BlockException统一异常处理

@Component
public class MyBlockException implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        Result r=null;

        if (e instanceof FlowException){
            r= Result.error(100,"限流了");
        } else if (e instanceof DegradeException) {
            r= Result.error(101,"降级了");
        } else if (e instanceof ParamFlowException) {
            r= Result.error(102,"热点参数限流");
        } else if (e instanceof SystemBlockException) {
            r= Result.error(103,"系统规则(负载、异常数)限制");
        }else if (e instanceof AuthorityException) {
            r= Result.error(104,"授权规则不通过");
        }
        //返回json数据
        response.setStatus(500);
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json");
        //转为json数据并返回
        new ObjectMapper().writeValue(response.getWriter(),r);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 4.3 流控模式

# 4.3.1 关联流控模式

关联流控模式是指,当与当前资源有关联关系的另一个资源达到流量阈值时,对当前资源进行限流,而非直接限流触发阈值的那个资源

比如订单和查询商品两个接口,当流量大时,可以限制查询接口的访问,来减少订单的错误

# 4.3.2 链路流控模式

链路流控模式,是指 Sentinel 针对 特定调用链路 上的流量进行限流。 它不像“直接”模式那样针对资源本身,也不像“关联”模式那样针对同级资源,而是精确控制从哪个入口进来的请求”

假设你有一个 queryDB() 方法(资源名:queryDB),它被两个接口调用:

  • /user 接口(入口)

  • /admin 接口(入口)

你想限制 /user 接口对 queryDB 的调用频率,但希望 /admin 接口不受影响。

如果用直接模式:只要 queryDB 的 QPS 超了,不管谁调用都会限流,/admin 也会被误伤。

链路模式:可以精确只限流 用户入口 → queryDB 这条链路,/admin 完全不受影响。

代码示例(同类中的方法需注意代理问题)

@RestController
@RequestMapping("/chain")
public class ChainController {

    @Autowired
    private OrderController orderController;

    @RequestMapping("/admin")
    @SentinelResource(value = "admin",entryType = EntryType.IN)
    public String admin(){
        return orderController.doQuery();
    }

    @RequestMapping("/user")
    @SentinelResource(value = "user",entryType = EntryType.IN)
    public String user(){
        return orderController.doQuery();
    }


}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

配置

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:9090
      web-context-unify: false
1
2
3
4
5
6
配置值 调用链路上下文 链路流控效果
true (默认值) 所有 Web 请求共用同一个上下文(sentinel_web_servlet_context 不生效:所有请求的入口都被视为同一个,无法区分来源
false 每个 Web 请求使用其 URL 路径作为独立的上下文(如 /chain/user 生效:每个接口调用链路相互独立,可以精确识别流量来源

# 4.4 流控效果

流控效果 核心行为 适用场景 特点
快速失败 立即拒绝,抛出异常 大部分场景 简单直接,反应最快
Warm Up 渐进式增加阈值,冷启动保护 系统刚启动/长期空闲后流量突增 防止瞬间流量冲垮刚启动的系统
排队等待 请求排队,匀速处理 需要平滑处理突发流量(如消息队列) 牺牲响应时间换取高吞吐

warm up 慢热,请求慢慢进,稳定了,就进的多

排队等待,就是10000个请求匀速进

# 4.5 热点参数流控

# 4.5.1 介绍

热点参数流控是Sentinel中针对接口参数的“精细化限流”策略,区别于“全局流控”(针对整个接口)。它针对接口中高频访问的参数值(即“热点参数”)单独设置限流规则,避免因某个参数值(如热门商品ID、用户ID)的请求量过大,导致系统压力集中在该参数对应的资源上。

# 4.5.2 适用场景

热点参数流控适用于参数值存在“热点”的场景,例如:

  • 电商秒杀:热门商品(如iPhone 15)的请求量远高于普通商品,需限制该商品ID的QPS,避免系统过载。
  • API接口:某个用户ID(如“admin”)的请求量异常高(如刷接口),需限制该用户ID的访问频率。
  • 数据查询:某个关键词(如“人工智能”)的搜索请求量远高于其他关键词,需限制该关键词的QPS。

# 4.5.3 代码示例

直接在控制台配置限流规则就行

    @GetMapping("/{id}")
    @SentinelResource(value = "get",blockHandler = "handleException")
    public String get(@PathVariable Integer id){
        return "查询成功,id:"+id;
    }
    public String handleException(Integer id, BlockException ex){
        return "限流了";
    }
1
2
3
4
5
6
7
8

# 5.熔断

# 5.1熔断策略

维度 慢调用比例 (SLOW_REQUEST_RATIO) 异常比例 (ERROR_RATIO) 异常数 (ERROR_COUNT)
统计指标 响应时间超过最大RT的请求比例 请求抛出异常的比例 请求抛出异常的绝对数量
适用场景 服务响应变慢,但还没挂 服务不稳定,异常率突然升高 对异常数量敏感,达到一定量就熔断
阈值类型 比例(0.0 ~ 1.0) 比例(0.0 ~ 1.0) 数量(整数)
最小请求数 必须达到,否则不计算 必须达到,否则不计算 必须达到,否则不计算
统计窗口 可配置(默认 1s/10s 等) 可配置 可配置(60s 滑动窗口

配置示例

慢调用比例

熔断策略: 慢调用比例
最大RT: 200ms          # 超过 200ms 算慢调用
比例阈值: 0.5          # 慢调用比例 ≥ 50% 时触发熔断
最小请求数: 5          # 统计窗口内至少 5 个请求才计算
统计时长: 1s           # 统计 1 秒内的数据
熔断时长: 5s           # 熔断持续 5 秒
1
2
3
4
5
6

异常比例

熔断策略: 异常比例
比例阈值: 0.2          # 异常比例 ≥ 20% 时触发熔断
最小请求数: 10         # 统计窗口内至少 10 个请求才计算
统计时长: 1s           # 统计 1 秒内的数据
熔断时长: 10s          # 熔断持续 10 秒
1
2
3
4
5

异常数

熔断策略: 异常数
异常数阈值: 5           # 异常数 ≥ 5 时触发熔断
最小请求数: 3           # 统计窗口内至少 3 个请求才计算
统计时长: 60s           # 固定 60 秒滑动窗口
熔断时长: 10s           # 熔断持续 10 秒
1
2
3
4
5

# 5.2 整合OpenFeign

步骤1:引入maven依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
    </dependencies>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

步骤二:配置yml文件

server:
  port: 8091
spring:
  application:
    name: order-openfeign-sentinel
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:9090
      web-context-unify: false
    nacos:
      server-addr: 47.94.9.59:8848
      discovery:
        username: nacos
        password: 2eb4e10f
    # 开启Feign的熔断(Resilience4j)
    openfeign:
      circuitbreaker:
        enabled: true
#启用 Feign 对 Sentinel 的支持        
feign:
  sentinel:
    enabled: true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

步骤三:引入远程接口并编写降级策略(别忘了在启动类开启feign支持---@EnableFeignClients)

@Component
@FeignClient(value = "stock-service",path = "/stock",fallback = StockServiceFallback.class)
public interface StockFeignService {
    @RequestMapping("/deduct")
    String deduct();
}
1
2
3
4
5
6

降级策略

@Component
public class StockServiceFallback implements StockFeignService {
    @Override
    public String deduct() {
        return "降级了";
    }
}
1
2
3
4
5
6
7

步骤四:调用远程接口

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private StockFeignService stockFeignService;

    @RequestMapping("/add")
    public String add(){
        System.out.println("下单成功");
        String msg = stockFeignService.deduct();
        return "hello feign"+msg;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

步骤五:在控制台配置降级策略


# 6.其他规则

# 6.1 系统规则

系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 Load、RT、入口 QPS 和线程数四个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。

系统规则支持以下的阈值类型:

  • Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5
  • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0)。
  • RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

# 6.2 sentinel持久化

使用示例:

1.引入依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
1
2
3
4
5
6
7
8

2.配置yml文件

server:
  port: 8091
spring:
  application:
    name: sentinel-persistent
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:9090
      web-context-unify: false
      datasource:
        # 数据源的名称,可以自定义
        flow-rules:
          nacos:
            username: nacos
            password: 2eb4e10f
            server-addr: 47.94.9.59:8848 # Nacos服务地址
            dataId: ${spring.application.name}-flow-rules # Nacos中配置的Data ID
            groupId: DEFAULT_GROUP # 分组,可自定义
            data-type: json # 配置数据格式
            rule-type: flow # 规则类型:flow(流控), degrade(熔断), param-flow(热点)等
    nacos:
      server-addr: 47.94.9.59:8848
      discovery:
        username: nacos
        password: 2eb4e10f
    # 开启Feign的熔断(Resilience4j)
    openfeign:
      circuitbreaker:
        enabled: true

#启用 Feign 对 Sentinel 的支持
feign:
  sentinel:
    enabled: true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

3.nacos中配置文件

 [ 
   { 
     "resource": "/order/get", 
     "controlBehavior": 0, 
     "count": 3, 
     "grade": 1, 
     "limitApp": "default", 
     "strategy": 0 
   } 
]

1
2
3
4
5
6
7
8
9
10
11

完成配置后访问方法,就可以在控制台看到对应的限流配置了

最近更新: 9/19/2026, 1:27:08 PM
编程NOTE   |