本文为尚硅谷周阳《springcloud第二季》视频学习笔记
分布式系统的流量防护卫兵
sentinel |
hystrix |
单独一个组件可以独立出来 |
需要程序员手工搭建监控平台 |
直接界面化的细粒度统一配置 |
没有一套web界面给我们进行细粒度化的配置 |
# github下载链接,按照视频使用1.7版本
https://github.com/alibaba/Sentinel/releases/download/1.7.0/sentinel-dashboard-1.7.0.jar
# 1、默认端口8080,注意不要被占用,有Java环境
java -jar sentinel-dashboard-1.7.0.jar
# 2、访问localhost:8080,账号密码为sentinel
localhost:8080
添加如下Maven依赖
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-web
com.alibaba.cloud
spring-cloud-alibaba-nacos-discovery
com.alibaba.csp
sentinel-datasource-nacos
com.alibaba.cloud
spring-cloud-alibaba-sentinel
org.springframework.boot
spring-boot-starter-test
test
com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.1.0.RELEASE
pom
import
server:
port: 8401
spring:
application:
name: springcloudAlibaba-sentinel
cloud:
nacos:
discovery:
# nacos注册中心地址
server-addr: localhost:8848
sentinel:
transport:
# 默认端口8719,如果被占用+1直到扫描到不被占用的端口
port: 8719
# sentinel dashboard地址
dashboard: localhost:8080
@EnableDiscoveryClient
@SpringBootApplication
public class SpringcloudAlibabaSentinelApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudAlibabaSentinelApplication.class, args);
}
}
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA(){
return "testA...";
}
@GetMapping("/testB")
public String testB(){
return "testB...";
}
}
启动项目请求接口,刷新sentinel dashboard,懒加载,不请求接口dashboard没有服务列表
可以查看接口访问情况
可以查看接口及其链路
在”簇点链路“菜单可以点击资源名后对应的流控按钮,进入流控编辑页面
也可以直接点”流控规则“菜单新增流控规则
点击上图”高级选项“默认选项如下,填写单机阈值为1,点击新增
请求接口超过流控频率(QPS即每秒请求数)
当调用该api的线程数达到阈值的时候,进行限流
添加线程数限流规则
超过每秒一次请求接口并没有超出流控提示(单线程)
显然线程数流控与QPS有所区别
QPS |
线程数 |
|
解读 |
关门打狗 |
御敌于国门之外 |
理解 |
拦截请求 |
接收请求,但是只能处理指定配置阈值。好比银行柜台,银行进来很多客人,但是只有一个柜台,就只能处理一个人的业务,其他的虽然进入银行,但是不处理 |
多线程下,如果有线程在被处理,已经到达阈值,其他线程请求会提示超出流控
当关联的资源A达到阈值时,就限流B(我感冒你吃药)
如:当支付接口达到阈值,可以限流下订单接口
使用postman模拟并发阈值访问
testA接口由可以正常访问变为限制访问
直到testB接口访问结束(不超出设定阈值)后,testA访问正常
快速失败直接抛出异常
查看源码来源于com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
预热公式:阈值除以冷加载因子(coldFactor(默认3))
经过预热时长才达到阈值
此场景用于避免接口瞬间大幅度提升请求,导致系统打垮
配置如下:
解读:阈值为10÷3(冷加载因子)取整=3,即从QPS3~10需预热五秒钟
源码来自于:
com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController#WarmUpController(double, int)
匀速排第,让请求以均匀的速度(严格,漏桶算法)通过,阈值类型必须设成QPS,否则无效
思路:拒绝”忙得时候忙死,闲的时候闲死“
配置如下:
解释:testA每秒一次请求,超过就排队,等待超时时间为20秒
源码:com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController
使用postman发送每秒一次接口请求,后台日志结果
熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高)
对这个资源进行限制,让它快速响应失败
避免影响到其他资源导致级联错误
当资源被降级后,在接下来的时间降级窗口之内,对该资源的调用都自动熔断
默认行为抛出DegradeException
sentinel的断路器没有半开状态
半开状态解释:hystrix会检查请求是否有异常,有就打开断路器,没有就关闭断路器
解释:秒级,RT超出阈值且在时间窗口内通过的请求>=5,两个条件同时满足时触发降级
窗口期过后关闭断路器
RT最大4900(更大的需求通过-Dcsp.sentinel.statistic.max.rt=xx设置虚拟机参数生效)
配置:
代码接口模拟一秒处理请求响应
jmeter模拟1秒钟10个线程请求
显然接口testB处理不了一秒钟10个请求,只能一秒钟一个
开启jmeter,请求接口发现接口被熔断
待关闭jmeter后,请求正常响应
解释:秒级,QPS>=5且异常比例(秒级统计)超过阈值时,触发降级
时间窗口结束后,关闭降级
配置:
接口代码模拟超过异常比例:
jmeter模拟一秒钟10个请求
请求接口,已经熔断保护
停止jmeter,请求接口,抛出错误
解释:分钟统计,超过阈值时,触发降级
时间窗口结束后,关闭降级
配置:
需要注意的是,统计时间为分钟级
如果时间窗口小于60s,结束窗口期,仍可能进入熔断降级
配置时间窗口时间要大于60s
代码:
请求接口五次异常以后,熔断降级
带时间超过窗口期时间,请求异常
解释:
很多时候我们希望根据某些热点数据访问频次高的数据进行限制
如:苹果新发布手机,超话等
热点参数限流会根据传入的热点参数,单独限制流控
只对该热点参数的某些值进行限制
热点限流源码:
com.alibaba.csp.sentinel.slots.block.BlockException
限流的总体思想:
try {
// 逻辑符合限流规则
} catch (Exception e) {
// 进入限流
} finally {
}
热点限流配置:
代码:
第一个参数p1不为空,请求频率超过一秒1次,执行兜底方法
请求第二个参数p2,不受影响
如果代码没有配置兜底方法
超过限流规则,则正常打出错误日志
需要注意的是,只要含有指定限流规则的参数就会执行兜底,后面可以继续加别的参数
解释:即VIP通道
配置:
代码不变,请求接口超过1秒一次,但传入的参数为例外项,没有超出阈值,则没有执行限流
参数例外项支持一下七种参数类型
值得注意的是@SentinelResource不会影响代码正常的异常,没有超出限流仍会有异常抛出
解释:即系统自适应限流
从整体的维度对应用入口流量进行配置
”防疫一刀切“(粒度变小)
配置:
各个阈值类型解释:
当系统load1超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR阶段)
系统容量由系统的maxQpsminRt估算得出。设定参考值一般是CPU cores*2.5
对标@HystrixCommand
代码如下:
此时超过限流访问接口不会执行兜底方法
代码:
配置:
超出限流规则后:
编写统一处理限流异常类,注意方法有static和入参BlockException
代码:
此时业务接口@SentinelResource注解的值,可以按照需要配置
blockHandlerClass的值为限流异常处理类
blockHandler为异常处理的具体方法
代码:
配置:
请求超出配置后执行结果:
以上解决了兜底方法面临的问题,解耦处理、
注意:注解埋点不支持private方法
不推荐,略
引入pom依赖:
com.alibaba.cloud
spring-cloud-alibaba-nacos-discovery
org.springframework.boot
spring-boot-starter-web
启动类:
@EnableDiscoveryClient // 开启服务注册发现
@SpringBootApplication
public class SpringcloudAlibabaOrderApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudAlibabaOrderApplication.class, args);
}
}
yml:
server:
port: 8402
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
application:
name: springcloudAlibaba-order
代码:
@RestController
public class OrderController {
private static HashMap dao = new HashMap<>();
static {
dao.put(1L, "orderDetail...1");
dao.put(2L, "orderDetail...2");
dao.put(3L, "orderDetail...3");
}
@GetMapping("/orderDetail/{id}")
public String orderDetail(@PathVariable("id") Long id) {
return dao.get(id);
}
}
pom新增依赖:
org.springframework.cloud
spring-cloud-starter-openfeign
2.1.3.RELEASE
启动类新增注解:
@EnableFeignClients // 新增开启feign远程调用
@EnableDiscoveryClient
@SpringBootApplication
public class SpringcloudAlibabaSentinelApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudAlibabaSentinelApplication.class, args);
}
}
yml新增配置:
# 激活sentinel对feign的支持
feign:
sentinel:
enabled: true
代码:
新建远程调用feign接口
@FeignClient(value = "springcloudAlibaba-order",
fallback = OrderFeignServiceFallbackService.class) // 降级实现类
public interface OrderFeignService {
@GetMapping("/orderDetail/{id}")
String orderDetail(@PathVariable("id") Long id);
}
降级实现类
@Component // 注意添加注解
public class OrderFeignServiceFallbackService implements OrderFeignService {
@Override
public String orderDetail(Long id){
return "服务降级返回OrderFeignServiceFallbackService...";
}
}
起到了防止服务调用不成功,一直重试卡死的情况
如果需要配置限流和兜底请自行添加@SentinelResource进行测试
需要注意的是fallback为Java异常处理,blockHandler为限流异常处理
sentinel默认没有持久化配置信息,服务启动配置即消失
sentinel持久化采用结合nacos持久化的方案
将限流配置规则持久化存储到nacos保存
只要nacos配置不删除,则sentinel限流规则持续有效
其中:
resource:资源名称;
limitApp:来源应用;
grade:阈值类型,0表示线程数,1表示QPS;
count:单机阈值;
strategy:流控模式,0表示直接,1表示关联,2表示链路;
controlBehavior:流控效果,0表示快速失败,1表示warmup,2表示排队等待;
clusterMode:是否集群;
spring:
application:
name: springcloudAlibaba-sentinel
cloud:
sentinel:
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: springcloudAlibaba-sentinel
goupId: DEFAULT_GROUP
data-type: json
rule-type: flow