Loading... ![](http://zfh-public-blog.oss-cn-beijing.aliyuncs.com/image-1603204992559.jpeg) **Hi,我是空夜!** 本节示例代码在 [https://github.com/laolunsi/spring-boot-examples](https://github.com/laolunsi/spring-boot-examples) --- 首先下载 sentinel jar包:https://github.com/alibaba/Sentinel/releases java -jar sentinel-xx.jar 运行,打开浏览器,输入默认地址:http://localhost:8080 ![](http://zfh-public-blog.oss-cn-beijing.aliyuncs.com/image-1603205028749.png) 参考:[如何使用 Sentinel?—— 官方文档](https://github.com/alibaba/Sentinel/wiki/如何使用) sentinel 进行流量控制有以下流程: - 定义资源 - 定义规则 - 检验规则是否生效 --- ## 概念 资源,是 sentinel 的核心概念之一,可以简单的理解为一段代码。 sentinel 对主流的框架都提供了适配,下面以 Spring Cloud 为例,记录在 Spring Cloud 微服务架构中如何使用 sentinel 进行流量控制。 ### 资源 分为以下几种方式: - 主流框架的默认配置 - 抛出异常方式定义资源 - 返回布尔值方式定义资源 - 注解方式定义资源 - 异步调用支持 注解方式定义资源主要用于接口上,对接口进行流量控制,使用的是 @ResourceSentinel 注解。该注解提供了可选的异常处理和 fallback 配置项。参考:[Sentinel 注解支持](https://github.com/alibaba/Sentinel/wiki/注解支持) 源码: ```java @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 的,否则无法解析。 ### 规则 - 流量控制规则 FlowRule:[流量控制](https://github.com/alibaba/Sentinel/wiki/流量控制) > 原理是监控应用流量的 QPS 或并发线程数等指标,设置阈值,避免服务被瞬时的高峰流量冲垮。目的是保障高峰流量时应用的高可用性。 - 熔断降级规则 DegradeRule:[熔断降级](https://github.com/alibaba/Sentinel/wiki/熔断降级) > 目的是防止单个服务不可用导致的雪崩现象的发生,同样是保障应用高可用性的方法之一。 > > 针对的是调用链路中不稳定的资源。 - 系统保护规则 SystemRule:[系统自适应限流](https://github.com/alibaba/Sentinel/wiki/系统自适应限流) > 系统保护规则从应用级别(而不是资源维度)的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。 - 来源访问控制规则 AuthorityRule:[黑白名单控制](https://github.com/alibaba/Sentinel/wiki/黑白名单控制) > 根据调用来源判断请求是否允许通过。 - 热点参数规则 ParamFlowRule:[热点参数限流](https://github.com/alibaba/Sentinel/wiki/热点参数限流) > 看作一种特殊的流量控制规则,仅对包含热点参数的资源调用生效。它根据传入参数中的热点参数,与配置的限流阈值、模式,对包含热点参数的资源调用进行限流。 sentinel 还提供了相关 API 用于定制自己的规则策略。 上面默认的规则分类,可以通过代码定义,也可以使用 dashboard 定义。 定义规则可以通过 dashboard,也可以使用代码创建。如果想要持久化存储规则,可以利用 Nacos 等数据源。这一点在后面会讲。 --- ## Spring Cloud 整合 Sentinel 参考:[spring-cloud-alibaba-sentinel](https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel) 创建一个 demo 服务,引入 spring-cloud 中的 sentinel 依赖: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>0.9.0.RELEASE</version> </dependency> ``` 配置: ```yaml server: port: 8203 spring: application: name: demo cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: dashboard: localhost:8080 port: 8081 ``` 可以配置流控、降级、热点、授权多种规则: ![](http://zfh-public-blog.oss-cn-beijing.aliyuncs.com/image-1603205096371.png) 注解支持使用参考:[注解支持 —— 官方文档](https://github.com/alibaba/Sentinel/wiki/注解支持) 默认情况下是以 url 作为链路地址以及资源名的,我们可以在代码中用 @SentinelResource 注解来主动注明资源的名称、阻塞处理方法等。比如: ```java @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 方法: ```java public class BlockHandlerConfig { public static String handleException(String email, String msg, BlockException exception) { return "444, " + exception.getClass().getCanonicalName() + "\t 服务不可用"; } } ``` 需要注意的是,blockHandle 对应方法的参数必须与 `资源` 的参数保持一致,否则规则不会生效,且会抛出异常。 这里给 helloTest 这个 resource 配置一个简单的流控: ![](http://zfh-public-blog.oss-cn-beijing.aliyuncs.com/image-1603205127874.png) 测试: 快速请求 helloTest 对应的接口,发现成功请求与限流响应交错出现了。这表明我们的限流规则和 blockHandler 生效了。 ![](http://zfh-public-blog.oss-cn-beijing.aliyuncs.com/image-1603205168654.png) --- ## 规则持久化 需要注意的是,如果服务重启了,那么这些规则配置就会被丢失。其中一个解决办法是利用 Nacos 做配置中心,先将规则定义保存在 Nacos 中。 sentinel 提供了 file/nacos/zp/apollo 等规则扩展存储方式。具体参考官方文档:[动态规则扩展](https://github.com/alibaba/Sentinel/wiki/动态规则扩展) 一个服务若要使用 Nacos 中的配置作为 sentinel 规则,除了 Nacos 的依赖外,还需要引入如下依赖: ```xml <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> ``` 配置: ```yaml 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,内容比如: ```json [ { "resource": "helloTest", "limitApp": "default", "grade": 1, "count": 3, "strategy": 0, "controlBehavior": 0, "clusterMode": false } ] ``` ![](http://zfh-public-blog.oss-cn-beijing.aliyuncs.com/image-1603205194823.png) 启动后可以看到 sentinel 中出现了这个规则。在 nacos 中修改该规则,发现 sentinel 那边同步修改了(反之则不行) ![](http://zfh-public-blog.oss-cn-beijing.aliyuncs.com/image-1603205233228.png) --- ## 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 --- 参考: - [Sentinel 是什么?—— 官方文档](https://github.com/alibaba/Sentinel/wiki/介绍) - [新手指南 —— 官方文档](https://github.com/alibaba/Sentinel/wiki/新手指南) - https://blog.csdn.net/xiongxianze/article/details/87570156 - https://blog.csdn.net/weixin_44757206/article/details/107119085 --- 最近在系统地学习 Redis、RabbitMQ、ES 等技术的知识,着重关注原理、底层、并发等问题,关于相关技术分享后续会逐渐发布出来。欢迎关注公众号:**猿生物语**(ID:**JavaApes**) Last modification:October 21, 2020 © Allow specification reprint Support Appreciate the author AliPayWeChat Like 0 请作者喝杯肥宅快乐水吧!
3 comments
2222
文章写得好,网站都很吊
不用注册吗