前言
在微服务架构中,服务间的依赖关系复杂,一个服务的故障可能引发连锁反应,导致整个系统雪崩。Sentinel 作为阿里巴巴开源的流量控制框架,能从流量控制、熔断降级等维度保护服务稳定性。本文将从实战角度,完整讲解 Sentinel 的核心概念、使用方式及各类规则配置。
一、Sentinel 核心概念
1.1 什么是 Sentinel
Sentinel(分布式系统的流量防卫兵)以流量为切入点,提供流量控制 、熔断降级 、系统负载保护等能力,保障微服务高可用。
1.2 核心概念
- 资源:Sentinel 要保护的对象,可是一个接口、方法、服务等。
- 规则:定义保护资源的策略,包括流量控制、熔断降级、热点参数、系统规则、授权规则等。
- 核心功能 :
- 流量控制:限制接口 QPS / 线程数,避免服务被压垮。
- 熔断降级:当下游服务异常时,暂时切断调用,防止级联故障。
二、环境准备
2.1 搭建基础微服务
2.1.1 服务提供者(sentinel-provider)
application.yml
server:
port: 9090
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.209.129:8848
application:
name: sentinel-provider
核心服务类
java
@Service
public class UserServiceImpl implements UserService {
@Override
public User getUserById(Integer id) {
// 模拟网络延时
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new User(id,"王粪堆-provider",18);
}
}
2.1.2 Feign 接口(sentinel_feign)
java
@FeignClient("sentinel-provider")
public interface UserFeign {
@RequestMapping(value = "/provider/getUserById/{id}")
public User getUserById(@PathVariable Integer id);
}
2.1.3 服务消费者(sentinel_consumer)
pom.xml
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud_parent</artifactId>
<groupId>com.hg</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sentinel_consumer</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.hg</groupId>
<artifactId>springcloud_common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--feign接口-->
<dependency>
<groupId>com.hg</groupId>
<artifactId>sentinel_feign</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--Sentinel核心依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
</project>
application.yml
server:
port: 8080
tomcat:
max-threads: 10 # 降低tomcat并发,便于测试雪崩
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.209.129:8848
sentinel:
transport:
dashboard: 127.0.0.1:8080 # Sentinel控制台地址
feign:
client:
config:
default:
connectionTimeout: 5000
readTimeout: 5000
sentinel:
enabled: true # 开启Feign整合Sentinel
三、Sentinel 快速入门
3.1 方式 1:硬编码(抛异常方式)
java
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@RequestMapping(value = "/hello")
public String hello() {
Entry entry = null;
try {
// 定义资源
entry = SphU.entry("/consumer/hello");
return "Hello Sentinel!!!";
} catch (BlockException e) {
// 限流兜底逻辑
return "接口被限流了, exception: " + e;
}finally {
if (entry != null) {
entry.exit();
}
}
}
// 初始化限流规则
@PostConstruct
public void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule1 = new FlowRule();
rule1.setResource("/consumer/hello"); // 资源名
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS); // 按QPS限流
rule1.setCount(2); // QPS阈值2
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
}
3.2 方式 2:注解方式(推荐)
java
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
// 开启Sentinel注解支持
@Bean
public SentinelResourceAspect sentinelResourceAspect(){
return new SentinelResourceAspect();
}
@RequestMapping(value = "/hello2")
@SentinelResource(value="/consumer/hello2",blockHandler = "blockHandlerMethod")
public String hello2() {
return "Hello Sentinel2!!!";
}
// 限流兜底方法
public String blockHandlerMethod(BlockException e){
return "接口被限流了, exception: " + e;
}
@PostConstruct
public void initFlowQpsRule() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule1 = new FlowRule();
rule1.setResource("/consumer/hello2");
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setCount(2);
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
}
3.3 Sentinel 控制台使用
3.3.1 启动控制台
bash
# 下载地址:https://github.com/alibaba/Sentinel/releases
java -jar sentinel-dashboard-1.8.1.jar
访问 http://localhost:8080,默认账号 / 密码:sentinel/sentinel。
3.3.2 接入控制台
消费者配置文件中添加:
yaml:
spring:
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080
访问任意接口(如 http://127.0.0.1:8080/consumer/hello3),控制台即可识别服务。
四、Sentinel 核心规则配置
4.1 流量控制规则
流量控制是 Sentinel 最核心的功能,通过限制 QPS / 线程数,防止服务被压垮。
4.1.1 核心配置项说明
| 配置项 | 说明 |
|---|---|
| 资源名 | 唯一标识,默认请求路径 |
| 针对来源 | 限制调用方(默认 default,不区分来源) |
| 阈值类型 | QPS(每秒请求数)/ 线程数 |
| 流控模式 | 直接(限流当前接口)/ 关联(关联接口阈值触发限流)/ 链路(指定入口限流) |
| 流控效果 | 快速失败 / Warm Up(预热)/ 排队等待 |
4.1.2 典型场景配置
(1)QPS 限流
- 规则配置:资源名
/consumer/getUserById/{id},阈值类型 QPS,单机阈值 2; - 效果:接口 QPS 超过 2 时,直接触发限流。
(2)Warm Up(预热限流)
- 适用场景:流量突增(如秒杀),避免瞬间打满服务;
- 规则配置:阈值类型 QPS,单机阈值 6,预热时长 5 秒;
- 效果:QPS 从 2(6/3)开始,5 秒后升至 6,平滑提升流量处理能力。
(3)排队等待
- 适用场景:需要匀速处理请求(如削峰填谷);
- 规则配置:阈值类型 QPS,单机阈值 1,排队超时时间 10ms;
- 效果:请求匀速通过,超时未处理的请求直接丢弃。
4.2 热点参数限流
对接口参数做精细化限流,支持参数例外项(如特定 ID 放宽阈值)。
java
@RequestMapping(value = "/getUserById/{id}")
@SentinelResource(value = "getUserById", blockHandler = "blockHandlerMethod")
public User getUserById(@PathVariable Integer id) {
return userFeign.getUserById(id);
}
// 热点参数限流兜底方法
public User blockHandlerMethod(Integer id, BlockException e) {
return new User(id, "热点参数限流触发", 0);
}
- 规则配置:资源名
getUserById,参数索引 0(第一个参数),单机阈值 2; - 例外项配置:参数值 2,阈值 3(ID=2 时 QPS 阈值提升至 3)。
4.3 熔断降级规则
当接口响应慢 / 异常比例高时,暂时切断调用,避免级联故障。
4.3.1 三种熔断策略
| 策略 | 触发条件 |
|---|---|
| 慢调用比例 | 慢调用(RT 超过阈值)占比超过设定值,且请求数≥最小请求数 |
| 异常比例 | 异常请求占比超过设定值,且请求数≥最小请求数 |
| 异常数 | 异常请求数超过设定值,且请求数≥最小请求数 |
4.3.2 配置示例(慢调用比例)
- 规则配置:资源名
/consumer/getUserById/{id},最大 RT 200ms,比例阈值 0.5,熔断时长 5s,最小请求数 5; - 效果:5 个请求中若 50% 以上 RT 超过 200ms,触发熔断,5 秒内拒绝所有请求。
4.4 授权规则
基于请求来源做黑白名单控制,适合接口访问权限管控。
4.4.1 实现来源解析
java
@Component
public class RequestOriginParserDefinition implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
// 从请求参数获取来源标识(可替换为请求头、Session等)
return request.getParameter("origin");
}
}
4.4.2 规则配置
- 黑名单:资源名
/consumer/getUserById/{id},黑名单值app1; - 效果:来源为
app1的请求直接被拒绝。
4.5 系统规则
针对整个应用的全局规则(粒度粗,慎用),支持:
- LOAD(Linux 系统负载);
- RT(所有请求平均响应时间);
- 线程数(所有请求总线程数);
- 入口 QPS(所有接口总 QPS);
- CPU 使用率。
五、Sentinel 高级特性
5.1 自定义兜底逻辑(blockHandler)
5.1.1 同级别兜底(当前类)
java
@SentinelResource(value = "getUserById", blockHandler = "blockHandlerMethod")
public User getUserById(@PathVariable Integer id) {
return userFeign.getUserById(id);
}
// 兜底方法(参数与原方法一致,最后加BlockException)
public User blockHandlerMethod(Integer id, BlockException e) {
return new User(0, "接口被流控/熔断:"+e, 0);
}
5.1.2 外置兜底类(解耦)
java
// 外置兜底类(方法必须static)
public class BlockHandlerClass {
public static User blockHandlerMethod(Integer id, BlockException e) {
return new User(0, "外置兜底:"+e, 0);
}
}
// 使用外置兜底类
@SentinelResource(value = "getUserById",
blockHandler = "blockHandlerMethod",
blockHandlerClass = BlockHandlerClass.class)
public User getUserById(@PathVariable Integer id) {
return userFeign.getUserById(id);
}
5.2 全局异常处理
统一处理 Sentinel 各类异常,返回标准化响应。
java
@Component
public class GlobalBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
response.setContentType("application/json;charset=utf-8");
Result data = null;
if (e instanceof FlowException) {
data = new Result(-1, "限流异常");
} else if (e instanceof DegradeException) {
data = new Result(-2, "降级异常");
} else if (e instanceof ParamFlowException) {
data = new Result(-3, "参数限流异常");
} else if (e instanceof AuthorityException) {
data = new Result(-4, "授权异常");
} else if (e instanceof SystemBlockException) {
data = new Result(-5, "系统负载异常");
}
response.getWriter().write(JSON.toJSONString(data));
}
}
// 统一返回体
class Result {
private int status;
private String msg;
private Object data;
// 省略getter/setter/构造器
}
5.3 Sentinel 整合 Feign
实现 Feign 远程调用的熔断降级,避免下游服务异常影响上游。
5.3.1 实现 FallbackFactory
java
@Component
public class UserFeignFallback implements FallbackFactory<UserFeign> {
@Override
public UserFeign create(Throwable t) {
return new UserFeign() {
@Override
public User getUserById(Integer id) {
return new User(id, "Feign调用失败:"+t, 0);
}
};
}
}
5.3.2 配置 Feign 接口
java
@FeignClient(value = "sentinel-provider", fallbackFactory = UserFeignFallback.class)
public interface UserFeign {
@RequestMapping(value = "/provider/getUserById/{id}")
User getUserById(@PathVariable Integer id);
}
六、总结
Sentinel 凭借轻量、易用、灵活的特性,成为 SpringCloud 微服务架构中服务保护的首选方案。核心要点总结:
- 资源定义:通过硬编码 / 注解 / 自动适配(SpringMVC/Feign)定义受保护资源;
- 规则配置:控制台 / 代码配置流量控制、熔断降级等规则,按需选择粒度;
- 兜底逻辑:通过 blockHandler / 全局异常 / FallbackFactory 处理限流 / 熔断场景;
- 核心价值:从流量入口到服务调用全链路保护,防止雪崩效应,保障微服务高可用。
建议结合 JMeter 压测工具验证各类规则效果,加深对 Sentinel 流量控制、熔断降级的理解,根据业务场景灵活配置规则,平衡系统稳定性和可用性。