Sentinel

Sentinel 完整使用流程(Spring Boot 2.x + Nacos 持久化)

一、环境准备

1.1 版本说明

xml 复制代码
<!-- 核心版本 -->
Spring Boot: 2.7.x
Spring Cloud: 2021.0.x
Spring Cloud Alibaba: 2021.0.5.0
Sentinel: 1.8.6

1.2 启动基础设施

bash 复制代码
# 1. 启动 Nacos(规则持久化)
docker run -d --name nacos \
  -p 8848:8848 \
  -e MODE=standalone \
  nacos/nacos-server:v2.1.2

# 2. 启动 Sentinel Dashboard(监控控制台)
java -Dserver.port=8080 \
  -Dcsp.sentinel.dashboard.server=localhost:8080 \
  -Dproject.name=sentinel-dashboard \
  -jar sentinel-dashboard-1.8.6.jar

二、项目搭建

2.1 添加依赖

xml 复制代码
<!-- pom.xml -->
<dependencies>
    <!-- Spring Boot -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Sentinel -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        <version>2021.0.5.0</version>
    </dependency>
    
    <!-- Sentinel Nacos 数据源 -->
    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-datasource-nacos</artifactId>
    </dependency>
    
    <!-- 可选:热部署 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

2.2 配置文件

yaml 复制代码
# application.yml
server:
  port: 8081

spring:
  application:
    name: sentinel-demo
  cloud:
    sentinel:
      # 1. 基础配置
      enabled: true
      eager: true  # 立即初始化
      
      # 2. 连接控制台
      transport:
        dashboard: localhost:8080
        port: 8719
      
      # 3. HTTP 请求埋点
      filter:
        enabled: true
        url-patterns: /**
      
      # 4. 规则持久化(Nacos)
      datasource:
        # 流控规则
        flow-rule:
          nacos:
            server-addr: localhost:8848
            namespace: public
            data-id: ${spring.application.name}-flow-rules
            group-id: SENTINEL_GROUP
            data-type: json
            rule-type: flow
        
        # 熔断规则
        degrade-rule:
          nacos:
            server-addr: localhost:8848
            data-id: ${spring.application.name}-degrade-rules
            group-id: SENTINEL_GROUP
            rule-type: degrade
        
        # 系统规则
        system-rule:
          nacos:
            server-addr: localhost:8848
            data-id: ${spring.application.name}-system-rules
            group-id: SENTINEL_GROUP
            rule-type: system

# 日志配置
logging:
  level:
    com.alibaba.csp.sentinel: DEBUG

三、核心代码实现

3.1 主启动类

java 复制代码
package com.example.sentinel;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SentinelApplication {
    public static void main(String[] args) {
        SpringApplication.run(SentinelApplication.class, args);
    }
}

3.2 业务接口定义

java 复制代码
package com.example.sentinel.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
public class DemoController {
    
    /**
     * 1. 简单接口 - 流控测试
     * http://localhost:8081/api/hello?name=world
     */
    @GetMapping("/hello")
    @SentinelResource(
        value = "hello",  // 资源名
        blockHandler = "helloBlockHandler",  // 流控处理
        fallback = "helloFallback"           // 异常降级
    )
    public String hello(@RequestParam String name) {
        // 模拟业务逻辑
        if ("error".equals(name)) {
            throw new RuntimeException("模拟业务异常");
        }
        return "Hello, " + name;
    }
    
    // 流控处理函数(必须是 public,参数+返回值与原方法一致,末尾加 BlockException)
    public String helloBlockHandler(String name, BlockException ex) {
        return "系统繁忙,请稍后重试(流控触发)";
    }
    
    // 异常降级函数(末尾加 Throwable)
    public String helloFallback(String name, Throwable throwable) {
        return "服务降级:" + throwable.getMessage();
    }
    
    /**
     * 2. 订单接口 - 复杂示例
     * http://localhost:8081/api/order/create?orderId=123&amount=100
     */
    @PostMapping("/order/create")
    @SentinelResource(
        value = "createOrder",
        blockHandler = "orderBlockHandler",
        blockHandlerClass = OrderBlockHandler.class,  // 外部类
        fallback = "orderFallback"
    )
    public ApiResult createOrder(
        @RequestParam String orderId,
        @RequestParam Double amount) {
        
        // 模拟复杂业务
        if (amount > 10000) {
            throw new IllegalArgumentException("金额超限");
        }
        
        // 模拟数据库操作
        try {
            Thread.sleep(100);  // 模拟耗时
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        return ApiResult.success("订单创建成功", orderId);
    }
    
    // 内部降级方法
    public ApiResult orderFallback(String orderId, Double amount, Throwable t) {
        return ApiResult.fail("订单创建失败:" + t.getMessage());
    }
    
    /**
     * 3. 热点参数限流
     * http://localhost:8081/api/product/detail?productId=1001&userId=123
     */
    @GetMapping("/product/detail")
    @SentinelResource(
        value = "getProductDetail",
        blockHandler = "hotParamBlockHandler"
    )
    public ApiResult getProductDetail(
        @RequestParam Long productId,
        @RequestParam(required = false) Long userId) {
        
        // 参数 0: productId, 参数 1: userId
        return ApiResult.success("产品详情", productId);
    }
    
    public ApiResult hotParamBlockHandler(Long productId, Long userId, 
                                          BlockException ex) {
        return ApiResult.fail("热门商品访问受限,请稍后");
    }
}

3.3 全局流控处理器

java 复制代码
package com.example.sentinel.handler;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.sentinel.vo.ApiResult;
import lombok.extern.slf4j.Slf4j;

/**
 * 全局流控处理器
 * 统一处理所有没有指定 blockHandler 的资源
 */
@Slf4j
public class GlobalBlockHandler {
    
    // 必须是 public static
    public static ApiResult handleException(BlockException ex) {
        log.warn("触发全局流控: {}", ex.getClass().getSimpleName());
        return ApiResult.fail("系统繁忙,请稍后重试");
    }
    
    // 订单模块专用
    public static ApiResult orderBlockHandler(String orderId, Double amount, 
                                             BlockException ex) {
        return ApiResult.fail("订单服务繁忙,请稍后提交");
    }
}

3.4 统一返回对象

java 复制代码
package com.example.sentinel.vo;

import lombok.Data;

@Data
public class ApiResult<T> {
    private Integer code;
    private String message;
    private T data;
    private Long timestamp;
    
    public static <T> ApiResult<T> success(String message, T data) {
        ApiResult<T> result = new ApiResult<>();
        result.setCode(200);
        result.setMessage(message);
        result.setData(data);
        result.setTimestamp(System.currentTimeMillis());
        return result;
    }
    
    public static <T> ApiResult<T> fail(String message) {
        ApiResult<T> result = new ApiResult<>();
        result.setCode(500);
        result.setMessage(message);
        result.setTimestamp(System.currentTimeMillis());
        return result;
    }
}

四、Nacos 规则配置

4.1 登录 Nacos

访问:http://localhost:8848/nacos

账号/密码:nacos/nacos

4.2 创建流控规则

Data ID: sentinel-demo-flow-rules
Group: SENTINEL_GROUP
格式: JSON

json 复制代码
[
  {
    "resource": "hello",
    "grade": 1,
    "count": 5,
    "limitApp": "default",
    "strategy": 0,
    "controlBehavior": 0,
    "clusterMode": false
  },
  {
    "resource": "createOrder",
    "grade": 1,
    "count": 10,
    "limitApp": "default",
    "strategy": 0,
    "controlBehavior": 2,
    "maxQueueingTimeMs": 2000,
    "clusterMode": false
  },
  {
    "resource": "getProductDetail",
    "grade": 1,
    "count": 20,
    "limitApp": "default",
    "strategy": 0,
    "controlBehavior": 1,
    "warmUpPeriodSec": 10,
    "clusterMode": false
  }
]

4.3 创建熔断规则

Data ID: sentinel-demo-degrade-rules
Group: SENTINEL_GROUP

json 复制代码
[
  {
    "resource": "createOrder",
    "grade": 0,
    "count": 500,
    "timeWindow": 10,
    "minRequestAmount": 5,
    "slowRatioThreshold": 0.5,
    "statIntervalMs": 10000
  },
  {
    "resource": "hello",
    "grade": 2,
    "count": 5,
    "timeWindow": 5,
    "minRequestAmount": 5,
    "statIntervalMs": 10000
  }
]

4.4 创建系统保护规则

Data ID: sentinel-demo-system-rules
Group: SENTINEL_GROUP

json 复制代码
[
  {
    "highestSystemLoad": 3.0,
    "avgRt": 200,
    "maxThread": 50,
    "qps": 100,
    "highestCpuUsage": 0.8
  }
]

五、Sentinel Dashboard 使用

5.1 访问控制台

http://localhost:8080

默认账号:sentinel/sentinel

5.2 查看实时监控

  1. 首页:查看应用列表,机器健康状态
  2. 簇点链路
    • 查看所有受保护的资源
    • 实时 QPS、响应时间
    • 配置规则
  3. 实时监控:图表展示

5.3 手动配置规则

除了 Nacos 持久化,可以在 Dashboard 临时配置:

  1. 点击 簇点链路
  2. 找到资源(如 /api/hello
  3. 点击 流控
  4. 设置 QPS=2
  5. 立即生效(重启应用会丢失,需要手动推送到 Nacos)

六、测试验证

6.1 启动应用

bash 复制代码
mvn spring-boot:run

查看启动日志,确认 Sentinel 初始化成功:

复制代码
[Sentinel Starter] DataSource NacosDataSource started
Loading flow rules from Nacos: [{"resource":"hello","count":5,...}]

6.2 测试流控

bash 复制代码
# 使用 ab 测试
ab -n 100 -c 10 "http://localhost:8081/api/hello?name=world"

# 观察结果
# 正常返回:Hello, world
# 触发流控:系统繁忙,请稍后重试

6.3 测试熔断

java 复制代码
// 快速触发异常
for (int i = 0; i < 10; i++) {
    // 访问会抛出异常的接口
    http://localhost:8081/api/hello?name=error
}
// 触发熔断后,即使正常请求也会被拒绝

七、高级功能配置

7.1 动态规则扩展

java 复制代码
package com.example.sentinel.config;

import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

/**
 * 动态规则管理(管理后台用)
 */
@RestController
@RequestMapping("/sentinel/rule")
public class DynamicRuleController {
    
    /**
     * 动态添加流控规则
     */
    @PostMapping("/flow/add")
    public String addFlowRule(
        @RequestParam String resource,
        @RequestParam int count) {
        
        List<FlowRule> rules = new ArrayList<>(FlowRuleManager.getRules());
        
        FlowRule rule = new FlowRule();
        rule.setResource(resource);
        rule.setGrade(1);  // QPS
        rule.setCount(count);
        rule.setLimitApp("default");
        
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
        
        return "规则添加成功:" + resource;
    }
    
    /**
     * 动态移除规则
     */
    @PostMapping("/flow/remove")
    public String removeFlowRule(@RequestParam String resource) {
        List<FlowRule> rules = FlowRuleManager.getRules();
        rules.removeIf(rule -> rule.getResource().equals(resource));
        FlowRuleManager.loadRules(rules);
        
        return "规则移除成功:" + resource;
    }
}

7.2 全局统一异常处理

java 复制代码
package com.example.sentinel.config;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.sentinel.vo.ApiResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理器
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    // 处理 Sentinel 流控异常
    @ExceptionHandler(BlockException.class)
    public ApiResult<Void> handleBlockException(BlockException e) {
        return ApiResult.fail("系统限流中,请稍后重试");
    }
    
    // 处理业务异常
    @ExceptionHandler(RuntimeException.class)
    public ApiResult<Void> handleRuntimeException(RuntimeException e) {
        return ApiResult.fail("业务异常:" + e.getMessage());
    }
}

八、生产环境建议

8.1 配置建议

yaml 复制代码
spring:
  cloud:
    sentinel:
      # 生产配置
      log:
        dir: /var/log/sentinel/${spring.application.name}
        switch-pid: true
      
      # 集群限流(可选)
      flow:
        enable: true
        cluster:
          enabled: true
          fallback-to-local-when-fail: true
      
      # 网关支持
      scg:
        enabled: true

8.2 监控告警

java 复制代码
// 自定义指标收集
@Component
public class SentinelMetricsCollector {
    
    @PostConstruct
    public void init() {
        // 注册自定义指标
        MetricsExtension.register();
    }
}

8.3 健康检查端点

yaml 复制代码
# application.yml
management:
  endpoints:
    web:
      exposure:
        include: health,metrics,sentinel
  endpoint:
    health:
      show-details: always

访问:http://localhost:8081/actuator/health

查看 Sentinel 健康状况。

九、常见问题排查

9.1 规则不生效

  1. 检查 Nacos 配置的 Data ID、Group 是否正确
  2. 查看应用日志,确认加载了规则
  3. 确认 @SentinelResource 的 value 与 resource 一致

9.2 控制台看不到应用

  1. 确认 spring.cloud.sentinel.transport.dashboard 配置正确
  2. 检查防火墙,端口 8719 是否开放
  3. 查看应用日志,确认成功连接 Dashboard

9.3 规则不持久化

  1. 确认在 Dashboard 修改规则后,点击了"推送到 Nacos"
  2. 检查 Nacos 配置是否被修改
  3. 重启应用,看是否加载了最新规则

十、快速验证脚本

bash 复制代码
#!/bin/bash
# sentinel-test.sh

# 1. 启动服务
echo "启动服务..."
java -jar sentinel-demo.jar &

# 2. 等待启动
sleep 30

# 3. 测试正常请求
echo "测试正常请求..."
for i in {1..3}
do
  curl "http://localhost:8081/api/hello?name=test$i"
  echo ""
done

# 4. 测试流控
echo "测试流控(触发限流)..."
for i in {1..10}
do
  curl "http://localhost:8081/api/hello?name=limit$i"
  echo ""
  sleep 0.1
done

# 5. 检查控制台
echo "请在浏览器访问:"
echo "Sentinel Dashboard: http://localhost:8080"
echo "Nacos: http://localhost:8848"

运行流程总结:

  1. ✅ 启动 Nacos、Sentinel Dashboard
  2. ✅ 创建 Spring Boot 项目,添加依赖
  3. ✅ 配置 application.yml,连接 Nacos
  4. ✅ 在业务方法上加 @SentinelResource
  5. ✅ 在 Nacos 中创建规则 JSON
  6. ✅ 启动应用,验证规则加载
  7. ✅ 通过 Dashboard 监控
  8. ✅ 测试流控、熔断效果

这套流程覆盖了 Sentinel 从入门到生产的所有关键环节,按步骤操作即可搭建完整的流量防护系统。

Sentinel 与 OpenFeign 的整合逻辑比较特殊:它不直接使用 @SentinelResource 注解(如 blockHandlerClass),而是通过 fallback 机制实现熔断降级。你需要区分"Feign 客户端"与"普通方法"在配置上的本质区别。

一、基础整合:开启 Sentinel 支持

  1. 依赖与配置

确保你的 spring-cloud-alibaba 版本与 Sentinel 兼容(如 2022.x 或 2023.x)。

application.yml

feign:

sentinel:

enabled: true # 关键:必须开启
com.alibaba.cloud spring-cloud-starter-alibaba-sentinel org.springframework.cloud spring-cloud-starter-openfeign

  1. 定义 Feign 客户端与 Fallback

注意:Feign 客户端接口上使用的是 @FeignClient 的 fallback 或 fallbackFactory 属性,不是 @SentinelResource。

// 1. Feign 客户端接口

@FeignClient(

name = "user-service",

path = "/api/user",

fallback = UserServiceFallback.class // 指定降级类

)

public interface UserServiceFeignClient {

复制代码
@GetMapping("/{id}")
ApiResult<User> getUserById(@PathVariable Long id);

@PostMapping
ApiResult<Void> createUser(@RequestBody UserDTO user);

}

  1. 实现 Fallback 降级类

降级类必须实现 Feign 接口,且必须是 Spring Bean。

// 2. Fallback 实现(处理限流、熔断、服务不可用)

@Component

public class UserServiceFallback implements UserServiceFeignClient {

复制代码
@Override
public ApiResult<User> getUserById(Long id) {
    // 当触发 Sentinel 流控或服务调用失败时,进入此方法
    return ApiResult.fail("用户服务繁忙,请稍后重试");
}

@Override
public ApiResult<Void> createUser(UserDTO user) {
    return ApiResult.fail("用户服务不可用");
}

}

二、进阶:使用 FallbackFactory(推荐)

如果你需要获取异常信息(如区分是限流 BlockException 还是网络超时),请使用 fallbackFactory。

// 1. 修改 @FeignClient 注解

@FeignClient(

name = "user-service",

fallbackFactory = UserServiceFallbackFactory.class // 改为工厂

)

public interface UserServiceFeignClient {

// ... 方法不变

}

// 2. FallbackFactory 实现

@Component

@Slf4j

public class UserServiceFallbackFactory implements FallbackFactory {

复制代码
@Override
public UserServiceFeignClient create(Throwable cause) {
    // cause 就是异常原因(BlockException、FeignException等)
    return new UserServiceFeignClient() {
        @Override
        public ApiResult<User> getUserById(Long id) {
            log.error("调用 getUserById 失败,原因:", cause);
            
            // 判断是否为 Sentinel 限流
            if (cause instanceof BlockException) {
                return ApiResult.fail("请求过于频繁,请稍后重试(限流)");
            } else {
                return ApiResult.fail("用户服务异常:" + cause.getMessage());
            }
        }
        
        @Override
        public ApiResult<Void> createUser(UserDTO user) {
            // ... 类似处理
            return ApiResult.fail("创建失败");
        }
    };
}

}

三、Sentinel 流控规则配置

Feign 整合后,Sentinel 会自动将每个 Feign 客户端方法注册为一个资源,资源名格式通常为:

在 Dashboard 中配置

  1. 访问 Sentinel 控制台(如 localhost:8080)。
  2. 找到你的服务 -> 簇点链路。
  3. 找到对应的 Feign 接口 URL 资源。
  4. 设置 流控规则(QPS/线程数)或 降级规则(异常比例/响应时间)。

规则生效逻辑

• 触发流控:当 QPS 超过阈值,Sentinel 会抛出 BlockException。

  • Feign 捕获:Feign 捕获到 BlockException 或其它异常后,不再重试,直接调用你定义的 fallback 方法。
  • 返回降级结果:用户收到友好的"服务繁忙"提示,而不是 500 错误。

四、常见误区与避坑

❌ 误区 1:在 Feign 接口上使用 @SentinelResource

// ❌ 错误写法:Feign 不支持在此处使用 @SentinelResource

@FeignClient(name = "user-service", fallback = ...)

public interface UserServiceFeignClient {

复制代码
@SentinelResource(blockHandlerClass = ...) // 无效!
@GetMapping("/{id}")
ApiResult<User> getUserById(@PathVariable Long id);

}

结论:@SentinelResource 的 blockHandlerClass 仅用于 Spring MVC Controller 或 普通 Service 方法,对 Feign 客户端无效。

❌ 误区 2:Fallback 类未被 Spring 扫描

// ❌ 错误:Fallback 类不在启动类扫描路径下

@Component

public class UserServiceFallback implements UserServiceFeignClient { ... }

// 启动类扫描包范围不对,导致 Fallback 无法注入,启动报错:

// No fallback instance found for feign client user-service

解决:确保 Fallback 类在 @SpringBootApplication 主类或其子包下,或显式指定扫描路径:

@EnableFeignClients(basePackages = "com.yourcompany.feign")

✅ 正确对比:Feign vs RestTemplate

组件 限流/降级配置方式 备注

OpenFeign @FeignClient(fallback = ...) 不支持 @SentinelResource

RestTemplate @SentinelRestTemplate 支持 blockHandlerClass

// RestTemplate 才用 blockHandlerClass

@Bean

@LoadBalanced

@SentinelRestTemplate(

blockHandler = "handleBlock",

blockHandlerClass = SentinelBlockHandler.class

)

public RestTemplate restTemplate() {

return new RestTemplate();

}

五、最佳实践总结

  1. 必开开关:feign.sentinel.enabled=true。

  2. 推荐使用 FallbackFactory:便于根据异常类型(限流 vs 宕机)做不同降级处理。

  3. 资源名管理:在 Sentinel 控制台中,Feign 资源名通常为 HTTP 方法 + URL,建议保持接口路径清晰。

  4. 区分场景:

    ◦ Feign 调用:用 @FeignClient(fallbackFactory = ...)

    ◦ 内部方法:用 @SentinelResource(blockHandlerClass = ...)

如果你需要为 Feign 调用单独配置复杂的流控逻辑(如基于参数限流),建议在 Feign 调用外层的 Controller 或 Service 方法上添加 @SentinelResource,而不是直接在 Feign 接口上操作。

相关推荐
随风,奔跑4 小时前
Spring Boot Alibaba(三)----Sentinel
spring boot·后端·sentinel
武超杰5 小时前
Sentinel 安装启动 + 全规则详解 + Feign 整合 + 持久化
sentinel
青槿吖5 小时前
Sentinel 进阶实战:Feign 整合 + 全局异常 + Nacos 持久化,生产环境直接用
java·开发语言·spring cloud·微服务·云原生·ribbon·sentinel
StackNoOverflow5 小时前
Sentinel服务保护框架完全指南:从原理到实践
java·数据库·sentinel
tsyjjOvO6 小时前
SpringCloud Alibaba Sentinel 从入门到精通
spring·spring cloud·sentinel
恼书:-(空寄1 天前
Sentinel 限流降级:滑动窗口原理 + 生产实战全解
sentinel·限流
身如柳絮随风扬1 天前
深入理解 Sentinel:服务雪崩、熔断原理、使用实践与规则持久化
java·微服务·sentinel
weixin_704266051 天前
Sentinel:微服务流量防护与熔断降级实战指南
sentinel
武超杰1 天前
微服务服务保护:Sentinel 从入门到流控规则实战
微服务·架构·sentinel