手把手学习Sentinel

Sentinel

1.介绍

Sentinel官方中文文档:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D

随着分布式系统的日益普及,服务之间的可靠性比以往任何时候都更加重要。Sentinel以“流量”为切入点,致力于流量控制、流量整形、电路中断和系统自适应保护等多个领域,确保微服务的可靠性和弹性。

image-20211104092720340

image-20211104093311917

Sentinel 分为两个部分:(和Hystrix类似)

  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

2.Sentinel中的两个概念

  1. 资源:在Sentinel中一切皆资源,比如一个接口、一段代码
  2. 规则:定义规则就是对指定资源的处理(熔断、流控…)

3.快速开始–Sentinel

首先需要下载它的Dashboard,有了控制台才能实现对资源的控制

gitee地址:https://github.com/alibaba/Sentinel/tags

选择一个版本,点进去:(我是1.8.2)

image-20211104102149611

往下滑:点击即可下载(20M,很快下完)

扫描二维码关注公众号,回复: 13399613 查看本文章

image-20211104102118830

这是Sentinel控制台的详细介绍(官网)

https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0#sentinel-%E6%8E%A7%E5%88%B6%E5%8F%B0

上传服务器运行:

因为这个dashboard也是springboot写的,默认端口8080,所以如果你需要改,在运行jar包时加上参数即可:

java -Dserver.port=8989 -jar sentinel-dashboard-1.8.2.jar

image-20211104104142512

可以看到运行起来了,但请记得防火墙开放端口,阿里服务器就去阿里云开放,虚拟机就直接防火墙关了

访问:ip+端口

image-20211104104806479

默认用户名密码都是:sentinel

如果想改请参考前面的控制台文档(官方地址),也是通过运行时指定参数修改

登陆成功:

image-20211104105125058

使用Nacos作为注册中心(其它的也可以)

image-20211104111329859

创建测试的微服务

一个叫User、Order,其实一个就行了。

下面我们就以USER服务实例:

1.引入依赖

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

<!--与控制台通信-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

以上是sentinel需要使用到的依赖,注册中心的依赖根据你自己的选择

当然你完全可以不使用注册中心,使用是为了方便查看微服务是否正常

2.写一个接口

@GetMapping("/test")
    public String test(){
        return "hello";
    }

3.增加以下配置

#开启sentinel
spring.cloud.sentinel.enabled=true

#dashboard的web地址
spring.cloud.sentinel.transport.dashboard=39.108.83.106:8989

#dashbord的通信端口
spring.cloud.sentinel.transport.port=8719

4.调用/test接口

image-20211104131510219

5.查看sentinel控制台

必须要先掉调用这个服务的资源(这里是接口,就必须先调用一次,sentinel控制台才能监听到),才会显示

image-20211104131552153

此时,idea控制台也会打印:

image-20211104131748784

4.规则

1.流控规则—>流量控制(flow control)

其原理是监控应用流量的 QPS (每秒请求数)或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6

通过流控规则,我们可以设置QPS或者并发线程数的阈值,超过阈值就不执行后面的了

比如我将QPS设置为2,即每秒最多接收2个请求,多的say byby

image-20211104161811761

添加

image-20211104163438322

ok,为了方便测试,我们需要新增几个接口,便于演示:

@RestController
public class UserController {
    @Value("${name}")
    private String name;
    
    @Autowired
    private OrderClient orderClient;
    
    @GetMapping("/test")
    public String test(){
        return "hello";
    }


    @GetMapping("/test2")
    public String test2(Integer n){
        if (n < 10) {
            throw new RuntimeException("搁这儿搁这呢?");
        }
        return "hello";
    }
    
    @GetMapping("/test3")
    public String getOrder(){
        //调用Order服务...
        String order = orderClient.getOrder("123456");
        System.out.println(order);
        return order;
    }
}

此外,如果你也是用服务器跑的nacos、sentinel(虚拟机或者win请忽略),那么也请将springboot的测试项目打包运行到和sentinel同一台的服务器上,因为你在本地运行,虽然可以在sentinel中看到你,但是却无法添加各种规则,公网的sentinel是无法访问你本地的。至于为什么要将springboot测试运行在和sentinel同一台服务器,是因为sentinel监听服务是根据服务的内网ip,比如我这个USER:

image-20211105100818537

这个我暂时还没去研究为啥,nacos的注册地址对于运行在服务器上的服务也是内网ip。

所以要使用sentinel的规则就必须和它在同一台服务器(内网ip相同),我这里USER、ORDER都和sentinel运行在同一台服务器。

ok。下面开始做细致介绍:

针对来源:

  1. default,所有调用了该资源的调用方都受到流量控制
  2. {some_origin_name},指定哪个调用方受到流控
  3. other,表示除了some_origin_name以外的调用者都会收到流量控制;

other必须和 {some_origin_name} 搭配使用,意为对同一资源添加了{some_origin_name},然后又加了一个other规则,它两很像if else的关系(无需关心它们的顺序,因为它们有优先级的,如下)

同一个资源名可以配置多条规则,规则的生效顺序为:{some_origin_name} > other > default

流控模式:(超过阈值才触发)

  1. 直接:谁调用我就流控谁,举例如下:

    image-20211105101417226

    在浏览器上快速刷新(1s超过一个即可),就是下面的效果,即快速失败

    image-20211104213726739

  2. 关联:当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说,read_dbwrite_db 这两个资源分别代表数据库读写,我们可以给 read_db 设置限流规则来达到写优先的目的:设置 strategyRuleConstant.STRATEGY_RELATE 同时设置 refResourcewrite_db。这样当写库操作过于频繁时,读数据的请求会被限流。(官方的例子很容易理解了),举例如下:

    我们把USER的test、test2接口关联:

    image-20211105101622319

    image-20211105101741951

    要演示关联的话,我们需要用到压力测试工具jmeter(如果有需要的话可以评论私聊,我写一篇jmeter的基本使用,当然百度也不错),因为关联资源必须要在其一直处于阈值的情况才能看到另一个资源的效果:

    image-20211105102842289

    运行jmeter:

    可以看到/test的接口已经无法访问了:

    image-20211105102959510

    但是/test2的请求却是正常的:

    image-20211105103132403

    所以,我们需要解释一下这个关联资源

    image-20211105112816626

    不知道你理解到了吗,关联资源处所指定的资源就像是 犯了错(指达到阈值)的孩子,它因为某些原因而犯下了错,但却是另一个孩子(资源名处所指定的资源)接受了惩罚。这样或许更利于理解。

  3. 链路:NodeSelectorSlot 中记录了资源之间的调用链路,这些资源通过调用关系,相互之间构成一棵调用树。这棵树的根节点是一个名字为 machine-root 的虚拟节点,调用链的入口都是这个虚节点的子节点。

               machine-root
                 /       \
                /         \
          Entrance1     Entrance2
             /             \
            /               \
    

    DefaultNode(nodeA) DefaultNode(nodeA)

这里我猜测使用虚拟节点就是为了将某个资源的调用链组成一棵树

官方这个图是Entrance1和Entrance2都调用了nodeA这个资源,这个时候sentinel就提供了一种链路流控,你可以选择流控哪条链路,比如流控Entrance1(那么这条链路的调用就是失败的): 那么Entrance2的调用就不会受影响

image-20211104171609844

这个貌似无法演示…

流控效果:------只适用于QPS限流

  1. 快速失败:很好理解,直接拒绝
  2. Warm Up:当系统之前处于低水位(即没啥访问量,系统很闲),但是突然流量猛涨,如果瞬间把系统提到高水位,也可能瞬间把服务器冲垮,所以warm up就是让系统慢慢升温,直到到达设置的阈值
  3. 排队等待:字面意思很好理解,一个一个来嘛;但我们需要直到-----匀速排队(官网叫这个)(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法,重点—匀速!!!!!

image-20211104172837091

匀速排队的作用场景:

这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

ok,现在我们简单测试一下QPS每秒一个请求:

image-20211104213750444

2.熔断降级

熔断是为了避免微服务中的雪崩现象,sentinel监控到调用链路中出现异常,满足了熔断条件就会触发熔断,我们还可以自己设置熔断时间

https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7

熔断策略

Sentinel 提供以下几种熔断策略:

  • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

    我来理一理,首先这个慢比例调用在以前就叫响应时间,我看的视频是2020年的,现在就已经变了,相当于加强版:

    慢比例调用触发熔断的要求:①有慢请求(响应时间大于RT的请求)②一个统计周期(即下图中的一个统计时长)内请求数达到最小请求数要求③在一个统计时长中,慢请求所占的比例达到要求,举个列子:

    image-20211105174304889

    ps:这里不知道是不是bug,我设置的比例阈值保存后查看就会变成1。

    这个熔断规则的意思是:对于接口/test,2秒内请求数量达到5个,并且这2秒内的请求有超过一半的比例响应时间大于0.1毫秒,熔断器触发,断路器打开10秒;10秒过后,放行一个请求,如果这个请求的响应时间还是大于0.1毫秒,再熔断10秒,如果小于0.1毫秒,断路器关闭,熔断结束

    然后还是使用jmeter:

    image-20211105174643562

    看结果:

    image-20211105175016484

    我们可以看到,前5个请求是成功的,但是此时一个统计周期结束,满足熔断条件,熔断触发,后续请求就失败了。浏览器访问就是上面的这个效果。

    熔断时间到了之后,断路器处于半开状态(half  open),会放一个请求过去,如果这个请求响应时间超过我们设置的响应时间(RT),则再熔断一次,如此循环下去,直到响应时间小于设定值,断路器关闭

  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

    这个比较好理解,就是设置一个请求出现异常的比例,一个统计周期内请求数目达到最小请求数目要求,并且异常请求比例超过这个比例,断路器就打开,举例:

    image-20211105211220834

    这个熔断规则的意思:对于接口/test,1秒内请求数量达到5个,并且这1秒内的请求异常比例超过0.5(来10个超过5个出现异常),触发熔断,断路器打开10秒。10秒过后,放行一个请求,如果这个请求没有出现异常,断路器关闭,熔断结束,否则,继续熔断10秒,如此往复。。。

    因为要使接口异常,所以使用/test2,其代码如下

    @GetMapping("/test2")
        public String test2(Integer n){
            if (n < 10) {
                throw new RuntimeException("搁这儿搁这呢?");
            }
            return "hello";
        }
    

    我们需要传一个int参数n,n小于10抛异常,否则返回hello:我们直接用jmeter发小于10的:

    image-20211105213534360

    访问一个正常请求:

    这时候断路器打开,正常的请求也是访问不了的

  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

    这个更好理解,就看上面的介绍即可,这个应该不难理解,这里就不作演示了

image-20211105213646032

3.热点规则(热点参数限流)

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K(即前k名) 数据,并对其访问进行限制。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。

如何使用呢?

首先他和其它规则比较不一样,它的资源名,必须是资源别名,所以我还得写一个接口来演示:

@GetMapping("/test4")
@SentinelResource(value = "xp", blockHandler = "handler", fallback = "")
public String test(String x){
    return "hello";
}

image-20211105220130304

image-20211105220547453

	@GetMapping("/test4")
    @SentinelResource(value = "xp", blockHandler = "handler")
    public String test(String x){
        return "hello";
    }

    //这是对于/test4 资源被限流、熔断...后的处理
    //该方法是可以接收请求参数的,比如这里的x
    public String handler(String x, BlockException e){
        if (e instanceof FlowException){
            return "被限流";
        }
        if (e instanceof ParamFlowException){
            return "被热点参数限流";
        }
        if (e instanceof DegradeException){
            return "被降级";
        }
        return "服务器繁忙,请稍后再试";
    }

对资源被限流、降级…的自定义处理,可以让错误提示稍微友好一点,

image-20211105221102411

这是我们之前的提示。。。。。。

ok,我需要重新打包发布一下。。。。。。。。。。。。。。。。。。

正常访问没问题:

image-20211105222037616

添加热点参数规则:

image-20211105222752368

QPS阈值为1,浏览器刷新几下请求就能触发:

image-20211105222945255

我们就可以通过这样的方式给用户更友好的提示,你也可以试试熔断降级这样写

这里提一嘴:这种异常处理的方式和Hystriy(好像单词打错了。。不管了)很类似,你可以写一个类来处理异常、也可以写一个方法处理,你可以试试,

image-20211105223754215

当然,现在的热点参数限流规则还有些高级选项:

image-20211105223842483

这里就借用官网了:

热点参数规则(ParamFlowRule)类似于流量控制规则(FlowRule):

属性 说明 默认值
resource 资源名,必填
count 限流阈值,必填
grade 限流模式 QPS 模式
durationInSec 统计窗口时间长度(单位为秒),1.6.0 版本开始支持 1s
controlBehavior 流控效果(支持快速失败和匀速排队模式),1.6.0 版本开始支持 快速失败
maxQueueingTimeMs 最大排队等待时长(仅在匀速排队模式生效),1.6.0 版本开始支持 0ms
paramIdx 热点参数的索引,必填,对应 SphU.entry(xxx, args) 中的参数索引位置
paramFlowItemList 参数例外项,可以针对指定的参数值单独设置限流阈值,不受前面 count 阈值的限制。仅支持基本类型和字符串类型
clusterMode 是否是集群参数流控规则 false
clusterConfig 集群流控相关配置

image-20211105225055966

这是我的理解,如有错误还请纠正☎️

ok,这就是我要写的了。躺会

猜你喜欢

转载自blog.csdn.net/qq_42682745/article/details/121172500