随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应过载保护、热点流量防护等多个维度保护服务的稳定性。
Sentinel 具有以下特征(来自中文官网)
丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。
完善的 SPI 扩展机制:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
Sentinel生态组件:
Sentinel 分为两个部分:
Sentinel 下载地址:点击下载,下载后,运行jar包
浏览器输入localhost:8080,登录账号密码均为sentinel,登录成功。
新建Model:cloud-alibaba-sentinel-service,pom文件添加依赖:
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--SpringCloud ailibaba sentinel-datasource-nacos 持久化-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!--SpringCloud ailibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- SpringBoot整合Web组件+actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--日常通用jar包配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.6.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.swc.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
新增配置文件application.yml
server:
port: 8401
spring:
application:
name: cloud-alibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: 182.92.122.196:1111 #Nacos集群服务注册中心地址
sentinel:
transport:
dashboard: localhost:8080 #Sentinel dashboard地址
port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
management:
endpoints:
web:
exposure:
include: '*'
主启动类:
/**
* @Auther: songweichao
* @Date: 2023-05-17 10:37
* @Description:
*/
@EnableDiscoveryClient
@SpringBootApplication
public class SentinelMain {
public static void main(String[] args) {
SpringApplication.run(SentinelMain.class,args);
}
}
业务类
/**
* @Auther: songweichao
* @Date: 2023-05-17 10:38
* @Description:
*/
@RestController
@Slf4j
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello,Day Day UP";
}
@GetMapping("/hi")
public String hi() {
return "Hi,Good Good Study";
}
}
启动应用,因为Sentinel采用的懒加载,任意访问一个清求,才能看到Sentinel控制台如图所示,成功部署。
流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
点击“流控规则”,新增流控规则:
资源名:唯一名称,默认请求路径。
针对来源: Sentinel可以针对调用者进行限流,填写微服务名,默认default (不区分来源)
阈值类型/单机闻值:
是否集群:不需要集群。
流控模式:
流控效果:
直接拒绝(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。
快速点击访问http://localhost:8401/hello,结果如图所示。
Blocked by Sentinel (flow limiting) 是Sentinel的默认失败结果。
Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
通常冷启动的过程系统允许通过的 QPS 曲线如下图所示:
公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值;
添加配置,默认coldFactor为3,即请求 QPS 从10 / 3 = 3开始,经预热时长 6s 逐渐升至设定的 QPS 阈值。
作用效果是阈值变化 3-10,经过6S。
不停刷新访问http://localhost:8401/hi ,刚开始阈值小,会有快速失败,慢慢阈值变大,不再出现;
在实时监控,可以看到效果如图:
匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。
该方式的作用如下图所示:
添加配置,测试:
在实时监控,可以看到,QPS设置为2,当有多个请求是,会拒绝超过2个以外的请求,去排队完成。
这种方式主要用于处理间隔性突发的流量,例如消息队列。在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。
热点即经常访问的数据,很多时候我们希望统计或者限制某个热点数据中访问频次最高的TopN数据,并对其访问进行限流或者其它操作;
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "testHotKeyHandler")
public String testHotKey(@RequestParam(value = "v1",required = false) String v1,
@RequestParam(value = "v2",required = false) String v2){
return "------测试热点数据";
}
public String testHotKeyHandler(String v1,String v2,BlockException exception)
{
return "-----热点数据访问失败回调";
}
新增配置:
限流模式只支持QPS模式。
单机阀值以及统计窗口时长表示在此窗口时间超过阀值就限流。
上图配置中第一个参数有值的话,1秒的QPS为1,超过就限流,限流后调用testHotKeyHandler方法。
我们期望v1参数当它是某个特殊值123时,它的限流值和平时不一样,QPS能到了20;
快速点击访问 测试:
需要注意的是注解@SentinelResource和方法中运行时异常:
@SentinelResource 处理的是Sentinel控制台配置的违规情况,有blockHandler方法配置的兜底处理;
RuntimeException是java运行时报出的运行时异常RunTimeException,@SentinelResource不管
Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。
当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛DegradeException)。
选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
@GetMapping("/RT")
public String testRT() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("测试RT");
return "test--RT";
}
QPS >= 5 且异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束后,关闭降级
@GetMapping("/testY")
public String testY() {
log.info("testY 测试异常比例");
int age = 10/0;
return "******测试异常比例******";
}
调用就报错:单独访问,来一次报错一次(int age = 10/0),调一次错一次;
用postman测试:开启20个进程,200ms完成,同时浏览器访问
高并发发送请求,多次调用达到我们的配置条件。断路器开启(保险丝跳闸),微服务不可用了,不再报错error而是服务降级。
异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级
异常数,好理解,就是累积异常数,从而触发服务降级。
系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。
系统规则支持以下的模式:
可以添加一个配置类,用来做服务降级的兜底方法,在需要使用的地方,引入即可。
/**
* @Auther: songweichao
* @Date: 2023-05-17 11:37
* @Description:
*/
public class CustomerBlockHandler {
public static CommonResult handleException(BlockException exception){
return new CommonResult(2023,"自定义的限流处理信息......CustomerBlockHandler");
}
}
/**
* 自定义通用的限流处理逻辑,
blockHandlerClass = CustomerBlockHandler.class
blockHandler = handleException
上述配置:找CustomerBlockHandler类里的handleException方法进行兜底处理
*/
/**
* 自定义通用的限流处理逻辑
*/
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException")
public CommonResult customerBlockHandler()
{
return new CommonResult(200,"成功访问");
}
经过多次的配置测试,一旦重启应用,sentinel规则将消失,而生产环境需要将配置规则进行持久化。
怎么做呢?
将限流配置规则持久化进Nacos保存,只要访问谋而请求,sentinel控制台的流控规则就能从Nacos中获取到信息,只要Nacos里面的配置不删除,针对sentinel上的流控规则持续有效;
实现上述效果,使用的是sentinel-datasource-nacos
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
配置中添加:
server:
port: 8401
spring:
application:
name: cloud-alibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: 182.92.122.196:1111
sentinel:
transport:
dashboard: localhost:8080
port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
datasource:
ds1:
nacos:
server-addr: 182.92.122.196:1111
dataId: cloud-alibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
management:
endpoints:
web:
exposure:
include: '*'
关于配置中datasource,是将Sentinel的流控配置进行持久化到Nacos中的操作。通过在cloud-alibaba-sentinel-service的配置文件中添加json配置内容即可。
每次启动Sentinel后,都会从Nacos中加载配置;