Sentinel 介绍
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助您保障微服务的稳定性。
Sentinel 的历史
2012 年,Sentinel 诞生,主要功能为入口流量控制。
2013-2017 年,Sentinel 在阿里巴巴集团内部迅速发展,成为基础技术模块,覆盖了所有的核心场景。Sentinel 也因此积累了大量的流量归整场景以及生产实践。
2018 年,Sentinel 开源,并持续演进。
2019 年,Sentinel 朝着多语言扩展的方向不断探索,推出 C++ 原生版本,同时针对 Service Mesh 场景也推出了 Envoy 集群流量控制支持,以解决 Service Mesh 架构下多语言限流的问题。
2020 年,推出 Sentinel Go 版本,继续朝着云原生方向演进。
2021 年,Sentinel 正在朝着 2.0 云原生高可用决策中心组件进行演进;同时推出了 Sentinel Rust 原生版本。
Sentinel 基本概念
1. 资源
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。
只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
2. 规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
流量控制有以下几个角度:
资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
运行指标,例如 QPS、线程池、系统负载等;
控制的效果,例如直接限流、冷启动、排队等。
Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。
1.流控规则
首先我们看一下流控规则
我们打开sentinel面板:
启动我们的微服务(可用上一章分支代码)
可以看到相关的接口,下面我们进行设置点开流控
在此可以看到设置QPS为1,不断刷新,可以看到被限流了
同样的并发线程数也可以设置的。不太好演示就不演示了同样可以达到限流的效果。
点开高级选项
可以看到很多的设置例如直接、关联、链路。
流控效果有:快速失败,Warm Up、排队等待。
直接(默认):接口达到限流条件时,开启限流。
关联:当关联的资源达到限流条件时,开启限流 (适合做应用让步)。
链路:当从某个接口过来的资源达到限流条件时,开启限流。
直接流控模式
直接流控模式是最简单的模式,当指定的接口达到限流条件时开启限流。前面的两个案例都是默认直接流控。
关联流控模式
关联流控模式指的是,当指定接口关联的接口达到限流条件时,开启对指定接口开启限流。
链路流控模式
链路流控模式是指当前一个接口调用service中一个方法,另一个接口也调用service中的一个方法,当一个接口达到QPS时,进行限流,
到底啥意思呢?下面我们来实战一下。
首先我们在Servic中添加一个message方法。并且加上如下注解
@SentinelResource("messsage")//名称可以自定义
然后再yml配置中添加收敛
然后再设置中添加流控
然后不断刷新/order/message
就可以看到报错了。
这个就是具体链路流控的规则。
采坑预告,如果不是使用本系列版本,低版本可能出现配置不生效的问题,首先自己配置
@Configuration
public class FilterContextConfigSentinel {
/**
* @NOTE 在spring-cloud-alibaba v2.1.1.RELEASE及前,sentinel1.7.0及后,关闭URL PATH聚合需要通过该方式,spring-cloud-alibaba v2.1.1.RELEASE后,可以通过配置关闭:spring.cloud.sentinel.web-context-unify=false
* 手动注入Sentinel的过滤器,关闭Sentinel注入CommonFilter实例,修改配置文件中的 spring.cloud.sentinel.filter.enabled=false
* 入口资源聚合问题:https://github.com/alibaba/Sentinel/issues/1024 或 https://github.com/alibaba/Sentinel/issues/1213
* 入口资源聚合问题解决:https://github.com/alibaba/Sentinel/pull/1111
*/
@Bean
public FilterRegistrationBean sentinelFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new CommonFilter());
registration.addUrlPatterns("/*");
// 入口资源关闭聚合
registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
registration.setName("sentinelFilter");
registration.setOrder(1);
return registration;
}
}
然后再yml配置进行配置
这样所有的就显示了
配置流控效果
快速失败(默认): 直接失败,抛出异常,不做任何额外的处理,是最简单的效果
Warm Up:它从开始阈值到最大QPS阈值会有一个缓冲阶段,一开始的阈值是最大QPS阈值的1/3,然后慢慢增长,直到最大阈值,适用于将突然增大的流量转换为缓步增长的场景。
排队等待:让请求以均匀的速度通过,单机阈值为每秒通过数量,其余的排队等待; 它还会让设置一个超时时间,当请求超过超时间时间还未处理,则会被丢弃。
前面的例子都是对当前的请求服务进行流控规则的新增,而流控模式中的关联,可以使得其它的请求服务达到阈值,本服务进行流控。
2.熔断降级
什么是熔断降级
除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。这个问题和 Hystrix 里面描述的问题是一样的。
Sentinel 和 Hystrix 的原则是一致的: 当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。
熔断降级设计理念
在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。
Hystrix 通过线程池的方式,来对依赖(在我们的概念中对应资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本,还需要预先给各个资源做线程池大小的分配。
Sentinel 对这个问题采取了两种手段:
通过并发线程数进行限制
和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。
通过响应时间对资源进行降级
除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。
系统负载保护
Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。
针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。
下面我们开始测试,首先我们在界面设置RT为1,时间为5s
进行疯狂刷新后就可以看到限流了,然后等待5s就可以正常的访问了。
异常比例和异常数都是根据当前抛出异常的次数进行限流时间的,在此就不和大家演示了。
3.热点规则
热点规则其实就是将控制作用到参数级别上。
下面开始我们的测试,我们先新建一个带参数的。
(这里有一个彩蛋,有一个小错误,改正才能在sentinel中看到相关资源,大家仔细了哦~)
进行访问测试
在sentinel进行热点规则配置
多次刷新就可以看到限流了
同样我们疯狂刷新age这边是没有限流的
点开高级选项,我们可以对具体的参数进行限流
这样的意思就是通过15的1000QPS才会限流,例如14 3QPS就会限流
然后进行age不同进行刷新测试就可以了
4.授权规则
其实就是根据不同来源调用微服务的链路进行限流。
点开授权就是黑白名单选择。
白名单:授权才可以进行访问。
黑名单:在黑名单里面的都不可以访问。
流控应用就是我们的微服务调用。
下面我们开始实战:
首先我们开始创建这样一个类RequestOriginParserDefinition 实现 RequestOriginParser接口
集成相关的类
public class RequestOriginParserDefinition implements RequestOriginParser {
//定义请求区分来源
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
String serviceName = httpServletRequest.getParameter("serviceName");
if(StringUtils.isEmpty(serviceName)){
throw new RuntimeException("服务为空");
}
return serviceName;
}
}
然后白名单添加pc
访问接口携带pc,是没有问题的,我们要是携带其他参数就会提示问题了。
这个就是授权规则了。
4.系统规则
系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体Load、RT、入口QPS、CPU使用率和线程数五个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体Load、RT、入口QPS、CPU使用率和线程数五个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量(进入应用的流量)生效。
·Load(仅对Linux/Unix-like机器生效)︰当系统load1超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的maxQps minRt计算得出。设定参考值一般是CPU cores 2.5。·RT:当单台机器上所有入口流星的平均RT达到阈值即触发系统保护,单位是毫秒。
·线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
·入口QPS:当单台机器上所有入口流量的QPS达到阈值即触发系统保护。
.CPU使用率:当单台机器上所有入口流量的CPU使用率达到阈值即触发系统保护。
4.自定义异常返回
在之前我们看到的异常返回都是通过本身的系统的返回,现在我们如何自定义呢?
那我们开始吧
首先新建处理异常类继承UrlBlockHandler
然后设置流控QPS的值。
然后我们疯狂刷新就可以看到自定义异常页面了。
设置熔断,和上面一样的操作。
然后就是@SentinelResource的相关介绍
设置流控
BlockException和Throwable,都是抛出的异常,后者的范围大一些,如果去掉BlockException
只会进入Throwable
为什么要区分两个呢?其实就是区分到底是sentinel还是系统代码的异常。
最后就是持久化了,默认保存在内存中的,微服务重新启动,sentinel规则就不存在了,所以我们需要持久化。
持久化以及持久化到nacos可以参考https://blog.csdn.net/weixin_42654295/article/details/117455723
到此,我们这一章的sentinel实战就完成了
后期会在这个项目上不断添加,喜欢的请点个start~
项目源码参考一下分支220212_xgc_useSentinel
Gitee:https://gitee.com/coderxgc/springcloud-alibaba
GitHub:https://github.com/coderxgc/springcloud-alibaba