大家好,我是冰河~~
一不小心《SpringCloud Alibaba实战》专栏都更新到第11章了,再不上车就跟不上了,小伙伴们快跟上啊!
注意:本项目完整源码加入 冰河技术 知识星球即可获取,文末有优惠券。
在《SpringCloud Alibaba实战》专栏前面的文章中,我们实现了用户微服务、商品微服务和订单微服务之间的远程调用,并且实现了服务调用的负载均衡。也基于阿里开源的Sentinel实现了服务的限流与容错。今天,就和大家一起来聊聊Sentinel的核心技术与配置规则,这应该是全网最全的Sentinel使用教程了吧。
本章总览
文章有点长呀,小伙伴们耐心看完,并跟着实操每一个案例,相信你一定会对Sentinel有一个全新的认识。
Sentinel核心功能
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。所以,Sentinel的核心功能包括:流量控制、熔断降级、系统负载保护。
流量控制
在高并发、大流量场景下,进入系统的流量如果不加控制的话,系统就很有可能会被流量压垮。所以,在流量正式进入系统之前,需要对流量进行控制,以便使流量均匀、可控的方式进入系统。
Sentinel作为一个非常出色的容错组件,能够将不可控的流量经过处理转化成均匀、可控的流量。
熔断降级
如果检测到系统中的某个调用链路中某个节点出现故障,比如请求超时、服务宕机或者异常比超出一定阈值时,就会对出现故障的节点的调用频率进行限制,甚至不调用出现故障的节点,让请求能够快速失败并返回,以最大程度避免影响到其他节点的服务而导致系统的级联故障。
Sentinel主要通过 限制并发线程数和响应时间 对资源的访问进行降级。
1.限制并发线程数进行降级
Sentinel可以通过限制服务节点的并发线程数量,来减少对其他服务节点的影响。例如,当某个服务节点出现故障,例如响应时间变长,或者直接宕机。此时,对服务的直接影响就是会造成请求线程数的不断堆积。如果这些堆积的线程数达到一定的数量后,对当前服务节点的后续请求就会被拒绝,等到堆积的线程完成任务后再开始继续接收新的请求。
2.通过响应时间进行降级
Sentinel除了可以通过限制并发线程数进行降级外,也能够通过响应时间进行降级。如果依赖的服务出现响应时间过长的情况,则所有对该服务的请求都会被拒绝,直到过了指定的时间窗口之后才能再次访问该服务。
系统负载保护
Sentinel提供了系统维度的自适应保护能力。当系统的压力和负载比较高的时候,如果还持续让大量的请求进入系统,此时就有可能将系统压垮,进而导致系统宕机。Sentinel会在集群环境下,将本应服务器A承载的流量转发到其他服务器上,比如转发到服务器B上。如果此时服务器B也处于高负载的状态,则Sentinel会提供相应的保护机制,让系统的入口流量和系统的整体负载达到平衡,让系统整体可用,并且能够最大限度的处理请求。
Sentinel核心规则
Sentinel的核心规则包括流控规则、熔断规则、热点规则、授权规则和系统规则,每种规则的配置方式不同。接下来,就详细介绍下Sentinel中的每种规则的作用与效果。
流控规则
Sentinel能够对流量进行控制,主要是监控应用的QPS流量或者并发线程数等指标,如果达到指定的阈值时,就会被流量进行控制,以避免服务被瞬时的高并发流量击垮,保证服务的高可靠性。
簇点链路规则
(1)点击簇点链路菜单,可以看到之前访问过的接口,如下所示。
(2)点击右侧的流控按钮,会弹出新增流控规则的提示框,如下所示。
这里,每个配置项的说明如下所示。
- 资源名:资源的唯一名称,默认就是请求的接口路径,可以自行修改,但是要保证唯一。
- 针对来源:具体针对某个微服务进行限流,默认值为default,表示不区分来源,全部限流。
- 阈值类型:QPS表示通过QPS进行限流,并发线程数表示通过并发线程数限流。
- 单机阈值:与阈值类型组合使用。如果阈值类型选择的是QPS,表示当调用接口的QPS达到阈值时,进行限流操作。如果阈值类型选择的是并发线程数,则表示当调用接口的并发线程数达到阈值时,进行限流操作。
- 是否集群:选中则表示集群环境,不选中则表示非集群环境。
配置简单限流
这里,针对http://localhost:8080/order/test_sentinel
接口进行简单的配置,在新增流控规则里阈值类型选择QPS,单机阈值输入3,表示每秒钟的请求量如果超过3,则会触发Sentinel的限流操作。
点击新增按钮后,会为http://localhost:8080/order/test_sentinel
接口新增一条限流规则,如下所示。
接下来,在浏览器上快速刷新http://localhost:8080/order/test_sentinel
接口,当每秒钟的刷新频率超过3次时,会出现如下所示的提示信息。
配置流控模式
点击http://localhost:8080/order/test_sentinel
接口流控规则后面的编辑按钮,打开编辑流控规则弹出框(如果是首次配置的话,就是新增流控规则弹出框),点击高级选项配置。
会显示出如下所示的界面。
可以看到,Sentinel主要提供了三种流控模式,分别为直接、关联和链路。
- 直接:默认的流控模式,当接口达到限流条件时,直接开启限流功能。
- 关联:当关联的资源达到限流条件时,开启限流功能。
- 链路:当从某个接口请求过来的资源达到限流条件时,开启限流功能。
演示直接流控模式
Sentinel默认就是使用的直接流控模式,我们之前在订单微服务中集成的就是Sentinel的直接流控模式,在本文的流控规则-配置简单限流中,也是使用的直接流控模式,这里不再赘述。
演示关联流控模式
(1)在订单微服务的io.binghe.shop.order.controller.OrderController
类中新增 /test_sentinel2
接口,如下所示。
@GetMapping(value = "/test_sentinel2") public String testSentinel2(){ log.info("测试Sentinel2"); return "sentinel2"; }
(2)在浏览器上访问下http://localhost:8080/order/test_sentinel2
接口,以便使Sentinel检测到http://localhost:8080/order/test_sentinel2
接口。
注意:如果想使用Sentinel对某个接口进行限流和降级等操作,一定要先访问下接口,使Sentinel检测出相应的接口,这里一定要注意,在后续的文章中,不再单独说明。
(3)回到为http://localhost:8080/order/test_sentinel
接口配置流控规则的页面,如下所示。
(4)在流控模式中选择关联,在关联资源中输入/test_sentinel2
,如下所示。
点击保存按钮保存配置。
(5)打开JMeter,对http://localhost:8080/order/test_sentinel2
接口进行测试,使其每秒钟的访问次数大于3,JMeter的具体配置如下所示。
在线程组中配置每秒访问4次。
配置完毕后,使用JMeter开始访问http://localhost:8080/order/test_sentinel2
接口。
(6)在浏览器上刷新http://localhost:8080/order/test_sentinel
接口,发现已经触发了Sentinel的限流功能。
至此,关联流控模式演示完毕。
演示链路流控模式
(1)在订单微服务的io.binghe.shop.order.service
包中新增SentinelService接口,用于测试流控模式,源码如下所示。
/** * @author binghe * @version 1.0.0 * @description 测试Sentinel */ public interface SentinelService { /** * 测试方法 */ void sendMessage(); }
(2)在订单微服务的io.binghe.shop.order.service
.impl包中新增SentinelServiceImpl类,实现SentinelService接口,源码如下所示。
/** * @author binghe * @version 1.0.0 * @description 测试类 */ @Service public class SentinelServiceImpl implements SentinelService { @Override @SentinelResource("sendMessage") public void sendMessage() { System.out.println("测试Sentinel的链路流控模式"); } }
这里,我们在sendMessage()方法上使用了@SentinelResource注解, @SentinelResource注解会在后续文章中介绍,这里不再赘述。
(3)在订单微服务的io.binghe.shop.order.controller
包下新建SentinelController类,用于测试接口,源码如下所示。
/** * @author binghe * @version 1.0.0 * @description 测试Sentinel */ @Slf4j @RestController public class SentinelController { @Autowired private SentinelService sentinelService; @GetMapping(value = "/request_sentinel1") public String requestSentinel1(){ log.info("测试Sentinel1"); sentinelService.sendMessage(); return "sentinel1"; } @GetMapping(value = "/request_sentinel2") public String requestSentinel2(){ log.info("测试Sentinel2"); sentinelService.sendMessage(); return "sentinel2"; } }
(4)升级SpringCloud Alibaba的依赖版本到2.2.7.RELEASE,升级SpringCloud版本到Hoxton.SR12,并且加入SpringBoot的管理依赖。主要的修改的是shop-springcloud-alibaba父工程的pom.xml配置,修改后的配置文件如下所示。
<properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring-cloud.version>Hoxton.SR12</spring-cloud.version> <spring-cloud-alibaba.version>2.2.7.RELEASE</spring-cloud-alibaba.version> <spring.boot.version>2.3.12.RELEASE</spring.boot.version> <logback.version>1.1.7</logback.version> <slf4j.version>1.7.21</slf4j.version> <common.logging>1.2</common.logging> <fastjson.version>1.2.51</fastjson.version> <mybatis.version>3.4.6</mybatis.version> <mybatis.plus.version>3.4.1</mybatis.plus.version> <mysql.jdbc.version>8.0.19</mysql.jdbc.version> <druid.version>1.1.10</druid.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>${spring.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
(5)升级Nacos,将Nacos注册中心由1.4.3版本升级为2.1.0版本,并进入Nacos的bin目录,输入如下命令启动Nacos。
startup.cmd -m standalone
(6)在订单微服务的application.yml文件中新增链路配置,如下所示。
spring: cloud: sentinel: web-context-unify: false
(7)在浏览器中分别访问http://localhost:8080/order/request_sentinel1
和http://localhost:8080/order/request_sentinel2
,查看Sentinel中的簇点链路,如下所示。
(8)点击sendMessage后面的流控按钮,如下所示。
(9)在弹出的新增流控规则编辑框中阈值类型选择QPS,单机阈值输入3,在打开的高级选项中的流控模式选择链路,入口资源输入/request_sentinel1,如下所示。
点击新增按钮保存配置,此时,如果是通过http://localhost:8080/order/request_sentinel1
接口调用io.binghe.shop.order.service.SentinelService#sendMessage()
方法时,如果调用的频率每秒钟超过3次,就会触发Sentinel的限流操作,而通过http://localhost:8080/order/request_sentinel2
接口调用io.binghe.shop.order.service.SentinelService#sendMessage()
方法时,则不受限制。
(10)在浏览器中不断访问
http://localhost:8080/order/request_sentinel1
,使得每秒的访问次数超过3,则会触发Sentinel的限流操作,如下所示。
访问http://localhost:8080/order/request_sentinel2
接口则不会被限流。
至此,链路流控模式演示完毕。
附加说明
在流控规则的高级选项中还有三个流控效果,如下所示。
接下来,就对这三个选项进行简单的说明。
- 快速失败:会直接失败,抛出异常,期间不会做任何其他的处理操作。
- Warm Up:从开始阈值到最大QPS阈值会有一个缓冲,可以设置一个预热时长,这个选项比较适合突发瞬时高并发流量的场景,能够将突发的高并发流量转换为均匀、缓慢增长的场景。
- 排队等待:能够使请求均匀的通过,单机的阈值为每秒通过的请求数量,其余的请求会排队等待。另外,还会设置一个超时时间,当请求超过超时时间未处理时,会被丢弃。
熔断规则
降级规则一般情况下,指的是满足某些条件时,对服务进行降级操作。
熔断规则概述
Sentinel主要提供了三个熔断策略,分别为:慢调用比例、异常比例和异常数。
演示基于慢调用比例熔断
(1)首先在浏览器中访问
http://localhost:8080/order/request_sentinel2
,在Sentinel的簇点链路里找到/request_sentinel2
(2)点击熔断按钮,进入熔断规则配置框,按照如下方式进行配置。
上述配置表示最大响应时长为1ms,比例阈值达到0.1时,会触发熔断操作,并且熔断的时长为2,最小请求数未5,统计的时长为1000毫秒。
(3)点击新增按钮后,不断在浏览器中刷新http://localhost:8080/order/request_sentinel2
,会发现触发了Sentinel的熔断操作,如下所示。
演示基于异常比例熔断
(1)在订单微服务的io.binghe.shop.order.controller.SentinelController
类中定义一个成员变量count,用来记录访问计数,同时,新增一个requestSentinel4()方法用来测试基于异常比例的熔断,如下所示。
private int count = 0; @GetMapping(value = "/request_sentinel4") @SentinelResource("request_sentinel4") public String requestSentinel4(){ log.info("测试Sentinel4"); count++; //模拟异常,比例为50% if (count % 2 == 0){ throw new RuntimeException("演示基于异常比例熔断"); } return "sentinel4"; }
(2)首先在浏览器中访问
http://localhost:8080/order/request_sentinel4
,在Sentinel的簇点链路里找到/request_sentinel4。
(3)点击熔断按钮,进入熔断规则配置框,按照如下方式进行配置。
在io.binghe.shop.order.controller.SentinelController#requestSentinel4()
方法中,设置的异常比例为50%,这里在Sentinel的比例阈值中设置的异常比例为0.3,也就是30%,所以,在访问http://localhost:8080/order/request_sentinel4
接口时,会触发Sentinel的熔断操作。
(4)点击新增按钮后,不断在浏览器中刷新http://localhost:8080/order/request_sentinel4
,会发现触发了Sentinel的熔断操作,如下所示。
演示基于异常数熔断
(1)首先在浏览器中访问
http://localhost:8080/order/request_sentinel4
,在Sentinel的簇点链路里找到/request_sentinel4。
(2)点击熔断按钮,进入熔断规则配置框,按照如下方式进行配置。
上述配置表示,在1秒钟内最少请求2次,当异常数大于1时,会触发熔断操作,熔断的时长为5秒。
(3)点击保存按钮后,不断在浏览器中刷新http://localhost:8080/order/request_sentinel4
,会发现触发了Sentinel的熔断操作,如下所示。
热点规则
Sentinel的热点规则可以将流量规则控制到具体的参数上。
热点规则概述
Sentinel的热点规则可以根据具体的参数来控制流量规则,适用于根据不同参数进行流量控制的场景。
演示热点规则
(1)在订单微服务的io.binghe.shop.order.controller.SentinelController
类中新增requestSentinel3()方法,其中会带有一个String类型的参数header和一个String类型的参数body,如下所示。
@GetMapping(value = "/request_sentinel3") @SentinelResource("request_sentinel3") public String requestSentinel3(String header, String body){ log.info("测试Sentinel3"); return "sentinel3"; }
(2)在浏览器中访问http://localhost:8080/order/request_sentinel3
接口,在Sentinel的簇点链路中会显示/request_sentinel3接口,如下所示。
(3)点击热点按钮,如下所示。
(4)在弹出的热点规则配置框中的参数索引中输入0,单机阈值输入1,统计窗口时长输入1,如下所示。
表示对requestSentinel3()方法的第一个参数header进行限流,如果每秒钟访问的次数超过1次,则触发限流。
(5)保存配置后,在浏览器中不断访问http://localhost:8080/order/request_sentinel3?header=header
,当每秒访问的频率超过1次时,会触发Sentinel的限流操作,如下所示。
不断访问http://localhost:8080/order/request_sentinel3?body=body
,则不会触发限流操作。
演示热点高级选项规则
(1)在弹出的热点规则配置框中打开高级选项,在参数类型中选择java.lang.String,因为在参数索引中输入0,表示的是对header参数限流,而header参数是String类型的。在参数值里输入header,也就是为参数名为header的参数赋值为字符串header。限流阈值为1,如下所示。
(2)点击添加按钮后如下所示。
(3)点击保存按钮,在浏览器不断刷新http://localhost:8080/order/request_sentinel3?header=header
,会触发Sentinel的限流操作。