Alibaba Sentinel 熔断与限流
一、Sentinel
1、官网
2、是什么
与Hystrix比较
.随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
3、去哪下
4、能干嘛
服务雪崩
服务降级
服务熔断
服务限流
5、怎么玩
二、安装Sentinel控制台
1、sentinel组件由两部分构成
sentinel分为两个部分:
1、核心库(java客户端)不依赖任何框架/库,能够运行于所有Java运行时环境,同时Dubbo/Spring Cloud等框架也有较好的支持
2、控制台(Dashboard)基于Spring Boot开发,打包后可以直接运行,不需要哦额外的Tomcat等应用容器
2、安装步骤
1、前提:java8环境+8080端口不能被占用
2、命令:java -jar sentinel-dashboard-1.7.0.jar
3、访问sentinel管理界面:http://localhost:8080
账号密码均为sentinel
三、初始化演示工程
1、启动Nacos8848成功
http://loaclhost:8848/nacos/#/login
2、Module
1)新建 cloudalibaba-sentinel-service8401
2)POM
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--后续做持久化用到的-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
3)YML
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
#Nacos服务注册中心地址
server-addr: localhost:8848
sentinel:
transport:
#配置Sentinel dashboard地址
dashboard: localhost:8080
#默认8719端口,假如被占用会自动从8719开始依次扫描,直至找到未被占用的端口
port: 8719
management:
endpoints:
web:
exposure:
include: '*'
4)主启动类
package com.atguigu.springcloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class MainApp8401 {
public static void main(String[] args){
SpringApplication.run(MainApp8401.class,args);
}
}
5)业务类FlowLimitController
package com.atguigu.springcloud.alibaba.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA(){
return "----------testA";
}
@GetMapping("/testB")
public String testB(){
return "-------testB";
}
}
3、启动Sentinel8080
java -jar sentinel-dashboard-1.7.0.jar
4、启动微服务8401
5、启动840微服务后查看sentienl控制台
页面为空:
说明:
Sentinel采用懒加载
需要执行一次访问:
http://localhost:8401/testB
http://localhost:8401/testA
四、流控规则
1、基本介绍
资源名:唯一名称,默认请求路径
针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
阈值类型、单机阈值:
----1QPS:(每秒钟请求数量):当调用该api的QPS达到阈值的时候,进行限流
----2线程数:当调用该api的线程数达到阈值的时候,进行限流
是否集群:不需要集群
流控模式:
-----1 直接:api达到限流条件时,直接限流
-----2 关联:当关联的资源达到阈值时,就限流自己
-----3 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【api级别的针对来源】
流控效果:
----1快速失败:直接失败,抛异常
----2Warm Up:根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值
----3排队等待:匀速排队,让请求以匀速通过,阈值类型必须设置为QPS,否则无效
2、流控模式
1)直接(默认)
测试:http://localhost:8401/testA
每秒只能点一次,否则Blocked by Sentinel (flow limiting)
直接调用的是默认报错信息,技术方面OK
但是,是否可以设置成我们自己定义的报错信息呢
类似一个fallback的兜底方法
后续慢慢改进
2)关联
解释:当关联的资源达到阈值时,就限流自己
当与A关联的资源B达到阈值后,就限流A自己
B惹事,A挂了
配置:
使用postman测试
3)链路
多个请求调用同一个微服务
3、流控效果
1)直接 -->快速失败(默认的流控处理)
直接失败,抛出异常
2)预热
说明:公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值
官网:
Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
源码:
WarmUp配置:
测试:http://localhost:8401/testA
刚开始不行,后续慢慢可以
应用场景:
秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。
3)排队等待
五、降级规则
1、基本介绍
Sentinel的断路器是没有半开状态的
2、降级策略实战
1)RT
1>是什么
我们通常用一下几种来衡量资源是否处于稳定状态:
平均响应时间、异常时间、异常数
详见官网
2>测试
代码:
@GetMapping("/testD")
public String testD(){
//暂停几秒钟线程
try{
TimeUnit.SECONDS.sleep(1);
}
catch (InterruptedException e){
e.printStackTrace();
}
log.info("testD 测试RT");
return "-----testD0";
}
配置:
jmeter压测:
结论:
永远一秒钟打进来十个线程调用testD,我们希望200毫秒处理完本次任务,
如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,后续停止jmeter,没有那么大的访问量了,断路器关闭,微服务恢复OK。
2)异常比例
1>是什么
当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态,即在接下的时间窗口之内,对这个方法的调用都会自动的返回。异常比率的阈值范围是[0.0,1.0],代表0%-100%
2>测试
代码:
@GetMapping("/testE")
public String testE(){
log.info("testE 测试RT");
int age=10/0;
return "----testE";
}
配置:
结论:
流控是根据访问量判断是否拒绝,熔断是根据系统业务出错是否拒绝
3)异常数
1>是什么
当资源近一分钟的异常数超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若timeWindow小于60s,则结束熔断状态后仍可能再进入熔断状态
窗口期应大于等于60秒
1>测试
@GetMapping("/testF")
public String testF() {
log.info("testE 测试异常数");
int age = 10 / 0;
return "----testF";
}
配置:
点击五次即跳闸断电
六、热点key限流
1、是什么
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。
2、官网
3、承上启下复习start
新注解标签
@SentinelResource
4、代码
源码:com.alibaba.csp.sentinel.slots.block.BlockException
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value = "p2",required = false) String p2){
return "-----testHotKey";
}
public String deal_testHotKey(String p1, String p2, BlockException exception){
return "-----deal_testHotKey,兜底方法";
}
5、配置
@SentinelResource(value = “testHotKey”,blockHandler = “deal_testHotKey”)
方法testHotKey里面第一个参数之哟啊QPS超过每秒1次,马上降级处理,执行我们自定义的兜底方法
如果没有设置blockHandler,则使用sentinel的默认兜底方法,即报错Enable Page
6、测试
http://localhost:8401/testHotKey?p1=0
超过每秒阈值时执行兜底方法
7、参数例外项
上述案例演示了第一个参数p1,当QPS超过1秒1次点击后马上被限流
特殊情况:
我们期望参数当它是某个特殊值时,它的限流值和平时不一样
特例:假如当p1的值等于5时,它的阈值可以达到200
配置:
测试:
http://localhost:8401/testHotKey?p1=5
http://localhost:8401/testHotKey?p1=0
当p1为5时,阈值变为200
当p1不为5时,阈值为1