日升时奋斗,日落时自省?
目录
①流量控制: 可以通过配置规则对接口的访问量进行限制,避免因流量过高而导致系统崩溃。
②服务熔断: 当后端服务不可用或异常时,可以通过配置熔断规则,快速失败并返回错误信息,避免连锁故障。
③系统负载保护: 根据系统的负载情况,自动控制流量的通过,防止系统出现过载现象。
④统计和监控:提供实时的流量控制和熔断统计信息,可以通过Dashboard (控制台)进行可视化监控和配置。
注:以下展示的都是控制台的操作,当然代码也是可以进行设置的(并不常用,控制台会更灵活)
流量控制是指对系统中的请求流量进行限制和管理,以确保系统在承受能力范围内正常运行。
常见的流量控制实现算法有: 计数器限流、漏桶限流算法和令牌桶限流算法等。
计数器算法是在一定的时间间隔里,记录请求次数,当请求次数超过该时间限制时,就把计数器清零,然后重新计算。当请求次数超过间隔内的最大次数时,拒绝访问。
计数器算法的特点是: 实现比较简单,但存在“突刺现象”
突刺现象举例:请求限制为1秒内100次,如果0.2秒的时候100次就已经访问结束了,那后面还有的0.8秒就会等待被拒绝
漏桶算法的实现思路是,有一个固定容量的漏桶,水流(请求)可以按照任意速率先进入到漏桶里,但漏桶总是以固定的速率匀速流出,当流入量过大的时候 (超过桶的容量),则多余水流 (请求) 直接溢出。
漏桶算法提供了一种机制,通过它可以让突发流量被整形,以便为系统提供稳定的请求,比如 Sentinel 中流量整形 (匀速排队功能)就是此算法实现的
此篇博客? 在RequestRateLimiter部分简要概述说明
漏桶:允许请求的数量(水滴)流入是任意,请求数量流出是固定
令牌桶:允许请求的数量(令牌数量)流入是固定,请求数量流出是任意(在桶现有令牌数的范围内)
Sentinel 流量控制有以下几个角度
①资源的调用关系,例如资源的调用链路,资源和资源之间的关系
②运行指标,例如 QPS (Queries Per Second,每秒查询数) 、线程池、系统负载等。
③控制的效果,例如直接限流、冷启动、排队等。
Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。
注:这里使用的是控制台进行限流设置(是临时的,需要进行一次访问之后才能进行查看)
直接:就是单一的限流我自己,也就是本路径
关联:就是我在某种情况下满足了阈值,跟我关联路径进行限流(关联资源)
链路:微服务有很多的链路构成,如果我们作为中间的一条链路,我们满足限流条件时,某条链路从入口处进行限流(对应入口资源)
快速失败: 该方式是默认的流量控制方式,比如 QPS 超过任意规则的闻值后,新的请求就会被立即拒绝,拒绝方式为抛出 FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。
排队等待(也叫匀速通过):排队等待会严格控制请求通过的间隔时间,让请求稳定目匀速的通过,可以用来处理间隔性突发的高流量。例如抢票软件,在某一秒或者一分钟内有大量的请求到来,而接下来的一段时间里处于空闲状态,我们希望系统能够在接下来的空余时间里也能出去这些请求,而不是直接拒绝。在设置排队等待时,需要填写超时时间。
Warm Up: 此项叫做预热或者冷启动方式,此模式主要是防止流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮,通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到闻值上限,给冷系统一个预热的时间,避免冷系统被压垮。当使用 Warm Up 模式时,我们还需要指定启动时开放的 QPS 比例(DEFAULT_COLD_FACTOR,默认值为 3,代表 30%),以及系统预热所需时长 (warmUpPeriodSec,默认值是 10秒)
熔断是一种在分布式系统中处理故障和异常的策略。当某个服务或者接口发生故障或异常时,熔断机制会迅速将请求拒绝或者返回错误信息,而不是让请求一直等待或者重试,以保护系统免受故障的扩散影响。
当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。
熔断机制的好处:能够快速失败并返回错误信息,避免资源的浪费和系统连锁故障。当服务恢复正常时,熔断器会逐渐放心请求,验证服务的可用性,确保系统逐渐恢复正常运行
慢调用比例: 在统计时长内的所有请求,如果请求时间超过 xx 秒则为慢请求,且慢请求的超过一定的比例,且请求数大于最小请求数,将触发熔断操作,也就是一段时间内 (熔断时长参数设置)的请求会快速失败。
异常比例: 在统计时长内的所有请求,如果异常的比例大于闽值,且请求数大于最小请求数,将触发熔断,也就是一段时间内 (熔断时长参数设置)的请求会快速失败。
异常数:在统计时长内的所有请求,如果异常数大于闽值,且请求数大于最小请求数,将触发熔断,也就是一段时间内 (熔断时长参数设置)的请求会快速失败
对某个接口的参数做流量限制,配置如下:
不难看出,大部分规则已经稳定
参数索引:就是访问时url后面的一些参数,从0下标开始计算
单机阈值:设置次数,热点访问请求次数,每台机器上
统计窗口时长: 多长时间内满足条件
注:这还不是热点限流的真正设置,设置完成之后来到热点规则会有一个编辑热点规则,这算是高级的热点规则:
点开高级选项之后 (点击向下的箭头可以提示很多类型)
这里以url?uid={id}?举例
参数值:指的就是例子中的id
限流阈值:在统一时间内访问多少次,进行热点限流
总述一下 当设置参数值为1,限流阈值为10时,表示当id=1时,在统一时间内请求访问10次过后,第11次就会进行热点限流
热点规则使用搭配注解@SentinelResource:
(1)热点规则只在控制配置是不生效的,需要在代码中配合@SentinelResource一起使用才行
(2)热点规则配置的参数必须存在,如果不存在配置也是无效的
@SentinelResource(value = "getname",blockHandler = "myBlockHandler")
@RequestMapping("/getname")
public String getName(@RequestParam("uid") Integer uid) throws InterruptedException {
Thread.sleep(100);
return "Name :" + new Random().nextInt(100);
}
public String myBlockHandler(Integer uid ,BlockException blockException){
if(blockException instanceof FlowException){
return "注解-流量限流";
}else if(blockException instanceof DegradeException){
return "注解-熔断限流";
}
return "限流";
}
(1)SentinelResource注解有很多的参数,value是资源名,控制设置热点限流的资源名
(2)需要配置参数索引,所以方法必须由参数
(3)限流方法返回值和参数必必须和源方法一样,同时结尾还需要写BlockException 参数
针对某个接口的调用服务做黑、白名单限制,设置如下:
流控设置是一个Header字段值
白名单:请求头中带有这个值的时候就可以放行
黑名单:请求头中不带这个值的时候就可以放行
授权实现关键有两步:
(1)在被调用服务中,获取授权字段
(2)在请求发起方,例如网关中添加授权字段
被调用服务中获取请求来源
@Component
public class CustomerRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
//前端的请求参数 设置一个key-value 这里拿到
String origin=httpServletRequest.getHeader("origin");
if(StringUtils.isEmpty(origin)){ //这个位置看情况 分配主要区分的为 unstandard 是一个值,不是为空
origin="blank";
}
return origin;
}
}
?使用postman访问url后的效果,黑名单友友们自己去尝试一下
Load 自适应(仅对 Linux/Unix-like 机器生效): 系统的负载 load1 为启发指标,进行自适应系统保护load1 是每分钟平均负载指标,当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5.
RT: Response Time,系统响应时间,当单台机器上所有入口流量的平均 RT 达到闻值,即触发系统保护,单位是毫秒。
线程数: 当单台机器上所有入口流量的并发线程数达到闯值即触发系统保护
入口 QPS: 当单台机器上所有入口流量的 OPS 达到值即触发系统保护
CPU 使用率: 当系统 CPU 使用率超过值即触发系统保护 (取值范围 0.0-1.0)。?(windows上一般是不行的)
为了方便我们知道是什么情况产生的降级处理,我们可以继承BlockExceptionHandler接口自定义不同异常响应
@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
int code= HttpStatus.TOO_MANY_REQUESTS.value();
String msg="未知异常";
if(e instanceof FlowException){
msg="请求被限流了";
}else if(e instanceof DegradeException){
msg="请求被熔断了";
}else if(e instanceof ParamFlowException){
msg="请求触发了热点限流";
}else if(e instanceof AuthorityException){
code=HttpStatus.UNAUTHORIZED.value();
msg="暂无权限";
}
httpServletResponse.setContentType("application/json;charset=utf-8");
httpServletResponse.setStatus(code);
httpServletResponse.getWriter().println("{\"code\":"+code+",\"msg\":"+msg+"}");
}
}
Sentinel 使用 Dashboard 可以动态修改流控规则,但因为默认是存在内存中的,所以重启之后数据就丢失了,因此我们可以配合 Nacos、ZooKeeperRedis、 etcd、Consul、Spring Cloud Config、Kubernetes CRD 等存储数据源。
按照以下步骤:
(1)添加依赖
(2)配置数据源
(3)Nacos新建限流/熔断规则
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
后面将配置可以配置到Nacos配置中心时,可以添加上nacos-config依赖
spring:
application:
name: sentinel-dashboard-demo
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
sentinel:
transport:
dashboard: localhost:18086
datasource:
ds1:
nacos:
server-addr: localhost:8848
username: nacos
password: nacos
data-id: ${spring.application.name}-flow-rules
group-id: DEFAULT_GROUP
data-type: json
rule-type: flow
配置解析:
ds1:就是一个数据源名字,可以随便起名
nacos:表示nacos数据源
server-addr:Nacos服务器地址
username:Nacos用户名
password: Nacos 密码
data-id: Nacos 新建配置的 Data ID。
group-id: 分组 ID? ? ?这里使用${配置参数} 获取的就是服务名称,友友们可以写成固定的
data-type: 数据格式
rule-type: 规则类型,它有:
????????flow: 限流类型
????????degrade: 熔断限流类型
????????system:系统保护类型
上面data-id对应配置中心的Data ID,group-id对应Group
配置内容:
?参数解释:
字段 | 说明 | 默认值 |
resource | 资源名,资源名是限流规则的作用对象 | |
count | 限流阈值 | |
grade | 限流阈值类型,QPS(1) 或线程数(0)模式 | QPS 模式 |
limitApp | 流控针对的调用来源 | default,代表不区分调用来源 |
strategy | 调用关系限流策略:直接(0)、链路(2)、关联(1) | 根据资源本身(直接) |
controlBehavior | 流控效果:直接拒绝(0) / 排队等待 (2)/ 慢启动模式(1),不支持按调用关系限流 | 直接拒绝 |
Sentinel 配置多数据源,比如既配置 Nacos 的限流策略,还配置 Nacos 的熔断策略,它实现步骤和上一个小节类似,只有需要在项目中配置多个Nacos 数据源,并且在 Nacos 中新建一个熔断的配置,具体操作如下
spring:
application:
name: sentinel-dashboard-demo
cloud:
nacos:
discovery:
server-addr: localhost:8848
username: nacos
password: nacos
sentinel:
transport:
dashboard: localhost:18086
datasource:
ds1:
nacos:
server-addr: localhost:8848
username: nacos
password: nacos
data-id: ${spring.application.name}-flow-rules
group-id: DEFAULT_GROUP
data-type: json
rule-type: flow
ds2:
nacos:
server-addr: localhost:8848
username: nacos
password: nacos
data-id: ${spring.application.name}-sentinel-degrade
group-id: DEFAULT_GROUP
data-type: json
rule-type: degrade
配置信息去官网上都有提供
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,即规则的作用对象 | |
grade | 熔断策略,支持慢调用比例(0)/异常比例(1)/异常数(2)策略 | 慢调用比例 |
count | 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值 | |
timeWindow | 熔断时长,单位为 s | |
minRequestAmount | 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) | 5 |
statIntervalMs | 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) | 1000 ms |
slowRatioThreshold | 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入) |
注:这里的同步都是单向同步的,nacos设定规则会在启动时同步给sentinel控制台,但是控制台修改是不能返回给nacos的,需要特殊处理才能实现双向通信(针对个人版sentinel)
其实图很很明显了,这里只是告诉友友们一个注意点
监控统计也是有顺序的,先检测热点规则,最后才是流量控制和熔断