Sentinel简单使用(1)

使用场景

在微服务架构中,服务之间会进行大量的调用。为了防止某个服务被过多的请求压垮,导致整个系统崩溃,就需要对流量进行控制。同时,当某个服务出现故障时,为了防止故障扩散到整个系统,需要进行熔断操作。Sentinel提供了流量控制和熔断降级的功能,因此非常适合在这种场景下使用。

雪崩效应

在微服务系统架构中,服务间调用关系错综复杂,一个微服务往往依赖于多个其它微服务。一个服务的不可用导致整个系统的不可用的现象就被称之为雪崩效应。

解决方法

  1. 超时处理
    在设置两个或多个微服务之间相互访问的时候,我使用的是OpenFeign来实现的访问,OpenFeign中可以自定义配置,日志配置、超时配置、重试配置
  2. 隔离处理https://www.jindouyun.cn/document/industry/details/184685#_293
  3. 熔断处理https://www.jindouyun.cn/document/industry/details/184685#_293
  4. 流量控制
    本篇文章主要学习的是如何使用流量控制来处理请求过多导致微服务服务器崩溃

流量控制使用的是Sentinel组件来实现需求

Sentinel前言配置

1.下载
在官网下载Sentinel控制器https://github.com/alibaba/Sentinel/releases
下载完成后可以在下载目录中找到一个Jar包,那就是我们启动sentinel所需要的资源
2.启动
java -jar +目录下的jar包
如果需要更改默认端口,账号,密码,可以通过以下配置

配置项 默认值 说明
server.port 8080 服务端口
sentinel.dashboard.auth.username sentinel 默认用户名
sentinel.dashboard.auth.password sentinel 默认密码

注意需要在每一个配置项前面添加(-D)
例如:修改端口号java -Dserver.port=8090 -jar sentinel-dashboard-2.0.0-alpha-preview.jar
3.访问Sentinel页面
访问http://localhost:8080页面,就可以看到sentinel的控制台了:

如何在IDEA中整合Sentinel

1.导入依赖

<!--sentinel的依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId> 
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2.在IDEA的yaml或者yml文件中导入相关的配置

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080  # 配置sentinel控制台地址

3.访问任意一个控制层的接口,就可以触发sentinel的监控

使用Sentinel流量控制(当系统面临高并发请求时,防止系统过载....)

Sentinel是在上述四种处理方法中唯一一个提前预防来处理问题的

首先我们先了解流量控制中的相关概念
1.簇点链路
当请求进入微服务时,首先会访问DispatcherServlet,然后进入Controller、Service、Mapper,这样的一个调用链就叫做簇点链路
2.资源
簇点链路中每一个被监控的Controller接口就是一个资源-->流控、熔断等都是针对簇点链路中的资源来设置的

  • 流控: 流量控制
  • 降级:降级熔断
  • 热点:热点参数限流,是限流的一种
  • 授权:请求的权限控制

sentinel快速入门

1.创建一个控制层在,其中编写Controller

    @GetMapping("/findUserByUserId/{userId}")
    public User findUserByUserId(@PathVariable("userId") Long userId) {
        return userService.findUserByUserId(userId);
    
    }
  顺便补齐后续的Server和Mapper,还有根据用户Id查询用户信息的SQL语句
  记得配置前面的依赖和配置

2.在浏览器访问ConTroller资源路径后,就可以在sentinel控制中心看到对应的请求


我们可以点击后面的流控来进行操作

  • 单机阈值:每秒最大能接收的请求数量
    为了模拟并发请求这里我们需要使用一个工具(jmeter测试工具)

    这里设置好线程数和时间,然后启动,我们就能看到相对应的效果

    上述图片中线程数是我们需要发送的请求数量,时间是我们需要运行的时间,所以每秒发送的请求数量是10,但是我们设置的单机阈值是5,所以会出现前五个请求成功,后五个请求失败的效果
    注意:如果测试结果不是上述情况,那是因为sentinel在统计请求的时候,把一部分的请求统计到了下一秒中导致的。

sentinel中三种详细的模式使用及介绍

  1. 直接:统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式
  2. 关联:统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流
  3. 链路:统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流

直接模式

就是我们上面的快速入门案例

关联模式

统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流
配置方式:


1.基于上面的Controller我们需要再一次创建一个请求以便实现我们的功能

    @GetMapping("/UpdataUserById")
    public String UpdataUserById(){
        return "修改用户数据成功";
    }

2.重启服务,在浏览器发送对应的的请求,让其产生簇点链路


3.配置流控规则,当/api/user/updateUserById资源被访问的QPS超过5时,对/api/user/findUserByUserId/1请求限流。对哪个端点限流,就点击哪个端点后面的按钮。我们是对用户查询/api/user/findUserByUserId/1限流,因此点击它后面的按钮:

4.在Jmeter中进行测试

链路模式

只针对从指定链路访问到本资源的请求做统计,判断是否超过阈值,如果超过阈值对从该链路请求进行限流。
配置方法:
如果只希望统计从/api/user/query进入到users的请求,并进行限流操作,则可以这样配置:


2.案例实现

  • 在UserService中添加一个queryUsers方法,不用实现业务
  public void queryUsers(){
    System.err.println("查询用户");
}
  • 在上述Controller中,添加两个端点(请求方法),在这两个端点中分别调用UserService中的queryUsers方法
    @GetMapping(value = "/save")
    public String save() {
        userService.queryUsers();
        System.out.println("保存用户");
        return "订单保存成功" ;
    }

    @GetMapping(value = "/query")
    public String query() {
        userService.queryUsers();
        System.out.println("查询用户");
        return "查询用户成功" ;
    }
  • 通过@SentinelResource标记UserService中的queryUsers方法为一个sentinel监控的资源(默认情况下,sentinel只监控controller方法)
@SentinelResource("users")
public void queryUsers(){
    System.err.println("查询用户");
}
  • 更改application.yml文件中的sentinel配置
    链路模式中,是对不同来源的两个链路做监控。但是sentinel默认会给进入spring mvc的所有请求设置同一个root资源,会导致链路模式失效。因此需要关闭这种资源整合。
spring:
  cloud:
    sentinel:
      web-context-unify: false # 关闭context整合
  • 重启服务,访问/api/user/save和/api/user/query,可以查看到sentinel的簇点链路规则中,出现了新的资源
  • 添加流控规则,点击users资源后面的流控按钮,在弹出的表单中填写下面信息:

    只统计从/api/user/query进入/users的资源,QPS阈值为2,超出则被限流。
  • jmeter测试
    选择《流控模式-链路》

    可以看到这里200个线程,50秒内发完,QPS为4,超过了我们设定的阈值2。
    一个http请求是访问/api/user/save

    另一个是访问/api/user/query

    运行测试,察看结果树:
    访问/api/user/save,没有进行限流

    访问/api/user/query,进行限流了

流控效果

  1. 快速失败:达到阈值后,新的请求会被立即拒绝并抛出FlowException异常,是默认的处理方式
  2. warm up:预热模式,对超出阈值的请求同样是拒绝并抛出异常,但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值
  3. 排队等待:让所有的请求按照先后次序进入到一个队列中进行排队,当某一个请求最大的预期等待时间超过了所设定的超时时间时同样是拒绝并抛出异常

warm up

  • 阈值(QPS):是一个微服务一秒能够承受的最大的请求数
  • 冷启动:刚启动一个服务器的时候,一切资源尚未启动
  • 如果直接将QPS跑到最大,可能导致服务器宕机
    Warm Up 也叫做预热模式,个人理解是阈值是一个动态的,会从一个较小值逐渐增加到最大阈值。

WarmUp案例:

测试的是上述Controller的/api/user/findUserByUserId/1

  • 设置最大阈值10,预热时间5秒
  • 在测试工具中设置线程数200,时间20秒->每秒10个请求
    得出的结果是由最刚开始的三个成功请求,随着时间的推移阈值会变大,成功的请求也会变多,直到最大阈值10

排队等待
解释:假设我现在有最大阈值10,第一秒我处理了10个请求,但是我每秒接收的请求是15,那么多出来的5个请求就会存放在队列中等待,第二秒我会优先处理上一次在队列中的请求,那么这一次我的队列中就存在10个请求...依次类推
当某一个请求在队列中等待的时间超过了设置的超时时间,那么这个请求同样是拒绝并抛出异常

那么等待的时间如何计算呢?

假如最大阈值为5,就是一秒处理5个请求,1/5=0.2/s 每200ms处理一个请求,设置超时时间=2000ms,那么就是等待时间超过了2000ms的请求就会被拒绝
比如现在有12个请求
那么第六个请求的预期等待时间=200ms(6-1)=1000ms
第十二个的请求的预期等待时间=200ms
(12-1)=2200ms,那么第十二个请求就会被拒绝

排队等待案例:

1.给/api/user/findUserByUserId/{userId}这个资源设置限流,最大QPS为10,利用排队的流控效果,超时时长设置为5s
2.在测试工具中设置线程数300,时间为20,那么每秒发送的请求为15个,QPS=15超过了我们设置的10,
3.结果等待时间长的将会被拒绝


4.在sentinel的监控中实时监控的QPS曲线

热点参数限流

使用场景

双十一的情境下,某些特价商品访问量非常大,但是一些普通的商品访问量比较正常,那么我们可以根据,发送的请求中的参数来设置热点限流,热点指的是访问量多的商品

热点参数限流:
统计请求中参数相同的情况,判断是否超过了阈值,超过了阈值就限流

热点参数限流实现

1.需要在所属的Controller的请求方法上添加注解
@SentinelResource("hot") 括号内填写上面名字都行,但是要对应编辑热点规则的资源名
2.配置sentinel

  • 在热点规则中添加新的热点规则
这是当id=1的情况,不是热点代码每秒只能执行2个请求 这是当id=2的情况,是热点代码每秒只能执行5个请求 这是当id=3的情况,是热点代码每秒只能执行10个请求