微服务服务容错保护:Sentinel 从入门到实战

一、前言

在微服务架构中,服务间的相互调用是常态,但网络波动、服务自身故障等因素会导致服务可用性降低。当高并发请求涌入故障服务时,极易引发服务雪崩------ 单个服务故障蔓延至整个调用链路,导致全链路不可用。为解决这一问题,我们需要引入服务容错保护机制,而 Sentinel 作为阿里巴巴开源的流量控制框架,能从流量控制、熔断降级等维度保障服务稳定性。本文将从实战角度,全面讲解 Sentinel 的核心功能与使用方式。

二、高并发场景模拟(服务雪崩雏形)

2.1 环境搭建

2.1.1 服务提供者(sentinel-provider)
  • 工程创建 :拷贝 feign_provider 工程,修改应用名为sentinel-provider

  • application.yml 配置

    server:
    port: 9090
    spring:
    cloud:
    nacos:
    discovery:
    server-addr: 192.168.209.129:8848
    application:
    name: sentinel-provider

  • 核心服务逻辑(模拟网络延时):

    package com.hg.service;

    import com.hg.pojo.User;
    import org.springframework.stereotype.Service;

    @Service
    public class UserServiceImpl implements UserService {
    @Override
    public User getUserById(Integer id) {
    //模拟网络延时2秒
    try {
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    return new User(id,"王粪堆-provider",18);
    }
    }

2.1.2 Feign 接口工程(sentinel_feign)
  • 工程创建:拷贝 feign_interface 工程
  • Feign 接口定义

java

复制代码
package com.hg.feign;

import com.hg.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@FeignClient("sentinel-provider")
public interface UserFeign {
    @RequestMapping(value = "/provider/getUserById/{id}")
    public User getUserById(@PathVariable Integer id);
}
2.1.3 服务消费者(sentinel_consumer)
  • 工程创建:拷贝 feign_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>
    </dependencies>
</project>
  • application.yml 配置(限制 Tomcat 最大线程数):

yaml

复制代码
server:
  tomcat:
    max-threads: 10 # 默认200,降低线程数放大高并发问题
feign:
  client:
    config:
      default:
        connectionTimeout: 5000 # 请求连接超时时间
        readTimeout: 5000 # 请求响应超时时间    
  • 测试接口

java

复制代码
@RequestMapping(value = "/hello")
public String hello() {
    return "Hello Sentienl!!!";
}

2.2 高并发测试(JMeter)

  1. 下载 JMeter:https://jmeter.apache.org/

  2. 创建线程组,设置高并发数;

  3. 添加 HTTP 请求,访问http://127.0.0.1:8080/consumer/getUserById/1

  4. 同时访问http://127.0.0.1:8080/consumer/hello,发现 hello 接口出现线程阻塞。

2.3 结论

消费者服务因大量请求堆积,导致非故障接口也无法正常响应,这就是服务雪崩的雏形。而 Sentinel 的核心目标,就是通过流量控制、熔断降级等手段,避免此类问题扩散。

三、Sentinel 核心概念与功能

3.1 什么是 Sentinel

Sentinel(分布式系统的流量防卫兵)是阿里开源的服务保护框架,以流量为切入点,通过流量控制熔断降级等能力保障微服务稳定性。

3.2 核心概念

  • 资源:Sentinel 要保护的对象,如一个接口、一个方法;
  • 规则:保护资源的策略,如流量控制规则、熔断降级规则等。

3.3 核心功能

功能 作用
流量控制 限制请求流量,避免系统被超出处理能力的请求压垮
熔断降级 当下游服务故障时,暂时切断调用,避免级联失败

流量控制
熔断降级

四、Sentinel 快速入门

4.1 方式 1:抛异常式(原生 API)

4.1.1 引入依赖

xml

复制代码
<!--sentinel核心依赖-->
<dependency>
	<groupId>com.alibaba.csp</groupId>
	<artifactId>sentinel-core</artifactId>
</dependency>
4.1.2 代码实现

java

复制代码
@RequestMapping(value = "/hello")
public String hello() {
    Entry entry = null;
    try {
        // 定义受保护的资源
        entry = SphU.entry("/consumer/hello");
        return "Hello Sentienl!!!";
    } catch (BlockException e) {
        // 限流/熔断时的兜底逻辑
        e.printStackTrace();
        return "接口被限流了, exception: " + e;
    }finally {
        // 释放资源(必须成对出现)
        if (entry != null) {
            entry.exit();
        }
    }
}

/**
 * 初始化流控规则(@PostConstruct:构造函数执行后初始化)
 */
@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); // 加载规则
}
4.1.3 测试
  • 正常访问:返回Hello Sentienl!!!
  • 高并发访问:触发限流,返回兜底信息。

4.2 方式 2:注解式

4.2.1 引入依赖

xml

复制代码
<!--sentinel注解依赖-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-annotation-aspectj</artifactId>
</dependency>
4.2.2 代码实现
  • 开启注解支持

java

复制代码
@Bean
public SentinelResourceAspect sentinelResourceAspect(){
    return new SentinelResourceAspect();
}
  • 注解式接口

java

复制代码
@RequestMapping(value = "/hello2")
@SentinelResource(value="/consumer/hello2",blockHandler = "blockHandlerMethod")
public String hello2() {
    return "Hello Sentienl2!!!";
}

/**
 * 限流兜底方法(要求:返回值、参数与原方法一致,最后加BlockException参数)
 */
public String blockHandlerMethod(BlockException e){
    return "接口被限流了, exception: " + e;
}

// 初始化规则(同4.1.2,仅修改资源名为/consumer/hello2)
@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);
}
4.2.3 测试

效果与原生 API 一致,但代码侵入性更低。

4.3 Sentinel 控制台(可视化配置)

4.3.1 控制台安装启动
  1. 下载控制台 jar 包:https://github.com/alibaba/Sentinel/releases
  2. 启动命令:java -jar sentinel-dashboard-1.8.1.jar
  3. 访问控制台:http://localhost:8080,默认账号 / 密码:sentinel/sentinel
4.3.2 客户端接入控制台
  • 替换依赖

xml

复制代码
<!-- 移除原生依赖,引入SpringCloud整合包 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
  • application.yml 配置

yaml

复制代码
spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080 # 控制台地址
  • 测试接口

java

复制代码
@RequestMapping(value = "/hello3")
public String hello3() {
    return "Hello Sentienl3!!!";
}
4.3.3 控制台使用
  1. 访问http://127.0.0.1/consumer/hello3(Sentinel 懒加载,需触发接口后控制台才会显示);
  2. 在控制台配置流控规则,高并发访问即可触发限流。

五、Sentinel 核心规则详解

5.1 流控规则(流量控制)

流控规则用于限制资源的请求流量,核心配置项如下:

配置项 说明
资源名 唯一标识,默认请求路径
针对来源 限制调用方(微服务名),默认 default(不区分来源)
阈值类型 QPS(每秒请求数)/ 线程数
单机阈值 限流阈值(如 QPS=2 表示每秒最多 2 次请求)
流控模式 直接(限制自身)/ 关联(关联资源阈值触发限流)/ 链路(指定入口限流)
流控效果 快速失败(直接拒绝)/Warm Up(预热限流)/ 排队等待(匀速处理)
5.1.1 阈值类型
  • QPS:每秒请求数达到阈值触发限流(适用于短耗时接口);
  • 线程数:请求线程数达到阈值触发限流(适用于长耗时接口)。
5.1.2 流控模式
  • 直接:默认模式,资源自身达到阈值限流;
  • 关联:如 "支付接口" 达到阈值时,限流 "订单接口"(应用让步场景);
  • 链路:仅限制从指定接口进入的请求(粒度比 "针对来源" 更细)。
5.1.3 流控效果
  • 快速失败:触发限流直接返回异常;
  • Warm Up :阈值从阈值/3开始,预热时长内逐步升至阈值(适用于流量突增场景);
  • 排队等待:请求匀速通过,超出阈值的请求排队(超时丢弃),适用于削峰填谷。

5.2 热点规则(参数级限流)

热点规则是更细粒度的流控,针对接口参数限流(如限制高频访问的商品 ID / 用户 ID)。

5.2.1 代码实现

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);
}
5.2.2 控制台配置

配置 "热点规则",指定参数索引、阈值,可设置 "参数例外项"(如 ID=2 时阈值放宽)。

5.3 系统规则(应用级限流)

系统规则针对整个应用限流,粒度粗,慎用!支持 5 种维度:

  • LOAD:Linux 系统负载(仅 Linux 生效);
  • RT:所有请求平均响应时间;
  • 线程数:应用总线程数;
  • 入口 QPS:应用所有接口总 QPS;
  • CPU 使用率:应用 CPU 占用率。

5.4 授权规则(来源控制)

根据请求来源(origin)做黑白名单控制:

  1. 实现 RequestOriginParser:解析请求来源(如从参数 / 请求头获取);

java

运行

复制代码
@Component
public class RequestOriginParserDefinition implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest request) {
        // 从参数获取来源标识
        return request.getParameter("origin");
    }
}
  1. 控制台配置黑白名单:如黑名单配置 "app1",则 origin=app1 的请求被拒绝。

5.5 降级规则(熔断降级)

当资源出现故障(慢调用 / 异常)时,暂时切断调用,避免级联失败。支持 3 种熔断策略:

表格

策略 触发条件
慢调用比例 慢调用(超过最大 RT)占比≥阈值,且请求数≥最小请求数
异常比例 异常请求占比≥阈值,且请求数≥最小请求数
异常数 异常请求数≥阈值,且请求数≥最小请求数
5.5.1 慢调用比例示例
  1. 控制台配置:最大 RT=200ms,比例阈值 = 0.5,熔断时长 = 5s,最小请求数 = 5;
  2. 接口中模拟延时:Thread.sleep(300);
  3. 高并发访问触发熔断,5 秒内请求被拒绝,熔断结束后恢复。

六、Sentinel 高级用法

6.1 自定义 blockHandler(兜底逻辑)

6.1.1 同类定义兜底方法

java

运行

复制代码
@SentinelResource(value ="getUserById", blockHandler="blockHandlerMethod")
public User getUserById(@PathVariable Integer id) {
    return userFeign.getUserById(id);
}

// 兜底方法(static修饰,参数需包含原参数+BlockException)
public static User blockHandlerMethod(Integer id, BlockException e) {
    return new User(0, "接口被流控/熔断:"+e, 0);
}
6.1.2 外置类定义兜底方法

java

运行

复制代码
// 外置兜底类
public class BlockHandlerClass {
    public static User blockHandlerMethod(Integer id, BlockException e) {
        return new User(0, "外置兜底:接口被限流", 0);
    }
}

// 接口引用
@SentinelResource(value ="getUserById",
    blockHandler="blockHandlerMethod",
    blockHandlerClass = BlockHandlerClass.class)
public User getUserById(@PathVariable Integer id) {
    return userFeign.getUserById(id);
}

6.2 全局异常处理

默认限流返回 "Blocked by Sentinel (flow limiting)",可实现BlockExceptionHandler自定义返回:

java

运行

复制代码
@Component
public class GloabBlockExceptionHandler 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省略
}

6.3 Sentinel 整合 Feign

Feign 与 Sentinel 整合,实现远程调用的熔断降级:

  1. 消费者开启 Feign 支持

yaml

复制代码
feign:
  sentinel:
    enabled: true # 开启Feign熔断
  1. Feign 接口配置兜底工厂

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);
            }
        };
    }
}

// Feign接口引用兜底工厂
@FeignClient(value="sentinel-provider",fallbackFactory = UserFeignFallback.class)
@RequestMapping(value = "/provider")
public interface UserFeign {
    @RequestMapping(value = "/getUserById/{id}")
    User getUserById(@PathVariable Integer id);
}

七、总结

Sentinel 作为轻量级的服务容错框架,通过 "资源 + 规则" 的核心设计,提供了流量控制、熔断降级、系统保护等全方位的服务保护能力。相比 Hystrix,Sentinel 更易上手、配置灵活,且支持可视化控制台,是微服务架构中服务容错的优选方案。

在实际应用中,需结合业务场景合理配置规则:

  • 流量控制:根据接口 QPS / 线程数设置阈值,选择合适的流控效果;
  • 熔断降级:针对慢调用 / 异常请求配置熔断策略,避免级联失败;
  • 授权规则:控制请求来源,提升接口安全性;
  • 整合 Feign:实现远程调用的熔断兜底,降低服务依赖风险。

通过 Sentinel 的层层防护,可有效避免服务雪崩,保障微服务架构的稳定性。

相关推荐
LONGZETECH2 小时前
破解汽车实训难题!龙泽科技仿真软件,助力院校教学与大赛备赛
人工智能·科技·架构·汽车·汽车仿真教学软件
刀法如飞2 小时前
一款基于 NestJS 的 DDD 脚手架,开箱即用
javascript·后端·架构
@不误正业2 小时前
第09章-分布式硬件平台
分布式·架构·开源·开源鸿蒙
aXin_ya4 小时前
微服务 第四天
微服务·云原生·架构
踩着两条虫10 小时前
如何评价VTJ.PRO?
前端·架构·ai编程
张忠琳10 小时前
【vllm】vLLM v1 KV Offload — 模块超深度逐行分析之一(七)
ai·架构·vllm
easy_coder12 小时前
Agent:从原理、架构到工程落地(上篇)
架构·云计算
张忠琳13 小时前
【vllm】vLLM v1 Attention — 系统级架构深度分析(五)
ai·架构·vllm
roman_日积跬步-终至千里13 小时前
【案例题-知识点】分篇一:质量属性与架构评估:非功能需求的场景化表达与架构权衡、评估与度量
架构