1.Sentinel简介
1.1背景分析
在我们日常生活中,经常会在淘宝、天猫、京东、拼多多等平台上参与商品的秒杀、抢购以及一些优惠活动,也会在节假日使用12306 手机APP抢火车票、高铁票,甚至有时候还要帮助同事、朋友为他们家小孩拉投票、刷票,这些场景都无一例外的会引起服务器流量的暴涨,导致网页无法显示、APP反应慢、功能无法正常运转,甚至会引起整个网站的崩溃。
1.2 Sentinel概述
Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决方案。它以流量为切入点, 从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。
Sentinel核心分为两个部分:
- 核心库(Java 客户端):能够运行于所有 Java 运行时环境,同时对Dubbo /Spring Cloud 等框架也有较好的支持。
- 控制台(Dashboard):基于 Spring Boot 开发,打包后可以直接运行。
1.3 安装Sentinel服务
1.打开sentinel下载网址
https://github.com/alibaba/Sentinel/releases
2.下载Jar包(可以存储到一个sentinel目录)建议8.0.0
3.在sentinel对应目录,打开命令行(cmd),启动运行sentinel
java -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar
4.访问Sentinal服务:访问网址localhost:8180
5.登陆sentinel,默认用户和密码都是sentinel,
2. Sentinel 限流入门
概述:在系统中的数据库连接池,线程池,nginx的瞬时并发,MQ消息等在使用时都会跟定一个限定的值,这本身就是一种限流的设计。限流的目的防止恶意请求流量、恶意攻击,或者防止流量超过系统峰值。
2.1 Sentinel集成
1.Sentinel 应用于服务消费方(Consumer),在消费方添加依赖如下:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2打开服务消费方配置文件application.yml,添加sentinel配置,代码如下:
spring:
cloud:
sentinel:
transport:
port: 8099 #跟sentinel控制台交流的端口,随意指定一个未使用的端口即可
dashboard: localhost:8180 # 指定sentinel控制台地址。
3.启动服务提供者,服务消费者,然后在浏览器访问消费者url
服务方代码:
@EnableFeignClients
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
@RestController
public class ConsumerController{
@Autowired
private RestTemplate loadBalanceRestTemplate;
//负载均衡客户端对象(基于此对象可以从nacos中获取服务列表,并且基于一定的算法)
//从列表中获取一个服务实例
@Autowired
public LoadBalancerClient loadBalancerClient;
@Value("${spring.application.name}")
private String appName;
@GetMapping("/consumer/doRestEcho3")
public String doRestEcho3(){
String serverId ="sca-provider";
String url =String.format("http://%s/provider/echo/%s",serverId,appName);
return loadBalanceRestTemplate.getForObject(url,String.class);
}
}
}
说明: @Autowired 注解描述属性时,会告诉Spring框架,要优先按照属性类型进行对象的查找和注入,假如此类对象存在多个,此时还会按照属性名进行查找和比对,有相同的直接注入DI
没有的则出错 ,当然也可以在属性上添加@Qualifiler(”bean的名字“)指定要注入的对象
@Value("${spring.application.name}")注解将提供方服务进行调用。获取配置文件中的名字,从而调用了提供方中的内容。
提供方代码:
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class,args);
}
@RefreshScope
@RestController
public class ProviderController {
private final Logger log=
LoggerFactory.getLogger(ProviderApplication.class);
//配置server.port
@Value("${server.port:8080}")
private String server;
4 刷新sentinel 控制台,检测服务列表
2.2 Sentinel限流快速入门
我们设置一下指定接口的流控(流量控制),QPS(每秒请求次数)单机阈值为1,代表每秒请求不能超出1次,要不然就做限流处理,处理方式直接调用失败。
1.选择要限流的链路
2.设置限流策略
3.反复刷新访问消费端服务,检测是否有限流信息输出
2.3 Sentinel流控规则分析
阈值类型分析
-
QPS(Queries Per Second):当调用相关url对应的资源时,QPS达到单机阈值时,就会限流。
-
线程数:当调用相关url对应的资源时,线程数达到单机阈值时,就会限流。
当我们在服务中添加了Sentinel依赖以后,Sentinel会为我们的服务提供一个SpringMVC拦截器,这个拦截器会对请求进行拦截,然后基于请求url获取sentinel控制台中设置好的流控规则,然后采用一定的算法对请求url要访问的资源进行流量限制。
2.4 限流模式
1.直接模式
演示效果:
2.关联模式
例如设置了关联资源为/ur2时,假如关联资源/url2的qps阀值超过1时,就限流/url1接口(是不是感觉很霸道,关联资源达到阀值,是本资源接口被限流了)。这种关联模式有什么应用场景呢?我们举个例子,订单服务中会有2个重要的接口,一个是读取订单信息接口,一个是写入订单信息接口。在高并发业务场景中,两个接口都会占用资源,如果读取接口访问过大,就会影响写入接口的性能。业务中如果我们希望写入订单比较重要,要优先考虑写入订单接口。那就可以利用关联模式;在关联资源上面设置写入接口,资源名设置读取接口就行了;这样就起到了优先写入,一旦写入请求多,就限制读的请求。
3.链路模式
链路模式只记录指定链路入口的流量。也就是当多个服务对指定资源调用时,假如流量超出了指定阈值,则进行限流。被调用的方法用@SentinelResource进行注解,然后分别用不同业务方法对此业务进行调用,假如A业务设置了链路模式的限流,在B业务中是不受影响的。例如现在设计一个业务对象,代码如下(为了简单,可以直接写在启动类内部):
2.5 限流效果:
1 快速失败
2. WarmUp (预热)
WarmUp也叫预热,根据codeFactor(默认3)的值,(阀值/codeFactor)为初始阈值,经过预热时长,才到达设置的QPS的阈值,假如单机阈值为100,系统初始化的阈为 100/3 ,即阈值为33,然后过了10秒,阈值才恢复到100。这个预热的应用场景,如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。例如:
3 排队等待
从字面上面就能够猜到,匀速排队,让请求以均匀的速度通过,阈值类型必须设成QPS,否则无效。比如有时候系统在某一个时刻会出现大流量,之后流量就恢复稳定,可以采用这种排队模式,大流量来时可以让流量请求先排队,等恢复了在慢慢进行处理,例如:
2.6 小节面试分析
Sentinel是什么?(阿里推出一个流量控制平台,防卫兵)
类似Sentinel的产品你知道有什么?(hystrix-一代微服务产品)
你了解哪些限流算法?(计数器、令牌桶、漏斗算法,滑动窗口算法,…)
Sentinel 默认的限流算法是什么?(滑动窗口算法)
你了解sentinel中的阈值应用类型吗?(两种-QPS,线程数)
Sentinel 限流规则中默认有哪些限流模式?(直连,关联,链路)
Sentinel的限流效果有哪些?(快速失败,预热,排队)
Sentinel 为什么可以对我们的业务进行限流,原理是什么?
我们在访问web应用时,在web应用内部会有一个拦截器,这个拦截器会对请求的url进行拦截,拦截到请求以后,读取sentinel 控制台推送到web应用的流控规则,基于流控规则对流量进行限流操作。
3.Sentinel流控进阶——降级
3.1 应用场景
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。
Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。
3.2 准备工作
1.修改ConumserController 类中的doRestEcho01方法,假如没有创建即可,基于此方法演示慢调用过程下的限流,代码如下:
//AtomicLong 类支持线程安全的自增自减操作
private AtomicLong atomicLong=new AtomicLong(1);
@GetMapping("/consumer/doRestEcho1")
public String doRestEcho01() throws InterruptedException {
//consumerService.doGetResource();
//获取自增对象的值,然后再加1
long num=atomicLong.getAndIncrement();
if(num%2==0){//模拟50%的慢调用比例
Thread.sleep(200);
}
String url="http://localhost:8081/provider/echo/"+server;
//远程过程调用-RPC
return restTemplate.getForObject(url,String.class);//String.class调用服务响应数据类型
}
2.选择要降级的链路
3.对指定链路进行刷新,多次访问测试,假如出现了降级熔断
我们也可以进行断点调试,在DefaultBlockExceptionHandler中的handle方法内部加断点,分析异常类型,假如异常类型为DegradeException则为降级熔断。
3.3 Sentinel 异常处理
系统提供了默认的异常处理机制,假如默认处理机制不满足我们需求,我们可以自己进行定义。定义方式上可以直接或间接实现BlockExceptionHandler接口,并将对象交给spring管理。
代码编辑:
@Component
public class ServiceBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,BlockException e) throws Exception {
//response.setStatus(601);
//设置响应数据的编码
response.setCharacterEncoding("utf-8");
//告诉客户端要响应的数据类型以及客户端以什么编码呈现数据
response.setContentType("text/html;charset=utf-8");
PrintWriter pw=response.getWriter();
Map<String,Object> map=new HashMap<>();
if(e instanceof DegradeException){//降级、熔断
map.put("status",601);
map.put("message", "服务被熔断了!");
}else if(e instanceof FlowException){
map.put("status",602);
map.put("message", "服务被限流了!");
}else{
map.put("status",603);
map.put("message", "Blocked by Sentinel (flow limiting)");
}
//将map对象转换为json格式字符串
String jsonStr=new ObjectMapper().writeValueAsString(map);
pw.println(jsonStr);
pw.flush();
}
}
3.4 面试分析
Sentinel 降级熔断策略有哪些?(慢调用,异常比例,异常数)
Sentinel 熔断处理逻辑中的有哪些状态?(Open,HalfOpen,Closed)
Sentinel 对服务调用进行熔断以后处于什么状态?(熔断打开状态-Open)
Sentinel 设置的熔断时长到期以后,Sentinel的熔断会处于什么状态?(探测-HalfOpen,假如再次访问时依旧响应时间比较长或依旧有异常,则继续熔断)
Sentinel 中的熔断逻辑恢复正常调用以后,会出现什么状态?(熔断关闭-closed)
4 .Sentinel热点规则分析(重点)
4.1 应用场景
生活中经常会有许多热门事件,比如最近郑爽偷税就上了热搜,网络的访问量也大幅度增加,形成一个访问热点,何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top N 数据,并对其访问进行限制。比如:
商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制。
用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制。
热点参数限流会统计传入参数中的热点数据,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。其中,Sentinel会利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。
4.2 快熟入门
1.定义热点业务代码
@GetMapping("/consumer/findById")
@SentinelResource("res")
public String doFindById(@RequestParam Integer id){
return "select by "+id;
}
2.服务启动后,选择要限流的热点链路
3. 设置要限流的热点,如图所示:
4.多次访问热点参数方法,前端会出现如下界面
其中,热点参数其实说白了就是特殊的流控,流控设置是针对整个请求的;但是热点参数他可以设置到具体哪个参数,甚至参数针对的值,这样更灵活的进行流控管理。
4.3 小节面试分析
如何理解热点数据?(访问频度比较高的数据,某些商品、谋篇文章、某个视频)
热点数据的限流规则是怎样的?(主要是针对参数进行限流设计)
热点数据中的特殊参数如何理解?(热点限流中的某个参数值的阈值设计)
对于热点数据的访问出现限流以后底层异常是什么?(ParamFlowException)
5. Sentinel系统规则分析(了解)
1.概述
系统在生产环境运行过程中,我们经常需要监控服务器的状态,看服务器CPU、内存、IO等的使用率;主要目的就是保证服务器正常的运行,不能被某些应用搞崩溃了;而且在保证稳定的前提下,保持系统的最大吞吐量。
长期以来,系统自适应保护的思路是根据硬指标,即系统的负载 (load1) 来做系统过载保护。当系统负载高于某个阈值,就禁止或者减少流量的进入;当 load 开始好转,则恢复流量的进入。
2.快速入门
Sentinel的系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 Load、RT、入口 QPS 、线程数和CPU使用率五个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。如图所示:
监控维度说明:
- Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5。
- CPU使用率:当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0)。
- RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
- 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
- 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
- 系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务。
3.小节面试分析
如何理解sentinel中的系统规则?(是对所有链路的控制规则,是一种系统保护策略)
Sentinel的常用系统规则有哪些?(RT,QPS,CPU,线程,Load-linux,unix)
Sentinel系统保护规则被触发以后底层会抛出什么异常?(SystemBlockException)
6 .Sentinel 授权规则分析(重点)
6.1 概述
很多时候,我们需要根据调用方来限制资源是否通过,这时候可以使用 Sentinel 的黑白名单控制的功能。黑白名单根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。例如微信中的黑名单。
6.2 快速入门
sentinel可以基于黑白名单方式进行授权规则设计,如图所示:
黑白名单规则(AuthorityRule)非常简单,主要有以下配置项:
- 资源名:即限流规则的作用对象
- 流控应用:对应的黑名单/白名单中设置的规则值,多个值用逗号隔开.
- 授权类型:白名单,黑名单(不允许访问).
入门案例:
1.:定义RequestOriginParser接口的实现类,基于业务在接口方法中解析请求数据并返回.
@Component
public class DefaultRequestOriginParser implements RequestOriginParser {
//http://localhost:8090/consumer/doRestEcho1?origin=app1
//这个方法会在资源访问时,由底层进行调用,获取请求中数据,再与我们指定的授权规则进行比对
@Override
public String parseOrigin(HttpServletRequest request) {
return request.getParameter("origin");//参数名自己定义
}
}
2.定义流控规则
3.执行资源访问,检测授权规则应用,当我们配置的流控应用值为app1时,假如规则为黑名单,则基于
http://ip:port/path?origin=app1的请求不可以通过,会出现如下结果:
4:设计过程分析
6.3 小节面试分析
如何理解Sentinel中的授权规则?(对指定资源的访问给出的一种简易的授权策略)
Sentinel的授权规则是如何设计的?(白名单和黑名单)
如何理解Sentinel中的白名单?(允许访问的资源名单)
如何理解Sentinel中的黑名单?(不允许访问的资源名单)、
Sentinel如何识别白名单和黑名单?(在拦截器中通过调用RequestOriginParser对象的方法检测具体的规则)
授权规则中RequestOriginParser类的做用是什么?(对流控应用值进行解析,检查服务访问时传入的值是否与RequestOriginParser的parseOrigin方法返回值是否相同。)