zoukankan      html  css  js  c++  java
  • Spring Cloud Alibaba Sentinel 流量卫兵

    Hi,我是空夜!

    本节示例代码在 https://github.com/laolunsi/spring-boot-examples


    首先下载 sentinel jar包:https://github.com/alibaba/Sentinel/releases

    java -jar sentinel-xx.jar 运行,打开浏览器,输入默认地址:http://localhost:8080

    参考:如何使用 Sentinel?—— 官方文档

    sentinel 进行流量控制有以下流程:

    • 定义资源
    • 定义规则
    • 检验规则是否生效

    概念

    资源,是 sentinel 的核心概念之一,可以简单的理解为一段代码。

    sentinel 对主流的框架都提供了适配,下面以 Spring Cloud 为例,记录在 Spring Cloud 微服务架构中如何使用 sentinel 进行流量控制。

    资源

    分为以下几种方式:

    • 主流框架的默认配置
    • 抛出异常方式定义资源
    • 返回布尔值方式定义资源
    • 注解方式定义资源
    • 异步调用支持

    注解方式定义资源主要用于接口上,对接口进行流量控制,使用的是 @ResourceSentinel 注解。该注解提供了可选的异常处理和 fallback 配置项。参考:Sentinel 注解支持

    源码:

    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    public @interface SentinelResource {
        // 资源名称,不能为空
        String value() default "";
    
        EntryType entryType() default EntryType.OUT;
    
        int resourceType() default 0;
    
        // 可选项,处理 BlockException 的函数名称,默认在本类中;如果想要指定其他类中的函数,需要使用 blockHandlerClass 属性
        String blockHandler() default "";
    
        Class<?>[] blockHandlerClass() default {};
    
        // 可选项,fallback 函数名称,用于在抛出异常时提供 fallback 处理逻辑。可以针对所有类型的异常。配合 fallbackClass 属性可以指定其他类中的函数
        String fallback() default "";
    
        String defaultFallback() default "";
    
        Class<?>[] fallbackClass() default {};
    
        Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class};
    
        // 忽略异常,即 fallback 和 blockHandler 函数不起作用的异常
        Class<? extends Throwable>[] exceptionsToIgnore() default {};
    }
    

    注意:

    • blockHandler 和 fallback 指定的函数默认在本类中,该函数的返回值类型和参数顺序需与原方法保持一致。blockHandler 对应的函数可以在最后额外加一个 BlockException 类型的参数,fallback 对应的函数可以再最后额外加一个 Throwable 类型的参数
    • 使用对应的 blockHandlerClass 和 fallbackClass 可以指定对应函数所在的类,而不是默认的当前类。注意,此时,指定的函数需要是 static 的,否则无法解析。

    规则

    原理是监控应用流量的 QPS 或并发线程数等指标,设置阈值,避免服务被瞬时的高峰流量冲垮。目的是保障高峰流量时应用的高可用性。

    目的是防止单个服务不可用导致的雪崩现象的发生,同样是保障应用高可用性的方法之一。

    针对的是调用链路中不稳定的资源。

    系统保护规则从应用级别(而不是资源维度)的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

    根据调用来源判断请求是否允许通过。

    看作一种特殊的流量控制规则,仅对包含热点参数的资源调用生效。它根据传入参数中的热点参数,与配置的限流阈值、模式,对包含热点参数的资源调用进行限流。

    sentinel 还提供了相关 API 用于定制自己的规则策略。

    上面默认的规则分类,可以通过代码定义,也可以使用 dashboard 定义。

    定义规则可以通过 dashboard,也可以使用代码创建。如果想要持久化存储规则,可以利用 Nacos 等数据源。这一点在后面会讲。


    Spring Cloud 整合 Sentinel

    参考:spring-cloud-alibaba-sentinel

    创建一个 demo 服务,引入 spring-cloud 中的 sentinel 依赖:

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
                <version>0.9.0.RELEASE</version>
            </dependency>
    

    配置:

    server:
      port: 8203
    spring:
      application:
        name: demo
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
        sentinel:
          transport:
            dashboard: localhost:8080
            port: 8081
    

    可以配置流控、降级、热点、授权多种规则:

    注解支持使用参考:注解支持 —— 官方文档

    默认情况下是以 url 作为链路地址以及资源名的,我们可以在代码中用 @SentinelResource 注解来主动注明资源的名称、阻塞处理方法等。比如:

    @RestController
    @RequestMapping(value = "test")
    @Validated
    public class TestAction {
    
        private static Logger logger = LoggerFactory.getLogger(TestAction.class);
    
        @SentinelResource(value = "helloTest", blockHandler = "handleEx")
        @GetMapping(value = "hello")
        public String hello(@RequestParam("msg") @NotBlank String msg) {
            logger.info("hellow, " + msg);
            return "hello, " + msg;
        }
    
        @GetMapping(value = "send")
        @SentinelResource(value = "sendTest", blockHandler = "handleException", blockHandlerClass = BlockHandlerConfig.class)
        public String send(@NotBlank(message = "{required}") String email, @Email(message = "{invalid}") String msg) {
            return "发消息给:" + email + ",消息内容:" + msg;
        }
    
        public String handleEx(String msg, BlockException ex) {
            System.out.println("系统错误:msg=" + msg + ", ex: " + ex);
            return "流量限制,请稍后重试";
        }
    }
    

    这里的 helloTest 使用了本类中的 handleEx 方法作为阻塞处理方法。而 sendTest 用 BlockHandlerConfig 类中的 handleException 方法:

    public class BlockHandlerConfig {
    
        public static String handleException(String email, String msg, BlockException exception) {
            return "444, " + exception.getClass().getCanonicalName() + "	 服务不可用";
        }
        
    }
    

    需要注意的是,blockHandle 对应方法的参数必须与 资源 的参数保持一致,否则规则不会生效,且会抛出异常。

    这里给 helloTest 这个 resource 配置一个简单的流控:

    测试:

    快速请求 helloTest 对应的接口,发现成功请求与限流响应交错出现了。这表明我们的限流规则和 blockHandler 生效了。


    规则持久化

    需要注意的是,如果服务重启了,那么这些规则配置就会被丢失。其中一个解决办法是利用 Nacos 做配置中心,先将规则定义保存在 Nacos 中。

    sentinel 提供了 file/nacos/zp/apollo 等规则扩展存储方式。具体参考官方文档:动态规则扩展

    一个服务若要使用 Nacos 中的配置作为 sentinel 规则,除了 Nacos 的依赖外,还需要引入如下依赖:

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
                <version>0.9.0.RELEASE</version>
            </dependency>
    
                    <dependency>
                <groupId>com.alibaba.csp</groupId>
                <artifactId>sentinel-datasource-nacos</artifactId>
                <version>1.8.0</version>
            </dependency>
    
            <!-- 为解决 Caused by: java.lang.ClassNotFoundException: com.alibaba.csp.sentinel.log.CommandCenterLog 引入 -->
            <dependency>
                <groupId>com.alibaba.csp</groupId>
                <artifactId>sentinel-transport-simple-http</artifactId>
                <version>1.8.0</version>
            </dependency>
    

    配置:

    spring:
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
        sentinel:
          datasource:
            ds1:
              nacos:
                server-addr: localhost:8848
                dataId: sentinel-config
                groupId: DEFAULT_GROUP
                data-type: json
                rule-type: flow
    

    nacos 中新建一个 sentinel-config 配置文件,类型是 json,内容比如:

    [
        {
             "resource": "helloTest",
             "limitApp": "default",
             "grade":   1,
             "count":   3,
             "strategy": 0,
             "controlBehavior": 0,
             "clusterMode": false    
        }
    ]
    

    启动后可以看到 sentinel 中出现了这个规则。在 nacos 中修改该规则,发现 sentinel 那边同步修改了(反之则不行)


    FAQ —— sentinel 部署路径的问题

    之前部署 sentinel 的时候,出现过这样一个问题:我配置了一个域名给微服务平台使用,其中的每一个模板,如 gateway, zipkin,sentinel,都是用 nginx 配置的 xxx.com/gateway/xxx 这样的请求格式来访问的。

    打开 xxx.com/sentinel, 是可以看到 dashboard 和每个服务的,但是点开服务,发现监控数据没有了,簇点链路中每个地址的 QPS 都是0,点击新增流控规则,控制台报了 404 异常。

    在官方仓库提了这个 issue,有位j叫 jasonjoo2010 的老哥给我解答了一下:

    目前dashboard的静态部分,并不支持任意子目录部署的方式,建议在不改动的情况下,使用独立域名部署。

    后来我新增了一个二级域名来专门访问 sentinel,就可以了。

    关于这个问题的详细描述在 sentinel 官方仓库中:https://github.com/alibaba/Sentinel/issues/1804


    参考:


    最近在系统地学习 Redis、RabbitMQ、ES 等技术的知识,着重关注原理、底层、并发等问题,关于相关技术分享后续会逐渐发布出来。欢迎关注公众号:猿生物语(ID:JavaApes

  • 相关阅读:
    Asp.net core 3.1+EF Core2.2.6+Oracle.EntityFrameworkCore2.1.19连接Oracle数据库
    外业数据采集平台(GPS+Android Studio+Arcgis for android 100.2.1)
    Android Studio 单元测试
    1.泛型(Generic)
    营销推广软件,抢沙发功能,滑动解锁,自动提交文章评论,使用Puppeteer(一)
    C# 使用Tesseract-OCR-v5.0,实现验证码,中文,身份证识别
    Tesseract-OCR-v5.0中文识别,训练自定义字库,提高图片的识别效果
    C# 实现验证码识别,使用AspriseOCR.dll
    C# 自动批量搜索指定关键字,没有注册的域名
    C#图片采集软件 自动翻页 自动分类(收集美图必备工具)(一)
  • 原文地址:https://www.cnblogs.com/eknown/p/13851691.html
Copyright © 2011-2022 走看看