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() + "\t 服务不可用";
    }
    
}

需要注意的是,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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容