# 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>
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);
}
}
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>
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();
}
}
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);
}
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 引入) |
半开状态的过程:
触发熔断(OPEN):当慢调用比例、异常比例等指标达到阈值后,熔断器会进入 OPEN(开启) 状态,此后所有对该资源的请求都会被直接拒绝
等待恢复(熔断时长):经过一段您设定的时间(即 熔断时长,默认单位是秒)后,熔断器会尝试恢复,从 OPEN 状态转变为 HALF_OPEN(半开) 状态
探测恢复(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);
}
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>
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>
2
3
4
2)配置文件
server:
port: 8091
spring:
application:
name: order-sentinel
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:9090
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);
}
}
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();
}
}
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
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 "限流了";
}
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 秒
2
3
4
5
6
异常比例
熔断策略: 异常比例
比例阈值: 0.2 # 异常比例 ≥ 20% 时触发熔断
最小请求数: 10 # 统计窗口内至少 10 个请求才计算
统计时长: 1s # 统计 1 秒内的数据
熔断时长: 10s # 熔断持续 10 秒
2
3
4
5
异常数
熔断策略: 异常数
异常数阈值: 5 # 异常数 ≥ 5 时触发熔断
最小请求数: 3 # 统计窗口内至少 3 个请求才计算
统计时长: 60s # 固定 60 秒滑动窗口
熔断时长: 10s # 熔断持续 10 秒
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>
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
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();
}
2
3
4
5
6
降级策略
@Component
public class StockServiceFallback implements StockFeignService {
@Override
public String deduct() {
return "降级了";
}
}
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;
}
}
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>
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
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
}
]
2
3
4
5
6
7
8
9
10
11
完成配置后访问方法,就可以在控制台看到对应的限流配置了