一句话解释就是阿里版本的Hystrix
能干什么:
用于处理服务器使用中的各种问题:服务雪崩、服务降级、服务熔断、服务限流。
下载地址:
https://github.com/alibaba/Sentinel/releases
sentienl由2部分组成:
因此下载好的sentinel.jar可以直接运行,前提是java环境OK和8080端口不被占用。
在控制台执行:
java -jar sentinel-dashboard-1.7.0.jar
然后访问:localhost:8080页面,用户名和密码都是sentinel
Nacos与Sentinel简单联合工程
1、启动Nacos8848。
2、建Model让注册进Nacos并让Sentinel监控。
建model
改pom:
com.ty.springCloud
cloud-api-commons
${project.version}
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
com.alibaba.csp
sentinel-datasource-nacos
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-devtools
runtime
true
cn.hutool
hutool-all
4.6.3
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
建yml:
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
management:
endpoints:
web:
exposure:
include: '*'
主启动:
@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401{
public static void main(String[] args) {
SpringApplication.run(MainApp8401.class, args);
}}
controller类:
@RestController
public class FlowLimitController{
@GetMapping("/testA")
public String testA() {
return "------testA";
}
@GetMapping("/testB")
public String testB() {
return "------testB";
}}
3、启动sentinel8080和微服务8401。
4、由于sentinel采用懒加载,所以此时在sentinel页面无任何显示,需访问一次localhost:8401/testA或者localhost:8401/testB,才会显示在sentinel页面。
①、直接+快速失败:(QPS模式下)
OPS(每秒钟的请求数量):当调用该api的QPS达到阈值时,进行限流。
直接:调用api达到限流条件时,直接限流。
快速失败:直接失败,报异常。
演示案例:
每一秒访问接口localhost:8401/testA的并发量不能超过1,超过1直接限流报异常
当1s访问/testA超过一次时显示页面:
也可不想显示此报错信息,自己定义一个兜底fallback方法。后续会讲。
QPS与线程数都设置为1时区别:
例如银行网点办理业务,只有一个银行业务人员时,QPS相当于1s只允许一个办理人员进银行办理,当在银行外面要办理业务的人1s超过1个时,直接限流。而线程数则表示允许办理人员都进银行,但是每次只能一个进行办理。
即QPS为1s只允许一个请求。线程数表示1s只允许一个线程。
②、关联+快速失败
关联:当关联的资源达到阈值时,限流自己。应用场景如支付和下订单,当支付达到阈值时,就限流下订单模块。
比如/testA关联/testB,当/testB达到访问阈值时,就限流/testA。下图的单机阈值是针对/testB设置的。
③、直接+Warm Up(预热):
Warm Up:跟进codeFactor(冷加载因子,默认3)的值,从阈值/codeFactor开始,经过预热时长,才达到设置的QPS阈值。
举例:
由于设置Warm Up模式,所以一开始的阈值为设定的10/3=3,预热时长为5s。所以会出现一开始1s中访问的请求大于3小于10时会出现限流情况,但过了预热时长后,请求大于3小于10就不会限流。
常用应用场景: 秒杀系统在开启的瞬间会有很多的流量上来,很有可能把系统打死,预热方式就是为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设定的阈值。
④、直接+排队等候:
排队等候:匀速排队,让请求以匀速通过,阈值类似必须设置为QPS,否则无效。
匀速排队:
阈值QPS=2,每隔500ms才允许通过下一个请求,是通过1s/2=500ms算出来的。
举例:
此时多个请求同时访问/testA时,控制台应该是没隔1s打印一次当前线程名称。可以用postman来实验。
@GetMapping("/testD")
public String testD(){
try { TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("testD 测试RT");
return "------testD"; }
执行该段程序需1s,即设定此程序的平均响应时间为1s。
设置RT,让其阈值为0.2s,时间窗口为2s。
然后使用Jmeter,以每秒钟10个请求方式打过去。
此时访问TestD就会报错
停止Jmeter后过2s在访问就正常
是因为我们程序设计执行TestD方法睡眠1s也就是平均响应时间至少1s,加上每秒钟的请求为10次。
同时满足 1秒持续进入5个请求和平均响应时间>阈值这2个条件,所以会报错。
异常比列的降级条件为:
每秒钟的请求数QPS>5;
每秒的异常比例超过设定阈值;
举例:
异常比例设置为20%,以每秒10次请求访问一个除0方法接口。
/testE中实现一个除0异常
@GetMapping("/testE")
public String testE(){
int a = 10/0;
return "------testE";
}
若单次访问/testE,不走异常比例降级流程,即出现Error页面:
若通过Jmeter模拟一秒中10次请求的方式同时访问/testE,则会出现降级报错页面:
一分钟内访问的请求出现异常的次数超过设定的阈值时,就降级并提示。而且时间窗口设定必须大于1分钟。
由于是出现异常的次数达到阈值才会出现降级提示页面,如全采用除0异常作请求,设定阈值为5,则前5次请求得到的都是除0错误页面,第6次才会出现降级提示页面。
新建需测试的热点参数接口以及接口对应的限流时提示内容个性化配置:
@GetMapping("/testHostKey")
@SentinelResource(value = "testHostKey",blockHandler = "deal_HostKey")//value参数值需唯一,一般规范为rest地址去掉斜线,blockHandler为接口对应的限流时提示内容个性化配置
public String testHostKey(@RequestParam(value = "a1",required = false)String a1,
@RequestParam(value = "a2",required = false)String a2){
return "------testHostkey";
}
public String deal_HostKey(String a1, String a2, BlockException bl){ //deal_HostKey中参数需与引用的接口参数一致,且需BlockException
return "------deal_HostKey,(′д` )…彡…彡";
}
@HystrixCommand类似@SentinelResource
接口对应的限流时提示内容个性化配置的配置由@SentinelResource中的blockHandler参数值来配置。
sentinel中配置热点key限流:
测试结果:1s请求超过1次时
当限流的参数是某个特殊值时,它的限流阈值和平时不一样。
/testHoskKey中第一个参数的值为5时,它的阈值为200而不是1。
需要注意SentinelResource处理的是配置异常,而不是运行时异常
使用上述兜底方案会出现的问题:
在第八点中将解决它们。
创建一个类用于用户自定义限流处理逻辑:
public class CustomerBlockHandler {
public static String blockHandler_01(BlockException bl){
return "------------global handler,blockHandler_01";
}
public static String blockHandler_02(BlockException bl){
return "------------global handler,blockHandler_02";
}
}
需注意定义的全局兜底方法需用static关键字修饰。
然后兜底的业务走这个全局兜底配置类:
@GetMapping("/testHandler")
@SentinelResource(value = "testHandler",
blockHandlerClass = CustomerBlockHandler.class,
blockHandler = "blockHandler_02") //指定以全局兜底类中的BlockHandler_02方法来兜底
public String testHandler(){
return "--------testHanlder";
}
fallback走程序运行时异常需处理的兜底方法
blockHandler走sentinel配置时服务异常的兜底方法
fallback的配置方法同blockHandler类似
当两者都配置时:
也就说未达到设定阈值时走程序运行异常兜底,达到阈值后走sentinel配置兜底。
一旦我们重启应用,Sentinel规则将消失,生产环境需要将配置规则进行持久化
将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上Sentinel上的流控规则持续有效。
具体配置:
pom中新增:
com.alibaba.csp
sentinel-datasource-nacos
yml文件中添加:
spring:
cloud:
sentinel:
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: cloudalibaba-sentinel-service #微服务名称
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
在nacos中新增配置规则json文件:
data id和groupid要和yml文件中对应。
json文件内容:
[
{
"resource": "/testA",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]