首页 > 其他分享 >2流高手速成记(之八):基于Sentinel实现微服务体系下的限流与熔断

2流高手速成记(之八):基于Sentinel实现微服务体系下的限流与熔断

时间:2022-11-07 17:14:07浏览次数:66  
标签:之八 熔断 限流 规则 Sentinel import select

我们接上回

上一篇中,我们进行了简要的微服务实现,也体会到了SpringCloudAlibaba的强大和神奇之处

我们仅改动了两个注释,其他全篇代码不变,原来的独立服务就被我们分为了provider和consumer两个独立部分,二者各司其职,分工明确

篇尾我们留下了一个疑问,consumer对provider有依存关系,如果下游的provider出现异常,上游的consumer如何自处?

其实这种单一的上下游关系仅是微服务日常运转下各种复杂情境的一个缩影,真实的生产环境下各个微服务节点可能会形成更为复杂的依赖关系,那我们该如何解决这些问题?

本节中我们引入Sentinel框架:

什么是 Sentinel?

在基于 SpringCloud 构建的微服务体系中,服务间的调用链路会随着系统的演进变得越来越长,这无疑会增加了整个系统的不可靠因素。

在并发流量比较高的情况下,由于网络调用之间存在一定的超时时间,链路中的某个服务出现宕机都会大大增加整个调用链路的响应时间,而瞬间的流量洪峰则会导致这条链路上所有服务的可用线程资源被打满,从而造成整体服务的不可用,这也就是我们常说的 “雪崩效应”。

而在微服务系统设计的过程中,为了应对这样的糟糕情况,最常用的手段就是进行 ”流量控制“ 以及对网络服务的调用实现“熔断降级”。因此,Sentinel 就因运而生了。

Sentinel 是一款面向分布式服务架构的轻量级流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来保障服务的稳定性,核心思想是:根据对应资源配置的规则来为资源执行相应的流控/降级/系统保护策略,Sentinel 的主要特性如下图:

 

 

 以上内容来源于Sentinel官方文档,看到这一大堆不明所以的名词接释,新入坑的同学可能已经劝退了。。

接下来我们依然沿用前几篇的思想,先不要管这一堆的理论,先来看怎么用,实际运用过程中如何达到我们预期的效果,返回来再看这些名词,你自然会有更清晰的认知

Sentinel怎么用?

Sentinel的使用分为两部分 —— 代码和控制台

首先我们先下载Sentinel控制台:https://github.com/alibaba/Sentinel/tags,本节中我使用的是Sentinel1.8版本

下载编译好的jar包,而后执行命令行:

java -jar .\sentinel-dashboard.jar --server.port=9999

之后我们打开浏览器,输入地址:http://127.0.0.1:9999/

打开Sentinel控制台如图所示:

 

 

整个面板是空白的,什么都没有?!不用着急,我们继续往下看代码的部分

上一节我们提到了微服务环境下consumer工程存在的隐患问题,接下来我们就要消除这个隐患!

dubbo-nacos-consumer工程引入Sentinel依赖库

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

这一步肯定是必须的,没什么好解释的

添加Sentinel相关配置

 

 

在SpringCloudAlibaba体系下,我们以Nacos为配置中心,所以我们编辑Nacos中的相关配置即可,非常方便

我把代码文本也贴出来,便于大家自行复制

# sentinel看板配置
spring.cloud.sentinel.transport.dashboard = 127.0.0.1:9999
# 开启对sentinel看板的饥饿式加载。sentinel默认是懒加载机制,只有访问过一次的资源才会被监控,通过关闭懒加载,在项目启动时就连接sentinel控制台
spring.cloud.sentinel.eager = true

这两句的主要意图在于将Consumer工程关联到Sentinel控制台,便于后续通过控制台统一管控

改造原有的PersonController

我们先创建一个ViewObject

 

 

代码如下:

package com.example.dubbonacosconsumer.vo;

import com.example.dubbonacosapi.model.Person;

import java.util.List;

public class SelectRetVo {
    private List<Person> persons;
    private String error;

    public List<Person> getPersons() {
        return persons;
    }

    public void setPersons(List<Person> persons) {
        this.persons = persons;
    }

    public String getError() {
        return error;
    }

    public void setError(String error) {
        this.error = error;
    }
}

然后是PersonController的改造

package com.example.dubbonacosconsumer.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.dubbonacosapi.model.Person;
import com.example.dubbonacosapi.service.PersonService;
import com.example.dubbonacosconsumer.vo.SelectRetVo;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;

@RestController
@RequestMapping("/person")
public class PersonController {
    @DubboReference
    PersonService service;

    @PostMapping("/insert")
    public Integer insert(Person person) {
        return service.insert(person);
    }

    @PostMapping("/update")
    public Integer update(Person person) {
        return service.update(person);
    }

    @PostMapping("/delete")
    public Integer delete(int id) {
        return service.delete(id);
    }

    @GetMapping("/select")
    @SentinelResource(value = "person/select", blockHandler = "selectBlock")
    public SelectRetVo select() {
        SelectRetVo vo = new SelectRetVo();
        vo.setPersons(service.select());
        vo.setError("ok");
        return vo;
    }

    public SelectRetVo selectBlock(BlockException e) {
        SelectRetVo vo = new SelectRetVo();
        vo.setPersons(new ArrayList<Person>());
        vo.setError(“当前访问人数过多,请稍后...”);
        return vo;
    }
}

我们将原有的select方法的返回值从原来的List<Person>升级为SelectPersonVo,后者在前者原有基础上扩展了一个error字段,用于返回异常信息

接着是本节的关键:select方法新增@SentinelResource注解,我们前边讲过:Sentinel根据对应资源配置的规则来为资源执行相应的流控/降级/系统保护策略

因此这个注解的作用是——用于标明这是一个Sentinel系统中的资源

value代表这个资源的名称是person/select,这个名字可以随自己的习惯自定义

blockHandler指定了一个方法,这个方法在Sentinel系统触发某种规则的时候会被执行,关于“某种规则”我们稍后会讲

这里指定的selectBlock方法,在定义时是有硬性要求的:

1. 保留select方法一样的参数,外加一个BlockException参数

2. 返回值必须和select方法相同 —— 所以明白为什么要额外定义一个SelectRetVo了吧?

控制台的使用

我们像上一节一样,分别启动provider和consumer,然后刷新Sentinel控制台页面

 

 

看到这个界面的时候,你是否有种豁然开朗的感觉?

因为consumer中定义了Sentinel资源,所以当dubbo-nacos-consumer工程执行之后,控制台会有相关显示

而功能菜单中有N多项的名称都是XX规则,这也就是前边我们定义的blockHandler对应的某种规则

我们在post中调用consumer中的select方法,此时实时监控页面显示如下内容:

 

 

这里的person/select自然就是我们定义的【资源】,控制台配套显示了其各项指标数据,很直观也很方便

下边还有一项/person/select(开头多个/),这个又是什么?这里先直接告诉大家答案——Sentinel默认会将所有Controller添加请求映射的方法视为资源

那我们额外添加一个@SentinelResource注解是否多此一举?答案是否,因为Controller生成的默认Sentinel资源是不带自定义规则触发方法的

因此@SentinelResource依然是有必要的,待本篇内容结束之后,大家可以自行验证这个说法

而从第二项【簇点链路】中,我们也能看到person/select和/person/select本身具备从属关系

 

 

流控规则

第三项【流控规则】对应了本节标题中提到的【限流】

 

 

这里涉及到三个概念:

阈值类型

QPS —— 服务器每秒接受的最大请求数

线程数 —— 服务器能容忍的最大线程占用数,一般用于保护服务器的业务线程池不被耗尽

流控模式

直接 —— 默认项,接口到达限流要求时,规则直接生效

关联 —— 当关联在资源到达阈值时,直接限流自己,一般应用于效率让步的诉求

链路 —— 记录链路流量,当入口资源到达阈值,则限流自己

流控效果

快速失败 —— 默认项,超出阈值后新请求直接拒绝

排队等待 —— 让请求匀速通过(漏桶算法),每个请求在一个允许的延迟时长范围

Warm up —— 冷启动模式,防止流量瞬间暴增直接将服务压垮,而是逐渐外放请求上限

我们先按图所示创建一个最简单的限流规则 —— QPS阈值为1,直接快速失败

而后我们启动两个post,同时向服务器端发送select请求,则结果对比如下:

 

 

 由于QPS指定的阈值为1,因此同时发起的第二个请求会因触发限流规则而执行blockHandler方法

而我们针对 阈值类型、流控模式、流控效果 这三个指标交叉组合,可以创造出适用于各种服务器场景之下的限流规则

再比如我们按如下设置限流规则

 

这种设置方式代表我们所能允许select方法同时请求的上限值为2000,但是这个数值是在5分钟(300秒)之间逐步放开的,比如我们用这种模式可以应对类似双11期间大力度优惠而带来的突发流量洪峰

通过【限流】可以很好的起到保护服务器的作用,在特殊时期针对流量进行削峰填谷,使得服务器处在一个长期稳定的环境

降级规则

第四项【降级规则】对应了本节标题中的【熔断】

 

 所谓“熔断”,其实最早这个概念来源于家庭电路中的保险丝,当家庭中的某件家用电器功率异常,或者某处电路出现短路,

为防止电流过大造成更大的损失,此刻保险丝即会【熔断】,造成我们日常所说的“掉闸”

熔断策略

慢调用比例 —— 慢调用其实就是响应超过预定时长,当这样的调用到达一定比例后,触发降级规则

异常比例 —— 方法调用出现异常数到达一定比例后,触发降级规则

异常数 —— 方法调用出现异常到达一定数目后,触发降级规则

我们按照图中所示创建一条降级规则,其含义为【任意1次并发请求(QPS)中有1次异常则触发熔断规则,时长为10秒】

这里的10秒时间是我们一个大概的预估值,一般理解为系统达到自愈效果需要大概10秒左右

之后我们直接关停下游的provider,则第一次请求会导致异常,而第二次请求则触发降级规则

 

若我们不设定降级规则,则大量的异常请求会堆积在consumer一侧,导致consumer最终崩溃

而熔断机制的设立,可以使得下游provider异常的情况下,上游的consumer依然做出正常的应答,

而10秒钟provider服务自愈之后,所有的异常影响将消失于无形 —— 这就是微服务方案下针对我们上一节所遗留的问题给出的答案

其他熔断策略同理,我们可以自行尝试

本节我们重点讲述了Sentinel系统中的限流熔断,而除此之外,Sentinel还有更多更丰富的规则设定,可以应对微服务体系中更加复杂多变的场景

这里我们推荐几篇文章,大家感兴趣可以自行阅读

sentinel 限流熔断神器详细介绍_张维鹏的博客-CSDN博客_sentinel熔断

Sentinel限流熔断最全教程_思月行云的博客-CSDN博客

本节内容到此为止,而微服务领域的探索却远不止于此

众多节点之间的复杂调用,不同微服务不同的认证方式,跨域问题等等一系列问题接踵而至,我们又当如何应对?

请期待下一节内容 —— 基于SpringCloudGateway的网关设计,谢谢~

 

 

e.getMessage()

标签:之八,熔断,限流,规则,Sentinel,import,select
From: https://www.cnblogs.com/itfantasy/p/16866609.html

相关文章

  • SpringCloud_Alibaba(熔断与限流)
    1、Sentinel官网:https://github.com/alibaba/Sentinel中文文档:https://github.com/alibaba/Sentinel/wiki/介绍下载地址:https://github.com/alibaba/Sentinel/releases......
  • 手撕四大限流算法
    在开发高并发系统时,有三把利器用来保护系统:缓存、降级和限流。那么何为限流呢?顾名思义,限流就是限制流量,就像你宽带包了1个G的流量,用完了就没了。通过限流,我们可以很好地控......
  • 限流 - 限流注解组件开发
    限流概述系统存在服务上限,流量超过服务上限会导致系统卡死、崩溃。限流:为了在高并发时系统稳定可用,牺牲或延迟部分请求流量以保证系统整体服务可用。限流算法固定窗......
  • Redis 的 Sentinel 系统
    介绍Redis的Sentinel系统技术是为了解决问题而生的,Redis的Sentinel系统实现了Redis主从服务器的自动切换。Sentinel是Redis的高可用性解决方案:由一个或多个......
  • 浅谈限流式保护器应用于防范电动自行车火灾的解决方案
    陈盼安科瑞电气股份有限公司上海嘉定201801【摘要】为了进一步研究电动自行车火灾事故发生机理,提升安全防范的针对性,文章分析了低压电气系统发生火灾的原理,解构了电动自行......
  • redis限流和滑动窗口限流
     一、redissetnx实现限流 比如我们需要在10秒内限定20个请求,那么我们在setnx的时候可以设置过期时间为当前时间戳+10s,使用setnx设置20个互不相同的key,当请求的s......
  • 42-42-Spring Cloud Alibaba之Sentinel设计原_ev
        热点数据处理:写日志一分钟批量提交       ......
  • redisson分布式限流[RRateLimiter]源码分析
    接下来在讲一讲平时用的比较多的限流模块--RRateLimiter1.简单使用publicstaticvoidmain(String[]args)throwsInterruptedException{RRateLimiterrateLimit......
  • 这样讲Redis哨兵机制Sentinel的工作原理,或许你真的能听懂~
    什么是哨兵机制?Sentinel是Redis官方提出的一个高可用解决方案。它由一个或多个sentinel实例构成sentinel系统。为什么要用哨兵机制?我们都知道Redis具备主从复制的功能,......
  • nginx限流+jmeter
    一般情况下,首页的并发量是比较大的,即使有了多级缓存,如果有大量恶意的请求,也会对系统造成影响。而限流就是保护措施之一。nginx提供两种限流的方式:一是控制速率二是控......