Spring Cloud: Sentinel入门讲解

在企业级微服务开发中,Sentinel 解决的是系统稳定性问题。


一、Sentinel 核心概念与目标

Sentinel(分布式系统的流量防卫兵)是阿里巴巴开源的一套面向分布式服务架构的流量控制熔断降级系统负载保护的组件。

它的核心目的是保护应用,确保服务在面对高并发、突发流量或依赖服务不可用时,仍能保持高可用性稳定性,避免因局部故障导致整个系统雪崩。


1-1. 核心概念

概念 描述 作用
资源 (Resource) Sentinel 中最核心的概念。可以是任何您希望保护的代码块、服务、方法、接口等。用唯一名称标识。 定义流量防护的目标。
规则 (Rule) 为资源定义的具体保护措施,如流量阈值、降级策略等。 定义如何保护资源(限流、降级、系统保护)。
Slot Chain Sentinel 的核心处理链。当请求流经资源时,会依次经过统计、限流、熔断等各个 Slot(插槽)进行处理。 Sentinel 工作的底层机制。

1-2、流量防护三大核心功能:

Sentinel 提供了三大保护功能,都基于对资源的实时统计

1. 🚦 流量控制 (Flow Control)

这是 Sentinel 最基本也是最重要的功能,目的是控制对资源的请求速度,确保其不超过系统的处理能力。

  • 指标: 通常基于 QPS(每秒查询数)或并发线程数

  • 示例规则: 资源 getProductInfo 的 QPS 阈值为 200,当超过 200 QPS 时,后续请求将被拒绝(默认是 FailFast 策略)。


2. ⚡ 熔断降级 (Degrade)

当依赖的资源或服务不稳定(响应慢或失败率高)时,Sentinel 会自动切断调用(熔断),让请求快速失败,而不是继续堆积,避免拖垮自身服务。

  • 策略:

    • 慢调用比例 (RT): 当资源的平均响应时间(RT)超过某个阈值,并且请求量也达到一定值时,触发熔断。

    • 异常比例: 当资源的异常请求比例达到阈值时,触发熔断。

    • 异常数: 在一个时间窗口内,异常请求总数达到阈值时,触发熔断。

  • 熔断器状态: 正常 -> 打开 (Open) -> 半开 (Half-Open) -> 正常。熔断打开后,在设定的恢复时间窗后进入半开状态尝试放行少量请求。


3. 🛡️ 系统保护 (System Protection)

从整个系统的维度进行负载保护,而不是针对单个资源。它基于系统的整体负载指标(如 CPU 利用率、系统 Load、平均 RT 等)进行判断和限流。

  • 作用: 防止系统压力过大时,雪崩式地拒绝所有请求,保护核心业务,同时保证非核心业务的快速失败。

二、Sentinel 快速入门步骤(基于 Spring Cloud/SpringBoot)

步骤一:部署 Sentinel Dashboard (TC)

Sentinel 的规则和监控信息通常通过控制台(Dashboard)来配置和查看。

  1. 下载: 从 Sentinel GitHub 或 Maven Central 下载最新的 sentinel-dashboard.jar

  2. 启动: 运行 Dashboard。默认端口是 8080

    复制代码
    java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -jar sentinel-dashboard.jar
  3. 访问: 浏览器访问 http://localhost:8080,默认账号/密码是 sentinel/sentinel


步骤二:集成到业务微服务

  1. 引入依赖: 在需要进行流量防护的微服务中引入 Sentinel 依赖(推荐使用 Spring Cloud Alibaba 提供的 starter)。

    XML 复制代码
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
  2. 配置客户端:application.propertiesapplication.yml 中配置服务名和 Dashboard 地址。

    bash 复制代码
    # application.yml
    spring:
      application:
        name: your-service-name
    # 配置 Sentinel Dashboard 地址
    cloud:
      sentinel:
        transport:
          dashboard: localhost:8080
  3. 定义资源 (Resource):

    • 自动定义 (Automatic): Sentinel 会自动将 HTTP 接口、Feign 客户端调用、Dubbo 接口等识别为资源。

    • 手动定义 (Manual): 使用 @SentinelResource 注解来保护您代码中的关键业务逻辑。

    java 复制代码
    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    
    @Service
    public class OrderService {
    
        // 使用 @SentinelResource 保护方法
        @SentinelResource(value = "createOrder", 
                          blockHandler = "handleBlock", // 违背限流/降级规则时调用的方法
                          fallback = "handleFallback") // 业务异常时调用的方法
        public String createOrder(String userId) {
            // 核心业务逻辑
            return "Order created successfully";
        }
    
        // 限流或降级时的处理逻辑(参数要匹配原方法)
        public String handleBlock(String userId, BlockException ex) {
            System.out.println("Blocked by Sentinel: " + ex.getMessage());
            return "System busy, please try later.";
        }
    
        // 业务异常时的处理逻辑(Throwable 参数)
        public String handleFallback(String userId, Throwable ex) {
            System.out.println("Service logic error: " + ex.getMessage());
            return "Internal error occurred.";
        }
    }
  4. 配置规则:

    • 启动您的微服务并调用几次被 @SentinelResource 保护的方法。(懒加载)

    • 登录 Sentinel Dashboard,在左侧菜单找到您的服务。

    • 进入 簇点链路 找到您定义的资源(如 createOrder),然后点击右侧的 新增限流新增降级 规则。

    • 例如: 设置 createOrderQPS 阈值 为 10,流控模式快速失败 (Fail Fast)


企业级最佳实践

  • 持久化规则: Dashboard 配置的规则默认只存在内存中,重启后丢失。企业级应用必须将规则持久化到配置中心 (如 Nacos、Apollo),以确保规则的动态性持久性

  • 区分降级和限流处理:

    • blockHandler:处理 Sentinel 规则 导致的异常(限流、降级、系统保护)。

    • fallback:处理 业务代码 执行时抛出的异常(如数据库连接失败、空指针等)。

  • 统一入口: 对外部提供的 API Gateway 接口是最重要的限流资源,应优先配置保护。


三、@SentinelResource一般是加在哪里?

@SentinelResource 是Sentinel的限流降级注解。

3-1、加在哪里

1. Service层方法(最常见)

java 复制代码
@Service
public class OrderService {
    
    @SentinelResource(
        value = "createOrder",
        blockHandler = "handleCreateOrderBlock",
        fallback = "createOrderFallback"
    )
    public Order createOrder(Order order) {
        // 业务逻辑
        return orderMapper.insert(order);
    }
    
    // 处理限流(BlockException)
    public Order handleCreateOrderBlock(Order order, BlockException e) {
        log.warn("订单创建被限流了");
        return null;
    }
    
    // 处理熔断降级(业务异常)
    public Order createOrderFallback(Order order, Throwable e) {
        log.warn("订单创建失败,执行降级方案");
        return new Order();  // 返回默认值
    }
}

2. Controller层方法

java 复制代码
@RestController
@RequestMapping("/api/orders")
public class OrderController {
    
    @Autowired
    private OrderService orderService;
    
    @PostMapping
    @SentinelResource(
        value = "createOrderApi",
        blockHandler = "handleBlock"
    )
    public ApiResponse<Order> createOrder(@RequestBody Order order) {
        Order result = orderService.createOrder(order);
        return ApiResponse.success(result);
    }
    
    public ApiResponse<Order> handleBlock(Order order, BlockException e) {
        return ApiResponse.fail("系统繁忙,请稍后再试");
    }
}

3. Feign客户端方法

java 复制代码
@FeignClient(name = "stock-service", fallback = StockServiceFallback.class)
public interface StockServiceClient {
    
    @PostMapping("/api/stock/deduct")
    @SentinelResource(
        value = "deductStock",
        fallback = "deductStockFallback"
    )
    Stock deductStock(@RequestParam Long productId, @RequestParam Integer quantity);
    
    default Stock deductStockFallback(Long productId, Integer quantity) {
        log.warn("库存服务调用失败,执行降级");
        return new Stock();
    }
}

4. 异步方法

java 复制代码
@Service
public class AsyncOrderService {
    
    @Async
    @SentinelResource(
        value = "asyncProcessOrder",
        blockHandler = "handleAsyncBlock"
    )
    public void processOrderAsync(Order order) {
        // 异步处理逻辑
        doSomeHeavyWork(order);
    }
    
    public void handleAsyncBlock(Order order, BlockException e) {
        log.warn("异步处理被限流");
    }
}

3-2、一般不加的地方

❌ 不加在Mapper层

java 复制代码
// 错误示范
@Mapper
public interface OrderMapper {
    
    @SentinelResource("selectOrder")  // ❌ 不要加这儿
    Order selectById(Long id);
}

// 原因:
// 1. Mapper直接操作数据库,没有业务逻辑
// 2. 限流应该在业务层面
// 3. 多个Service可能调用同一个Mapper

❌ 不加在private私有方法

java 复制代码
@Service
public class OrderService {
    
    @SentinelResource("privateMethod")  // ❌ 不要加
    private void privateMethod() {
        // ...
    }
    
    // 原因:Sentinel是通过代理实现的,私有方法代理不了
}

❌ 不加在构造方法

java 复制代码
@Service
public class OrderService {
    
    @SentinelResource("constructor")  // ❌ 不要加
    public OrderService() {
        // ...
    }
}

❌ 不加在static方法

java 复制代码
@Service
public class OrderService {
    
    @SentinelResource("staticMethod")  // ❌ 不要加
    public static void staticMethod() {
        // ...
    }
    
    // 原因:static方法不能被代理
}

3-3、最佳实践

推荐做法:Service + Controller双层

java 复制代码
// ===== Controller层 =====
@RestController
@RequestMapping("/api/orders")
public class OrderController {
    
    @SentinelResource(
        value = "createOrderApi",  // API级别的限流
        blockHandler = "apiBlockHandler"
    )
    @PostMapping
    public ApiResponse<Order> createOrder(@RequestBody Order order) {
        return ApiResponse.success(orderService.createOrder(order));
    }
    
    public ApiResponse<Order> apiBlockHandler(Order order, BlockException e) {
        return ApiResponse.fail("API请求过于频繁");
    }
}

// ===== Service层 =====
@Service
public class OrderService {
    
    @SentinelResource(
        value = "createOrderService",  // 业务级别的限流
        blockHandler = "serviceBlockHandler",
        fallback = "createOrderFallback"
    )
    public Order createOrder(Order order) {
        // 实际业务逻辑
        return orderMapper.insert(order);
    }
    
    public Order serviceBlockHandler(Order order, BlockException e) {
        return null;  // 限流处理
    }
    
    public Order createOrderFallback(Order order, Throwable e) {
        return new Order();  // 降级处理
    }
}

为什么双层?

复制代码
用户请求
    ↓
Controller层(@SentinelResource)
    ├─ 控制HTTP请求的流量
    ├─ 返回友好的错误信息
    └─ 保护系统入口
    ↓
Service层(@SentinelResource)
    ├─ 控制业务操作的流量
    ├─ 保护核心业务逻辑
    └─ 其他Service也可能调用

3-4、@SentinelResource 注解参数说明

java 复制代码
@SentinelResource(
    value = "createOrder",              // 资源名,必需
    
    blockHandler = "handleBlock",       // 限流/降级时的处理方法
    blockHandlerClass = BlockHandlers.class,  // 指定外部类
    
    fallback = "fallbackMethod",        // 业务异常时的降级方法
    fallbackClass = FallbackMethods.class,    // 指定外部类
    
    exceptionsToIgnore = {IOException.class}  // 忽略的异常
)
public Order createOrder(Order order) {
    // ...
}

3-5、常见场景总结

场景 位置 用途
保护HTTP接口 Controller 限制请求频率
保护业务方法 Service 限制业务操作
远程调用降级 Feign客户端 调用失败降级
异步任务保护 @Async方法 限制异步线程
定时任务保护 @Scheduled方法 限制定时任务

简单总结:加在Service和Controller的public业务方法上,不要加在Mapper、私有方法、static方法。

相关推荐
JHC00000018 小时前
dy直播间评论保存插件
java·后端·python·spring cloud·信息可视化
华大哥19 小时前
spring cloud微服务实战:consul+Feign/Ribbon服务注册和远程调用
spring cloud·微服务·ribbon·consul·java-consul
黄俊懿1 天前
【深入理解SpringCloud微服务】Seata(AT模式)源码解析——全局事务的提交
java·后端·spring·spring cloud·微服务·架构·架构师
kkoral1 天前
单机docker部署的redis sentinel,使用python调用redis,报错
redis·python·docker·sentinel
墨白曦煜2 天前
深入剖析 Redis 客户端:Sentinel 模式下的“寻址”与“感知”艺术
数据库·redis·sentinel
遇见火星2 天前
Redis高可用-哨兵模式(Sentinel)
redis·sentinel
墨痕诉清风2 天前
java漏洞集合工具(Struts2、Fastjson、Weblogic(xml)、Shiro、Log4j、Jboss、SpringCloud)
xml·java·struts·安全·web安全·spring cloud·log4j
⑩-2 天前
SpringCloud-Feign客户端实战
后端·spring·spring cloud
楠枬2 天前
Nacos
java·spring·spring cloud·微服务
一人の梅雨2 天前
京东商品详情接口深度解析:从宙斯签名到商详数据价值重构
java·spring cloud·微服务