Loading

02_Sentinel组件使用

官方快速入门案例:

在官方文档中,定义的Sentinel进行资源保护的几个步骤:
1. 定义资源
2. 定义规则
3. 检验规则是否生效
        Entry entry = null;
        // 务必保证 finally 会被执行
        try {
            // 资源名可使用任意有业务语义的字符串 开启资源的保护
            entry = SphU.entry("自定义资源名");
            // 被保护的业务逻辑 method
            // do something...
        } catch (BlockException ex) {
            // 资源访问阻止,被限流或被降级 Sentinel定义异常 流控规则,降级规则,热点参数规则。。。。 服务降级(降级规则)
            // 进行相应的处理操作
        } catch (Throwable ex) {
            // 若需要配置降级规则,需要通过这种方式记录业务异常 RuntimeException 服务降级 mock feign:fallback
            Tracer.traceEntry(ex, entry);
        } finally {
            // 务必保证 exit,务必保证每个 entry 与 exit 配对
            if (entry != null) {
                entry.exit();
            }
        }

Sentinel资源保护的方式:

基于API实现

1. 引入依赖
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel‐core</artifactId>
            <version>1.8.4</version>
        </dependency>
2. 编写测试逻辑
private static final String RESOURCE_NAME = "HelloWorld";

    @RequestMapping(value = "/hello")
    public String hello() {
        try (Entry entry = SphU.entry(RESOURCE_NAME)) {
            // 被保护的逻辑
            log.info("hello world");
            return "hello world";
        } catch (BlockException ex) {
            // 处理被流控的逻辑
            log.info("blocked!");
            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);
    }

缺点:
业务侵入性很强,需要在controller中写入非业务代码。
配置不灵活,若需要添加新的受保护资源 需要手动添加 init方法来添加流控规则。

@SentinelResource注解实现

@SentinelResource 注解用来标识资源是否被限流、降级。
  blockHandler: 定义当资源内部发生了BlockException应该进入的方法(捕获的是Sentinel定义的异常)
  fallback: 定义的是资源内部发生了Throwable应该进入的方法
  exceptionsToIgnore:配置fallback可以忽略的异常
源码入口:com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect

引入依赖 

    <dependency>
      <groupId>com.alibaba.csp</groupId>
      <artifactId>sentinel-annotation-aspectj</artifactId>
      <version>1.8.4</version>
      <scope>compile</scope>
    </dependency>

配置切面支持(非SpringBoot环境)

    @Configuration
    public class SentinelAspectConfiguration {
        @Bean
        public SentinelResourceAspect sentinelResourceAspect() {
            return new SentinelResourceAspect();
        }
    }

UserController中编写测试逻辑,添加@SentinelResource,并配置blockHandler和fallback 

@SentinelResource(value = RESOURCE_NAME,
            blockHandler = "handleException",
            fallback = "fallbackException")
    @RequestMapping("/hello2")
    public String hello2() {

        int i = 1 / 0;

        return "helloworld";
    }

    public String handleException(BlockException ex) {
        return "被流控了";
    }

    public String fallbackException(Throwable t) {
        return "被异常降级了";
    }
编写ExceptionUtil,注意如果指定了class,方法必须是static方法
public class ExceptionUtil {

    /**
     * 注意: 必须为 static 函数
     */
    public static R fallback(Integer id, Throwable e){
        return R.error(-1,"===被异常降级啦===");
    }

    public static R handleException(Integer id, BlockException e){
        return R.error(-2,"===被限流啦===");
    }
}
    @RequestMapping(value = "/findOrderByUserId/{id}")
    @SentinelResource(value = "findOrderByUserId",
            fallback = "fallback", fallbackClass = ExceptionUtil.class,
            blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class)
    public R findOrderByUserId(@PathVariable("id") Integer id) {
        //ribbon实现
        String url = "http://mall‐order/order/findOrderByUserId/" + id;
        R result = restTemplate.getForObject(url, R.class);

        if (id == 4) {
            throw new IllegalArgumentException("非法参数异常");
        }

        return result;
    }
Spring Cloud Alibaba整合Sentinel后会在springMVC的拦截器中声明为资源。
public abstract class AbstractSentinelInterceptor implements HandlerInterceptor:

流控规则设置可以通过Sentinel dashboard配置,客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。
    <dependency>
      <groupId>com.alibaba.csp</groupId>
      <artifactId>sentinel-transport-simple-http</artifactId>
      <version>1.8.4</version>
      <scope>compile</scope>
    </dependency>
启动 Sentinel 控制台
下载控制台 jar 包并在本地启动:可以参见 此处文档
#启动控制台命令
java ‐jar sentinel‐dashboard‐1.8.4.jar
用户可以通过如下参数进行配置:
-Dsentinel.dashboard.auth.username=sentinel 用于指定控制台的登录用户名为 sentinel;
-Dsentinel.dashboard.auth.password=123456 用于指定控制台的登录密码为 123456;
如果省略这两个参数:默认用户和密码均为 sentinel;
-Dserver.servlet.session.timeout=7200 用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示7200 秒;60m 表示 60 分钟,默认为 30 分钟;
访问http://localhost:8080/#/login ,默认用户名密码: sentinel/sentinel 
Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包,所以要确保客户端有访问量; 

Spring Cloud Alibaba整合Sentinel 

引入依赖
        <!--sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
添加yml配置,为微服务设置sentinel控制台地址
spring:
  application:
    name: sentinel-demo

  cloud:
    sentinel:
      transport:
        # 添加sentinel的控制台地址
        dashboard: 127.0.0.1:8080
        # 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
        port: 8719
在sentinel控制台中设置流控规则:
资源名: 接口的API
针对来源: 默认是default,当多个微服务都调用这个资源时,可以配置微服务名来对指定的微服务设置阈值
阈值类型: 分为QPS和线程数 假设阈值为10
QPS类型: 只得是每秒访问接口的次数>10就进行限流
线程数: 为接受请求该资源分配的线程数>10就进行限流

测试: 因为QPS是1,所以1秒内多次访问会被限流。
访问http://localhost:8800/actuator/sentinel, 可以查看flowRules

微服务和Sentinel Dashboard通信原理

Sentinel控制台与微服务端之间,实现了一套服务发现机制,集成了Sentinel的微服务都会将元数据传递给Sentinel控制台,架构图如下所示: 

测试:http://localhost:8719/getRules?type=flow 获取微服务流控规则信息

注意:随着微服务增加,端口是递增的,具体参考Sentinel Dashboard显示的微服务对应端口

 

posted @ 2023-05-04 08:34  1640808365  阅读(15)  评论(0编辑  收藏  举报