精华内容
下载资源
问答
  • 分布式系统中的限流熔断
    2021-02-26 21:15:58

    在应对秒杀、大促、双 11、618 等高性能压力的场景时,限流已经成为了标配技术解决方案,为保证系统的平稳运行起到了关键性的作用。不管应用场景是哪种,限流无非就是针对超过预期的流量,通过预先设定的限流规则选择性的对某些请求进行限流“熔断”。

    1. 限流

    1.1 单机限流

    a>>限制并发量

    importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.Semaphore;public classSemaphoreTest {private static final int THREAD_COUNT = 30;private static ExecutorService threadPool =Executors

    .newFixedThreadPool(THREAD_COUNT);private static Semaphore s = new Semaphore(10);public static voidmain(String[] args) {for (int i = 0; i < THREAD_COUNT; i++) {

    threadPool.execute(newRunnable() {

    @Overridepublic voidrun() {try{

    s.acquire();

    System.out.println(Thread.currentThread().getName());

    Thread.sleep(5000);

    System.out.println("--------------");

    s.release();

    }catch(InterruptedException e) {

    }

    }

    });

    }

    threadPool.shutdown();

    }

    }

    b>>计数器,以CountDownLatch为例

    importjava.util.concurrent.CountDownLatch;public classCountDownLatchTest2 {public static voidmain(String[] args) {//创建计数器,初始化为2

    final CountDownLatch latch = new CountDownLatch(2);new Thread(() ->{try{

    System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");

    Thread.sleep(3000);

    System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");

    latch.countDown();//减一

    } catch(InterruptedException e) {

    e.printStackTrace();

    }

    }).start();new Thread(() ->{try{

    System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");

    Thread.sleep(3000);

    System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");

    latch.countDown();

    }catch(InterruptedException e) {

    e.printStackTrace();

    }

    }).start();try{

    System.out.println("等待2个子线程执行完毕...");//阻塞

    latch.await();

    System.out.println("2个子线程已经执行完毕");

    System.out.println("继续执行主线程");

    }catch(InterruptedException e) {

    e.printStackTrace();

    }

    }

    }

    c>>guava RateLimiter

    public voidtest()

    {/*** 创建一个限流器,设置每秒放置的令牌数:2个。速率是每秒可以2个的消息。

    * 返回的RateLimiter对象可以保证1秒内不会给超过2个令牌,并且是固定速率的放置。达到平滑输出的效果*/RateLimiter r= RateLimiter.create(2);while (true)

    {/*** acquire()获取一个令牌,并且返回这个获取这个令牌所需要的时间。如果桶里没有令牌则等待,直到有令牌。

    * acquire(N)可以获取多个令牌。*/System.out.println(r.acquire());

    }

    }

    1.2 分布式限流

    a>> nginx

    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;server {

    location / {

    limit_req zone=mylimit;}

    }

    b>>api-gateway+redis限流

    https://github.com/wangzheng0822/ratelimiter4j

    2. 熔断对比

    功能对比

    SentinelHystrixresilience4j

    隔离策略

    信号量隔离(并发线程数限流)

    线程池隔离/信号量隔离

    信号量隔离

    熔断降级策略

    基于响应时间、异常比率、异常数

    基于异常比率

    基于异常比率、响应时间

    实时统计实现

    滑动窗口(LeapArray)

    滑动窗口(基于 RxJava)

    Ring Bit Buffer

    动态规则配置

    支持多种数据源

    支持多种数据源

    有限支持

    扩展性

    多个扩展点

    插件的形式

    接口的形式

    基于注解的支持

    支持

    支持

    支持

    限流

    基于 QPS,支持基于调用关系的限流

    有限的支持

    Rate Limiter

    流量整形

    支持预热模式、匀速器模式、预热排队模式

    不支持

    简单的 Rate Limiter 模式

    系统自适应保护

    支持

    不支持

    不支持

    控制台

    提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等

    简单的监控查看

    不提供控制台,可对接其它监控系统

    参考文献:

    【1】https://mp.weixin.qq.com/s?__biz=MjM5MDE0Mjc4MA==&mid=2651008444&idx=1&sn=a579c3ceb143ea30930bd4c6d4a8d7e2&chksm=bdbed5ef8ac95cf93e71c5393f08e3b97a7e19e8232ce3872231f2cae74f7a19ab15501aeb44&scene=27#wechat_redirect

    【2】https://mp.weixin.qq.com/s?__biz=MzIwMzY1OTU1NQ==&mid=2247484306&idx=1&sn=b6c1b7b9d7c57bbb9f82ec451bcda867&chksm=96cd43dea1bacac8a24cde429146f69dba8bb15c5c9c3fe9adfe858d9a4349cc127fbfa84a8c&scene=27#wechat_redirect

    【3】https://github.com/alibaba/Sentinel/wiki/Guideline:-%E4%BB%8E-Hystrix-%E8%BF%81%E7%A7%BB%E5%88%B0-Sentinel

    更多相关内容
  • 我们可以在系统负载过高时,采用限流、降级和熔断,三种措施来保护系统,由此一些流量控制中间件诞生。例如Sentinel。 Sentinel概述 Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决...

    Sentinel简介

    背景分析

    在我们日常生活中,经常会在淘宝、天猫、京东、拼多多等平台上参与商品的秒杀、抢购以及一些优惠活动,也会在节假日使用12306 手机APP抢火车票、高铁票,甚至有时候还要帮助同事、朋友为他们家小孩拉投票、刷票,这些场景都无一例外的会引起服务器流量的暴涨,导致网页无法显示、APP反应慢、功能无法正常运转,甚至会引起整个网站的崩溃。
    我们如何在这些业务流量变化无常的情况下,保证各种业务安全运营,系统在任何情况下都不会崩溃呢?我们可以在系统负载过高时,采用限流、降级和熔断,三种措施来保护系统,由此一些流量控制中间件诞生。例如Sentinel。

    Sentinel概述

    Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决方案。它以流量为切入点, 从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。
    Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景, 例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。

    Sentinel核心分为两个部分:

    • 核心库(Java 客户端):能够运行于所有 Java 运行时环境,同时对Dubbo /Spring Cloud 等框架也有较好的支持。
    • 控制台(Dashboard):基于 Spring Boot 开发,打包后可以直接运行。

    安装Sentinel服务

    Sentinel 提供一个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能,其控制台安装步骤如下:
    第一步:打开sentinel下载网址

    https://github.com/alibaba/Sentinel/releases
    

    第二步:下载Jar包(可以存储到一个sentinel目录),如图所示:
    在这里插入图片描述

    第三步:在sentinel对应目录,打开命令行(cmd),启动运行sentinel

    java -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar
    

    检测启动过程,如图所示:
    在这里插入图片描述

    访问Sentinal服务

    第一步:假如Sentinal启动ok,通过浏览器进行访问测试,如图所示:
    在这里插入图片描述

    第二步:登陆sentinel,默认用户和密码都是sentinel,登陆成功以后的界面如图所示:
    在这里插入图片描述

    Sentinel限流入门

    概述

    我们系统中的数据库连接池,线程池,nginx的瞬时并发,MQ消息等在使用时都会跟定一个限定的值,这本身就是一种限流的设计。限流的目的防止恶意请求流量、恶意攻击,或者防止流量超过系统峰值。

    Sentinel集成

    第一步: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>

    第二步:打开服务消费方配置文件application.yml,添加sentinel配置,代码如下:

    spring:
      cloud:
        sentinel:
          transport:
             port: 8099 #跟sentinel控制台交流的端口,随意指定一个未使用的端口即可
             dashboard: localhost:8180 # 指定sentinel控制台地址。
    

    第三步:启动服务提供者,服务消费者,然后在浏览器访问消费者url,如图所示:
    在这里插入图片描述

    第四步:刷新sentinel 控制台,检测服务列表,如图所示:
    在这里插入图片描述
    Sentinel的控制台其实就是一个SpringBoot编写的程序,我们需要将我们的服务注册到控制台上,即在微服务中指定控制台的地址,并且还要在消费端开启一个与sentinel控制台传递数据端的端口,控制台可以通过此端口调用微服务中的监控程序来获取各种信息。

    Sentinel限流快速入门

    我们设置一下指定接口的流控(流量控制),QPS(每秒请求次数)单机阈值为1,代表每秒请求不能超出1次,要不然就做限流处理,处理方式直接调用失败。

    第一步:选择要限流的链路,如图所示:
    在这里插入图片描述

    第二步:设置限流策略,如图所示:

    在这里插入图片描述

    第三步:反复刷新访问消费端端服务,检测是否有限流信息输出,如图所示:

    在这里插入图片描述

    Sentinel流控规则分析

    阈值类型分析

    • QPS(Queries Per Second):当调用这个api的时,QPS达到单机阈值时,就会限流。

    • 线程数:当调用这个api的时,线程数达到单机阈值时,就会限流。

    设置限流模式

    Sentinel的流控模式代表的流控的方式,默认【直接】,还有关联,链路。

    直接模式:

    Sentinel默认的流控处理就是【直接->快速失败】。
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/72e7f7b3b6d14d2f9532ada149108fb0.png

    关联模式

    当关联的资源达到阈值,就限流自己。例如设置了关联资源为/ur2时,假如关联资源/url2的qps阀值超过1时,就限流/url1接口(是不是感觉很霸道,关联资源达到阀值,是本资源接口被限流了)。这种关联模式有什么应用场景呢?我们举个例子,订单服务中会有2个重要的接口,一个是读取订单信息接口,一个是写入订单信息接口。在高并发业务场景中,两个接口都会占用资源,如果读取接口访问过大,就会影响写入接口的性能。业务中如果我们希望写入订单比较重要,要优先考虑写入订单接口。那就可以利用关联模式;在关联资源上面设置写入接口,资源名设置读取接口就行了;这样就起到了优先写入,一旦写入请求多,就限制读的请求。例如:

    在这里插入图片描述
    在这里插入图片描述

    链路模式

    链路模式只记录指定链路入口的流量。也就是当多个服务对指定资源调用时,假如流量超出了指定阈值,则进行限流。被调用的方法用@SentinelResource进行注解,然后分别用不同业务方法对此业务进行调用,假如A业务设置了链路模式的限流,在B业务中是不受影响的。例如现在设计一个业务对象,代码如下(为了简单,可以直接写在启动类内部):

    @Service
    public class ConsumerService{
        @SentinelResource("doGetResource")
        public String doGetResource(){
            return "doGetResource";
        }
    }
    

    接下来我们在/consumer/doRestEcho1对应的方法中对ConsumerService中的doGetResource方法进行调用(应用consumerService对象之前,要先在doRestEcho01方法所在的类中进行consumerService值的注入)。例如:

       @GetMapping("/consumer/doRestEcho1")
        public String doRestEcho01() throws InterruptedException {
            consumerService.doGetResource();
            //Thread.sleep(200);
            String url="http://localhost:8081/provider/echo/"+server;
            //远程过程调用-RPC
            return restTemplate.getForObject(url,String.class);//String.class调用服务响应数据类型
        }
    

    其路由规则配置如下:

    在这里插入图片描述

    在这里插入图片描述

    说明,流控模式为链路模式时,假如是sentinel 1.7.2以后版本,Sentinel Web过滤器默认收敛所有URL的入口上下文(sentinel_spring_web_context),因此互连限流不生效,需要在application.yml添加如下语句来关闭URL PATH聚合(了解,可以自己尝试):

    sentinel:
         web-context-unify: false
    

    修改配置以后,重新sentinel,并设置链路流控规则,然后再频繁对链路/consumer/doRestEcho1进行访问,检测是否会出现500异常。
    在这里插入图片描述

    设计限流效果(了解)

    此模块做为课后了解内容,感兴趣自学即可.

    快速失败

    流量达到指定阀值,直接返回报异常。(类似路前方坍塌,后面设定路标,让后面的车辆返回)

    WarmUp (预热)

    WarmUp也叫预热,根据codeFactor(默认3)的值,(阀值/codeFactor)为初始阈值,经过预热时长,才到达设置的QPS的阈值,假如单机阈值为100,系统初始化的阈为 100/3 ,即阈值为33,然后过了10秒,阈值才恢复到100。这个预热的应用场景,如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。例如:
    在这里插入图片描述

    排队等待

    从字面上面就能够猜到,匀速排队,让请求以均匀的速度通过,阈值类型必须设成QPS,否则无效。比如有时候系统在某一个时刻会出现大流量,之后流量就恢复稳定,可以采用这种排队模式,大流量来时可以让流量请求先排队,等恢复了在慢慢进行处理,例如:

    在这里插入图片描述

    小节面试分析

    • Sentinel是什么?(阿里推出一个流量控制平台,防卫兵)
    • 类似Sentinel的产品你知道有什么?(hystrix-一代微服务产品)
    • 你了解哪些限流算法?(计数器、令牌桶、漏斗算法,滑动窗口算法,…)
    • Sentinel 默认的限流算法是什么?(滑动窗口算法)
    • 你了解sentinel中的阈值应用类型吗?(两种-QPS,线程数)
    • Sentinel 限流规则中默认有哪些限流模式?(直连,关联,链路)
    • Sentinel的限流效果有哪些?(快速失败,预热,排队)
    • Sentinel 为什么可以对我们的业务进行限流,原理是什么?
      我们在访问web应用时,在web应用内部会有一个拦截器,这个拦截器会对请求的url进行拦截,拦截到请求以后,读取sentinel 控制台推送到web应用的流控规则,基于流控规则对流量进行限流操作。

    Sentinel降级入门

    概述

    除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。
    Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。

    准备工作

    修改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调用服务响应数据类型
        }
    

    Sentinel降级入门

    第一步:服务启动后,选择要降级的链路,如图所示:
    在这里插入图片描述

    第二步:选择要降级的链路,如图所示:
    在这里插入图片描述

    这里表示熔断策略为慢调用比例,表示链路请求数超过3时,假如平均响应时间假如超过200毫秒的有50%,则对请求进行熔断,熔断时长为10秒钟,10秒以后恢复正常。

    第三步:对指定链路进行刷新,多次访问测试,假如出现了降级熔断,会出现如下结果:

    在这里插入图片描述

    我们也可以进行断点调试,在DefaultBlockExceptionHandler中的handle方法内部加断点,分析异常类型,假如异常类型为DegradeException则为降级熔断。

    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();
        }
    }
    

    小节面试分析

    • 何为降级熔断?(让外部应用停止对服务的访问,生活中跳闸,路障设置-此路不通)
    • 为什么要进行熔断呢?(平均响应速度越来越慢或经常出现异常,这样可能会导致调用链堆积,最终系统崩溃)
    • Sentinel中限流,降级的异常父类是谁?(BlockException)
    • Sentinel 出现降级熔断时,系统底层抛出的异常是谁?(DegradeException)
    • Sentinel中异常处理接口是谁?(BlockExceptionHandler)
    • Sentinel中异常处理接口下默认的实现类为? (DefaultBlockExceptionHandler)
    • 假如Sentinel中默认的异常处理规则不满足我们的需求怎么办?(自己定义)
    • 我们如何自己定义Sentinel中异常处理呢?(直接或间接实现BlockExceptionHandler )

    Sentinel降级策略分析(重点)

    Sentinel熔断降级支持慢调用比例、异常比例、异常数三种策略。

    慢调用比例

    慢调用指耗时大于阈值RT(Response Time)的请求称为慢调用,阈值RT由用户设置。其属性具体含义说明如下:
    在这里插入图片描述
    慢调用逻辑中的状态分析如下:

    • 熔断(OPEN):请求数大于最小请求数并且慢调用的比率大于比例阈值则发生熔断,熔断时长为用户自定义设置。
    • 探测(HALFOPEN):当熔断过了定义的熔断时长,状态由熔断(OPEN)变为探测(HALFOPEN)。
    • 关闭(CLOSED):如果接下来的一个请求小于最大RT,说明慢调用已经恢复,结束熔断,状态由探测(HALF_OPEN)变更为关闭(CLOSED),如果接下来的一个请求大于最大RT,说明慢调用未恢复,继续熔断,熔断时长保持一致
      注意:Sentinel默认统计的RT上限是4900ms,超出此阈值的都会算作4900ms,若需要变更此上限可以通过启动配置项-Dcsp.sentinel.statistic.max.rt=xxx来配置

    异常比例

    当资源的每秒请求数大于等于最小请求数,并且异常总数占通过量的比例超过比例阈值时,资源进入降级状态。其属性说明如下:
    在这里插入图片描述
    异常比例中的状态分析如下:

    • 熔断(OPEN):当请求数大于最小请求并且异常比例大于设置的阈值时触发熔断,熔断时长由用户设置。
    • 探测(HALFOPEN):当超过熔断时长时,由熔断(OPEN)转为探测(HALFOPEN)
    • 关闭(CLOSED):如果接下来的一个请求未发生错误,说明应用恢复,结束熔断,状态由探测(HALF_OPEN)变更为关闭(CLOSED)。如果接下来的一个请求继续发生错误,说明应用未恢复,继续熔断,熔断时长保持一致。

    异常数量

    当资源近1分钟的异常数目超过阈值(异常数)之后会进行服务降级。注意,由于统计时间窗口是分钟级别的,若熔断时长小于60s,则结束熔断状态后仍可能再次进入熔断状态。其属性说明如下:

    在这里插入图片描述

    基于异常数的状态分析如下:

    • 熔断(OPEN):当请求数大于最小请求并且异常数量大于设置的阈值时触发熔断,熔断时长由用户设置。
    • 探测(HALFOPEN):当超过熔断时长时,由熔断(OPEN)转为探测(HALFOPEN)
    • 关闭(CLOSED):如果接下来的一个请求未发生错误,说明应用恢复,结束熔断,状态由探测(HALF_OPEN)变更为关闭(CLOSED)如果接下来的一个请求继续发生错误,说明应用未恢复,继续熔断,熔断时长保持一致。

    小节面试分析

    • Sentinel 降级熔断策略有哪些?(慢调用,异常比例,异常数)
    • Sentinel 熔断处理逻辑中的有哪些状态?(Open,HalfOpen,Closed)
    • Sentinel 对服务调用进行熔断以后处于什么状态?(熔断打开状态-Open)
    • Sentinel 设置的熔断时长到期以后,Sentinel的熔断会处于什么状态?(探测-HalfOpen,假如再次访问时依旧响应时间比较长或依旧有异常,则继续熔断)
    • Sentinel 中的熔断逻辑恢复正常调用以后,会出现什么状态?(熔断关闭-closed)

    Sentinel热点规则分析(重点)

    概述

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

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

    热点参数限流会统计传入参数中的热点数据,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。其中,Sentinel会利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。
    4.8.2 快速入门
    第一步:定义热点业务代码,如图所示:

         //http://ip:port/consumer/doFindById?id=10
            @GetMapping("/consumer/findById")
            @SentinelResource("res")
            public String doFindById(@RequestParam("id") Integer id){
                return "resource id is "+id;
            }
    

    第二步:服务启动后,选择要限流的热点链路,如图所示:

    ![在这里插入图片描述](https://img-blog.csdnimg.cn/af4bbedf5b8b4b1dae26232577ac027d.png

    第三步:设置要限流的热点,如图所示:
    在这里插入图片描述

    热点规则的限流模式只有QPS模式(这才叫热点)。参数索引为@SentinelResource注解的方法参数下标,0代表第一个参数,1代表第二个参数。单机阈值以及统计窗口时长表示在此窗口时间超过阈值就限流。

    第四步:多次访问热点参数方法,前端会出现如下界面,如图所示:
    在这里插入图片描述

    然后,在后台出现如下异常表示限流成功。

    com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException: 2
    

    其中,热点参数其实说白了就是特殊的流控,流控设置是针对整个请求的;但是热点参数他可以设置到具体哪个参数,甚至参数针对的值,这样更灵活的进行流控管理。
    一般应用在某些特殊资源的特殊处理,如:某些商品流量大,其他商品流量很正常,就可以利用热点参数限流的方案。

    特定参数设计

    配置参数例外项,如图所示:
    在这里插入图片描述

    这里表示参数值为5时阈值为100,其它参数值阈值为1,例如当我们访问http://ip:port/consumer/doRestEcho1?id=5时的限流阈值为100。

    小节面试分析

    • 如何理解热点数据?(访问频度比较高的数据,某些商品、谋篇文章、某个视频)
    • 热点数据的限流规则是怎样的?(主要是针对参数进行限流设计)
    • 热点数据中的特殊参数如何理解?(热点限流中的某个参数值的阈值设计)
    • 对于热点数据的访问出现限流以后底层异常是什么?(ParamFlowException)

    Sentinel系统规则(了解)

    概述

    系统在生产环境运行过程中,我们经常需要监控服务器的状态,看服务器CPU、内存、IO等的使用率;主要目的就是保证服务器正常的运行,不能被某些应用搞崩溃了;而且在保证稳定的前提下,保持系统的最大吞吐量。
    长期以来,系统自适应保护的思路是根据硬指标,即系统的负载 (load1) 来做系统过载保护。当系统负载高于某个阈值,就禁止或者减少流量的进入;当 load 开始好转,则恢复流量的进入。

    快速入门

    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 服务。

    小节面试分析

    • 如何理解sentinel中的系统规则?(是对所有链路的控制规则,是一种系统保护策略)
    • Sentinel的常用系统规则有哪些?(RT,QPS,CPU,线程,Load-linux,unix)
    • Sentinel系统保护规则被触发以后底层会抛出什么异常?(SystemBlockException)

    Sentinel授权规则(重要)

    概述

    很多时候,我们需要根据调用方来限制资源是否通过,这时候可以使用 Sentinel 的黑白名单控制的功能。黑白名单根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。例如微信中的黑名单。

    快速入门

    sentinel可以基于黑白名单方式进行授权规则设计,如图所示:
    在这里插入图片描述
    黑白名单规则(AuthorityRule)非常简单,主要有以下配置项:

    • 资源名:即限流规则的作用对象
    • 流控应用:对应的黑名单/白名单中设置的规则值,多个值用逗号隔开.
    • 授权类型:白名单,黑名单(不允许访问).

    案例实现:

    定义请求解析器,用于对请求进行解析,并返回解析结果,sentinel底层 在拦截到用户请求以后,会对请求数据基于此对象进行解析,判定是否符合黑白名单规则

    第一步:定义RequestOriginParser接口的实现类,基于业务在接口方法中解析请求数据并返回.

    @Component
    public class DefaultRequestOriginParser implements RequestOriginParser {
        @Override
        public String parseOrigin(HttpServletRequest request) {
            String origin = request.getParameter("origin");
            return origin;
        }
    }
    

    第二步:定义流控规则,如图所示:
    在这里插入图片描述

    第三步:执行资源访问,检测授权规则应用,当我们配置的流控应用值为app1时,假如规则为黑名单,则基于
    http://ip:port/path?origin=app1的请求不可以通过,会出现如下结果:

    在这里插入图片描述

    第四步:设计过程分析,如图所示:

    在这里插入图片描述

    小节面试分析

    • 如何理解Sentinel中的授权规则?(对指定资源的访问给出的一种简易的授权策略)
    • Sentinel的授权规则是如何设计的?(白名单和黑名单)
    • 如何理解Sentinel中的白名单?(允许访问的资源名单)
    • 如何理解Sentinel中的黑名单?(不允许访问的资源名单)、
    • Sentinel如何识别白名单和黑名单?(在拦截器中通过调用RequestOriginParser对象的方法检测具体的规则)
    • 授权规则中RequestOriginParser类的做用是什么?(对流控应用值进行解析,检查服务访问时传入的值是否与RequestOriginParser的parseOrigin方法返回值是否相同。)

    总结(Summary)

    总之,Sentinel可为秒杀、抢购、抢票、拉票等高并发应用,提供API接口层面的流量限制,让突然暴涨而来的流量用户访问受到统一的管控,使用合理的流量放行规则使得用户都能正常得到服务。

    重难点分析

    • Sentinel诞生的背景?(计算机的数量是否有限,处理能力是否有限,并发比较大或突发流量比较大)
    • 服务中Sentinel环境的集成,初始化?(添加依赖-两个,sentinel配置)
    • Sentinel 的限流规则?(阈值类型-QPS&线程数,限流模式-直接,关联,链路)
    • Sentinel 的降级(熔断)策略?(慢调用,异常比例,异常数)
    • Sentinel 的热点规则设计(掌握)?
    • Sentinel 系统规则设计?(了解,全局规则定义,针对所有请求有效)
    • Sentinel 授权规则设计?(掌握,黑白名单)

    FAQ分析

    • 为什么要限流?
    • 你了解的那些限流框架?(sentinel)
    • 常用的限流算法有那些?(计数,令牌桶-电影票,漏桶-漏斗,滑动窗口)
    • Sentinel有哪些限流规则?(QPS,线程数)
    • Sentinel有哪些限流模式?(直接,关联-创建订单和查询订单,链路限流-北京六环外不限号,但是五环就限号)
    • Sentinel 的降级(熔断)策略有哪些?(慢调用-响应时长,异常比例-异常占比,异常数)
    • Sentinel 的热点规则中的热点数据?(热卖商品,微博大咖,新上映的电影)
    • 如何理解Sentinel 授权规则中的黑白名单?

    Bug分析

    • 依赖下载失败 (maven-本地库,网络,镜像仓库)
    • 单词错误(拼写错误)
    展开全文
  • fallbackMethod = "errMethod" ) 总结 限流熔断和服务降级是系统容错的重要设计模式,从一定意义上讲限流熔断也是一种服务降级的手段。 熔断和服务降级主要是针对非核心业务功能,而核心业务如果流程超过预估...

    在分布式系统中,如果某个服务节点发生故障或者网络发生异常,都有可能导致调用方被阻塞等待,如果超时时间设置很长,调用方资源很可能被耗尽。这又导致了调用方的上游系统发生资源耗尽的情况,最终导致系统雪崩。

    如下图:

    如果D服务发生了故障不能响应,B服务调用D时只能阻塞等待。假如B服务调用D服务设置超时时间是10秒,请求速率是每秒100个,那10秒内就会有1000个请求线程被阻塞等待,如果B的线程池大小设置1000,那B系统因为线程资源耗尽已经不能对外提供服务了。而这又影响了入口系统A的服务,最终导致系统全面崩溃。

    提高系统的整体容错能力是防止系统雪崩的有效手段。

    在Martin Fowler和James Lewis的文章 《Microservices: a definition of this new architectural term》[1]中,提出了微服务的9个特征,其中一个是容错设计。

    要防止系统发生雪崩,就必须要有容错设计。如果遇到突增流量,一般的做法是对非核心业务功能采用熔断和服务降级的措施来保护核心业务功能正常服务,而对于核心功能服务,则需要采用限流的措施。

    今天我们来聊一聊系统容错中的限流、熔断和服务降级。

    1 限流

    当系统的处理能力不能应对外部请求的突增流量时,为了不让系统崩溃,必须采取限流的措施。

    1.1 限流指标

    1.1.1 TPS

    系统吞吐量是衡量系统性能的关键指标,按照事务的完成数量来限流是最合理的。

    但是对实操性来说,按照事务来限流并不现实。在分布式系统中完成一笔事务需要多个系统的配合。比如我们在电商系统购物,需要订单、库存、账户、支付等多个服务配合完成,有的服务需要异步返回,这样完成一笔事务花费的时间可能会很长。如果按照TPS来进行限流,时间粒度可能会很大大,很难准确评估系统的响应性能。

    1.1.2 HPS

    每秒请求数,指每秒钟服务端收到客户端的请求数量。

    如果一个请求完成一笔事务,那TPS和HPS是等同的。但在分布式场景下,完成一笔事务可能需要多次请求,所以TPS和HPS指标不能等同看待。

    1.1.3 QPS

    服务端每秒能够响应的客户端查询请求数量。

    如果后台只有一台服务器,那HPS和QPS是等同的。但是在分布式场景下,每个请求需要多个服务器配合完成响应。

    目前主流的限流方法多采用HPS作为限流指标。

    1.2 限流方法

    1.2.1 流量计数器

    这是最简单直接的方法,比如限制每秒请求数量100,超过100的请求就拒绝掉。

    但是这个方法存在2个明显的问题:

    • 单位时间(比如1s)很难把控,如下图:这张图上,从下面时间看,HPS没有超过100,但是从上面看HPS超过100了。
    • 有一段时间流量超了,也不一定真的需要限流,如下图,系统HPS限制50,虽然前3s流量超了,但是如果都超时时间设置为5s,并不需要限流。

    1.2.2 滑动时间窗口

    滑动时间窗口算法是目前比较流行的限流算法,主要思想是把时间看做是一个向前滚动的窗口,如下图:

    开始的时候,我们把t1~t5看做一个时间窗口,每个窗口1s,如果我们定的限流目标是每秒50个请求,那t1~t5这个窗口的请求总和不能超过250个。

    这个窗口是滑动的,下一秒的窗口成了t2~t6,这时把t1时间片的统计抛弃,加入t6时间片进行统计。这段时间内的请求数量也不能超过250个。

    滑动时间窗口的优点是解决了流量计数器算法的缺陷,但是也有2个问题:

    • 流量超过就必须抛弃或者走降级逻辑
    • 对流量控制不够精细,不能限制集中在短时间内的流量,也不能削峰填谷

    1.2.3 漏桶算法

    漏桶算法的思想如下图:

    在客户端的请求发送到服务器之前,先用漏桶缓存起来,这个漏桶可以是一个长度固定的队列,这个队列中的请求均匀地发送到服务端。

    如果客户端的请求速率太快,漏桶的队列满了,就会被拒绝掉,或者走降级处理逻辑。这样服务端就不会受到突发流量的冲击。

    漏桶算法的优点是实现简单,可以使用消息队列来削峰填谷。

    但是也有3个问题需要考虑:

    • 漏桶的大小,如果太大,可能给服务端带来较大处理压力,太小可能会有大量请求被丢弃。
    • 漏桶给服务端的请求发送速率。
    • 使用缓存请求的方式,会使请求响应时间变长。

    漏桶大小和发送速率这2个值在项目上线初期都会根据测试结果选择一个值,但是随着架构的改进和集群的伸缩,这2个值也会随之发生改变。

    1.2.4 令牌桶算法

    令牌桶算法就跟病人去医院看病一样,找医生之前需要先挂号,而医院每天放的号是有限的。当天的号用完了,第二天又会放一批号。

    算法的基本思想就是周期性地执行下面的流程:

    客户端在发送请求时,都需要先从令牌桶中获取令牌,如果取到了,就可以把请求发送给服务端,取不到令牌,就只能被拒绝或者走服务降级的逻辑。如下图:

    令牌桶算法解决了漏桶算法的问题,而且实现并不复杂,使用信号量就可以实现。在实际限流场景中使用最多,比如google的guava中就实现了令牌桶算法限流,感兴趣可以研究一下。

    1.2.5 分布式限流

    如果在分布式系统场景下,上面介绍的4种限流算法是否还适用呢?

    以令牌桶算法为例,假如在电商系统中客户下了一笔订单,如下图:

    如果我们把令牌桶单独保存在一个地方(比如redis中)供整个分布式系统用,那客户端在调用组合服务,组合服务调用订单、库存和账户服务都需要跟令牌桶交互,交互次数明显增加了很多。

    有一种改进就是客户端调用组合服务之前首先获取四个令牌,调用组合服务时减去一个令牌并且传递给组合服务三个令牌,组合服务调用下面三个服务时依次消耗一个令牌。

    1.2.6 hystrix限流

    hystrix可以使用信号量和线程池来进行限流。

    1.2.6.1 信号量限流

    hystrix可以使用信号量进行限流,比如在提供服务的方法上加下面的注解。这样只能有20个并发线程来访问这个方法,超过的就被转到了errMethod这个降级方法。

    @HystrixCommand(
     commandProperties= {
       @HystrixProperty(name="execution.isolation.strategy", value="SEMAPHORE"),
       @HystrixProperty(name="execution.isolation.semaphore.maxConcurrentRequests", value="20")
     },
     fallbackMethod = "errMethod"
    )

    1.2.6.2 线程池限流

    hystrix也可以使用线程池进行限流,在提供服务的方法上加下面的注解,当线程数量

    @HystrixCommand(
        commandProperties = {
                @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD")
        },
        threadPoolKey = "createOrderThreadPool",
        threadPoolProperties = {
                @HystrixProperty(name = "coreSize", value = "20"),
       @HystrixProperty(name = "maxQueueSize", value = "100"),
                @HystrixProperty(name = "maximumSize", value = "30"),
                @HystrixProperty(name = "queueSizeRejectionThreshold", value = "120")
        },
        fallbackMethod = "errMethod"
    )

    这里要注意:在java的线程池中,如果线程数量超过coreSize,创建线程请求会优先进入队列,如果队列满了,就会继续创建线程直到线程数量达到maximumSize,之后走拒绝策略。但在hystrix配置的线程池中多了一个参数queueSizeRejectionThreshold,如果queueSizeRejectionThreshold < maxQueueSize,队列数量达到queueSizeRejectionThreshold就会走拒绝策略了,因此maximumSize失效了。如果queueSizeRejectionThreshold > maxQueueSize,队列数量达到maxQueueSize时,maximumSize是有效的,系统会继续创建线程直到数量达到maximumSize。Hytrix线程池设置坑[2]

    2 熔断

    相信大家对断路器并不陌生,它就相当于一个开关,打开后可以阻止流量通过。比如保险丝,当电流过大时,就会熔断,从而避免元器件损坏。

    服务熔断是指调用方访问服务时通过断路器做代理进行访问,断路器会持续观察服务返回的成功、失败的状态,当失败超过设置的阈值时断路器打开,请求就不能真正地访问到服务了。

    为了更好地理解,我画了下面的时序图:

    2.1 断路器的状态

    断路器有3种状态:

    • CLOSED:默认状态。断路器观察到请求失败比例没有达到阈值,断路器认为被代理服务状态良好。
    • OPEN:断路器观察到请求失败比例已经达到阈值,断路器认为被代理服务故障,打开开关,请求不再到达被代理的服务,而是快速失败。
    • HALF OPEN:断路器打开后,为了能自动恢复对被代理服务的访问,会切换到半开放状态,去尝试请求被代理服务以查看服务是否已经故障恢复。如果成功,会转成CLOSED状态,否则转到OPEN状态。

    断路器的状态切换图如下:

    2.2 需要考虑的问题

    使用断路器需要考虑一些问题:

    • 针对不同的异常,定义不同的熔断后处理逻辑。
    • 设置熔断的时长,超过这个时长后切换到HALF OPEN进行重试。
    • 记录请求失败日志,供监控使用。
    • 主动重试,比如对于connection timeout造成的熔断,可以用异步线程进行网络检测,比如telenet,检测到网络畅通时切换到HALF OPEN进行重试。
    • 补偿接口,断路器可以提供补偿接口让运维人员手工关闭。
    • 重试时,可以使用之前失败的请求进行重试,但一定要注意业务上是否允许这样做。

    2.3 使用场景

    • 服务故障或者升级时,让客户端快速失败
    • 失败处理逻辑容易定义
    • 响应耗时较长,客户端设置的read timeout会比较长,防止客户端大量重试请求导致的连接、线程资源不能释放

    3 服务降级

    前面讲了限流和熔断,相比来说,服务降级是站在系统全局的视角来考虑的。

    在服务发生熔断后,一般会让请求走事先配置的处理方法,这个处理方法就是一个降级逻辑。

    服务降级是对非核心、非关键的服务进行降级。

    3.1 使用场景

    • 服务处理异常,把异常信息直接反馈给客户端,不再走其他逻辑
    • 服务处理异常,把请求缓存下来,给客户端返回一个中间态,事后再重试缓存的请求
    • 监控系统检测到突增流量,为了避免非核心业务功能耗费系统资源,关闭这些非核心功能
    • 数据库请求压力大,可以考虑返回缓存中的数据
    • 对于耗时的写操作,可以改为异步写
    • 暂时关闭跑批任务,以节省系统资源

    3.2 使用hystrix降级

    3.2.1 异常降级

    hystrix降级时可以忽略某个异常,在方法上加上@HystrixCommand注解:

    下面的代码定义降级方法是errMethod,对ParamErrorException和BusinessTypeException这两个异常不做降级处理。

    @HystrixCommand(
     fallbackMethod = "errMethod",
     ignoreExceptions = {ParamErrorException.class, BusinessTypeException.class}
    )

    3.2.2 调用超时降级

    专门针对调用第三方接口超时降级。

    下面的方法是调用第三方接口3秒未收到响应就降级到errMethod方法。

    @HystrixCommand(
        commandProperties = {
                @HystrixProperty(name="execution.timeout.enabled", value="true"),
                @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value="3000"),
        },
        fallbackMethod = "errMethod"
    )

    总结

    限流、熔断和服务降级是系统容错的重要设计模式,从一定意义上讲限流和熔断也是一种服务降级的手段。

    熔断和服务降级主要是针对非核心业务功能,而核心业务如果流程超过预估的峰值,就需要进行限流。

    对于限流,选择合理的限流算法很重要,令牌桶算法优势很明显,也是使用最多的限流算法。

    在系统设计的时候,这些模式需要配合业务量的预估、性能测试的数据进行相应阈值的配置,而这些阈值最好保存在配置中心,方便实时修改。

    来源:
    https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzU2NTEyNjIzMw==&scene=161#wechat_redirect

    展开全文
  • 在 Sentinel 中资源定义和规则配置是分离的。...1,引入依赖包com.alibaba.cspsentinel-core1.8.0com.alibaba.cspsentinel-annotation-aspectj1.8.0使用方式一:Java原生编码方式步骤1:定义需要保护的资源public St...

    在 Sentinel 中资源定义和规则配置是分离的。先通过 Sentinel API 给对应的业务逻辑定义资源(埋点),然后可以在需要的时候配置规则。

    1,引入依赖包

    com.alibaba.csp

    sentinel-core

    1.8.0

    com.alibaba.csp

    sentinel-annotation-aspectj

    1.8.0

    使用方式一:Java原生编码方式

    步骤1:定义需要保护的资源

    public String test(){

    Entry entry = null;

    try {

    //定义资源保护的入口,同时指定资源名(用于与规则匹配)

    entry = SphU.entry("sentinelApi");

    //业务逻辑(这了调用了另一个方法)

    return getMsg() ;

    } catch (BlockException e) {

    if(e instanceof FlowException){

    //限流控制逻辑处理

    return "限流了" ;

    }

    if(e instanceof DegradeException){

    //熔断控制逻辑处理

    return "降级了" ;

    }

    return "none" ;

    } catch (Exception e){

    //记录业务异常数

    Tracer.trace(e) ;

    return "exe" ;

    }finally {

    if (entry != null) {

    entry.exit();

    }

    }

    }

    步骤2:定义资源保护规则

    @Component

    public class SentinelRuleConfiguration {

    @PostConstruct

    public void init() {

    //限流规则

    initFlowRule("sentinelApi") ;

    //熔断降级规则

    initDegradeRule("sentinelApi") ;

    //添加时间监听

    addEventObserver() ;

    }

    /**

    *

    * 流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,

    * 当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

    *

    * 限流的直接表现是在执行 Entry nodeA = SphU.entry(resourceName) 的时候抛出 FlowException 异常。

    * FlowException 是 BlockException 的子类,您可以捕捉 BlockException 来自定义被限流之后的处理逻辑。

    *

    * 流量控制规则 (FlowRule).

    * 同一个资源可以同时有多个限流规则,检查规则时会依次检查。

    * @param resourceName 资源名,资源名是限流规则的作用对象

    * */

    private static void initFlowRule(String resourceName) {

    List rules = new ArrayList<>();

    /*

    * 配置策略1: 并发线程数控制【通常在调用端进行配置】

    * 并发数控制用于保护业务线程池不被慢调用耗尽

    * */

    FlowRule thRule = new FlowRule(resourceName);

    thRule.setCount(1); //限流阈值

    thRule.setGrade(RuleConstant.FLOW_GRADE_THREAD); //限流阈值类型,QPS 模式(1)或并发线程数模式(0)。默认:QPS 模式

    thRule.setLimitApp("default"); //流控针对的调用来源。默认:default,代表不区分调用来源

    thRule.setClusterMode(false) ; //是否集群限流。默认为false

    /*

    * 流量控制的效果

    * 1)直接拒绝(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式(该方式适用于对系统处理能力确切已知的情况下);

    * 2)Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。

    * 3)匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)让请求以均匀的速度通过,对应的是漏桶算法(该方式主要用于处理间隔性突发的流量,暂不支持 QPS > 1000 的场景)。

    * */

    thRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT) ;

    rules.add(thRule);

    /*

    * 配置策略2:QPS流量控制

    * 当 QPS 超过某个阈值的时候,则采取措施进行流量控制

    * */

    FlowRule qpsRule = new FlowRule(resourceName);

    qpsRule.setCount(1); //限流阈值

    qpsRule.setGrade(RuleConstant.FLOW_GRADE_QPS); //限流阈值类型,QPS 模式(1)或并发线程数模式(0)。默认:QPS 模式

    qpsRule.setLimitApp("default"); //流控针对的调用来源。默认:default,代表不区分调用来源

    qpsRule.setClusterMode(false) ; //是否集群限流。默认为false

    /*

    * 流量控制的效果

    * 1)直接拒绝(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式(该方式适用于对系统处理能力确切已知的情况下);

    * 2)Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。

    * 3)匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)让请求以均匀的速度通过,对应的是漏桶算法(该方式主要用于处理间隔性突发的流量,暂不支持 QPS > 1000 的场景)。

    * */

    qpsRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER) ;

    /*

    * 这里设置的等待处理时间较大, 让系统能平稳的处理所有的请求.

    * 表示每一个请求的最长等待时间20s

    * */

    qpsRule.setMaxQueueingTimeMs(20 * 1000);

    rules.add(qpsRule);

    //定义流量控制规则

    FlowRuleManager.loadRules(rules);

    }

    /**

    * 熔断降级规则 (DegradeRule)

    *

    * 1:慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),

    * 请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,

    * 并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。 经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),

    * 若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

    *

    * 注意:只会统计在单位统计时长(statIntervalMs)内已经响应的请求【这样的请求才能判断是否满足慢调用条件】,

    * 如果实际请求的响应时长或设置的慢时长(count)都超出了statIntervalMs,那么将不可能启动熔断的作用

    * ----------------------------------------------------

    *

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

    *

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

    * 注意异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常。示例:

    * */

    private static void initDegradeRule(String resourceName) {

    List rules = new ArrayList<>();

    /*

    * 配置策略1:慢调用比例

    * 当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断;

    *

    * 当资源的保护处于CLOSED状态时,当请求进来时开始计时,统计statIntervalMs时间范围内所有请求中有多大比例的请求

    * 满足“慢请求”的条件(statIntervalMs时间范围内已经响应的才能判断是否为慢请求),如果满足则开启(OPEN)熔断,熔断时间结束后,接受一条请求通过,

    * 如果不是慢请求,则切换到HALF_OPEN状态,然后切换到CLOSE状态;

    * 所以:statIntervalMs > count

    * */

    DegradeRule srule = new DegradeRule(resourceName);

    /*

    * 熔断策略,支持慢调用比例/异常比例/异常数策略。

    * 默认:慢调用比例

    **/

    srule.setGrade(RuleConstant.DEGRADE_GRADE_RT);

    /*

    * 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用,单位ms);

    * 异常比例/异常数模式下为对应的阈值;

    * 注意:该模式下,该值要小于“统计时长”,否则不会生效。

    **/

    srule.setCount(10);

    /*

    *熔断时长,单位为 s

    **/

    srule.setTimeWindow(10);

    /*

    * 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断。

    * 默认值:5

    * */

    srule.setMinRequestAmount(5) ;

    /*

    * 统计时长(单位为 ms),如 60*1000 代表分钟级。

    * 默认:1000 ms

    * 注意与上面count值得联系,同时该时间段内的请求都会进入并参与统计。

    * */

    srule.setStatIntervalMs(1000) ;

    /*

    *慢调用比例阈值,仅慢调用比例模式有效

    * */

    srule.setSlowRatioThreshold(0.6) ;

    rules.add(srule);

    /*

    * 配置策略2:异常比例

    * 当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。

    * 注意:需要通过Tracer.trace(ex)记录非BlockException类型的业务异常数

    * */

    DegradeRule erule = new DegradeRule(resourceName);

    erule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);

    erule.setCount(0.1) ; //异常比率阈值,阈值范围是 [0.0, 1.0],代表 0% - 100%。

    erule.setTimeWindow(10) ; //熔断时长,单位为 s

    erule.setMinRequestAmount(5) ; //熔断触发的最小请求数

    erule.setStatIntervalMs(1000) ; //单位统计时长

    rules.add(erule);

    /*

    * 配置策略3:异常数

    * 当单位统计时长内的异常数目超过阈值之后会自动进行熔断

    * 注意:需要通过Tracer.trace(ex)记录非BlockException类型的业务异常数

    * */

    DegradeRule ecrule = new DegradeRule(resourceName);

    ecrule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);

    ecrule.setCount(2) ; //异常数阈值

    ecrule.setTimeWindow(10) ; //熔断时长,单位为 s

    ecrule.setMinRequestAmount(5) ; //熔断触发的最小请求数

    ecrule.setStatIntervalMs(1000) ; //单位统计时长

    rules.add(ecrule);

    //加载配置的熔断策略

    DegradeRuleManager.loadRules(rules);

    }

    private void addEventObserver(){

    //熔断器事件监听

    EventObserverRegistry.getInstance().addStateChangeObserver("logging",

    (prevState, newState, rule, snapshotValue) -> {

    if (newState == CircuitBreaker.State.OPEN) {

    // 变换至 OPEN state 时会携带触发时的值

    System.err.println(String.format("%s -> OPEN at %d, snapshotValue=%.2f", prevState.name(),

    TimeUtil.currentTimeMillis(), snapshotValue));

    } else {

    System.err.println(String.format("%s -> %s at %d", prevState.name(), newState.name(),

    TimeUtil.currentTimeMillis()));

    }

    });

    }

    }

    通过以上两步,test方法被调用的时候就能受到限流和熔断的保护了。

    至于怎么样熔断规则配置才是有效的,可看以下的代码

    public static boolean isValidRule(DegradeRule rule) {

    boolean baseValid = rule != null && !StringUtil.isBlank(rule.getResource())

    && rule.getCount() >= 0 && rule.getTimeWindow() > 0;

    if (!baseValid) {

    return false;

    }

    if (rule.getMinRequestAmount() <= 0 || rule.getStatIntervalMs() <= 0) {

    return false;

    }

    switch (rule.getGrade()) {

    case RuleConstant.DEGRADE_GRADE_RT:

    return rule.getSlowRatioThreshold() >= 0 && rule.getSlowRatioThreshold() <= 1;

    case RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO:

    return rule.getCount() <= 1;

    case RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT:

    return true;

    default:

    return false;

    }

    }

    使用方式二:使用Spring的AOP进行控制

    步骤1:添加所需切面的配置

    在Spring的配置文件中添加以下配置

    也可以通过JavaConfig的方式来配置

    @Configuration(proxyBeanMethods = false)

    //SpringBoot下该@EnableAspectJAutoProxy可以不需要,会自动完成装配

    //@EnableAspectJAutoProxy(proxyTargetClass = true)

    public class SentinelAspectConfiguration {

    @Bean

    public SentinelResourceAspect sentinelResourceAspect() {

    return new SentinelResourceAspect();

    }

    }

    步骤2:在方法上添加注解

    /**

    *

    * @SentinelResource注解参数介绍

    * 1)value 配置资源名称,如果不配置则使用方法全路径名

    * 2)entryType 指定规则作用于入口流量还是出口流量。默认为EntryType.OUT

    * 3)blockHandler 对应处理 BlockException 的函数名称。

    * 该函数的返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的类型为BlockException的参数;

    * 默认需要和原方法在同一个类中,也可以配置blockHandlerClass来指定处理的类,但类里的方法必须是static。

    * 4)fallback 失败回调的函数名称(优先级低于blockHandler),可以处理除了在参数exceptionsToIgnore中指定排除的所有异常类型,

    * 该函数默认与原函数在同一个类型中,也可以配置fallbackClass 来指定处理的类,但类里的方法必须是static,其函数的签名要求如下:

    * - 返回类型与原函数类型一致

    * - 参数列表与原函数保持一致,同时可以额外添加一个Throwable类型参数来接收对应的异常

    * 5)defaultFallback 默认的 fallback 函数名称,可以处理除了在参数exceptionsToIgnore中指定排除的所有异常类型,在未配置fallback的情况下生效。

    * 该函数默认与原函数在同一个类型中,也可以配置fallbackClass 来指定处理的类,但类里的方法必须是static,其函数的签名要求如下:

    * - 返回类型与原函数类型一致

    * - 参数列表为空,同时可以额外添加一个Throwable类型参数来接收对应的异常

    * 6)exceptionsToIgnore 用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

    * */

    @SentinelResource(value = "getUserById", fallback = "fallbackForGetUser")

    public String getUserById(String id) {

    throw new RuntimeException("getUserById command failed");

    }

    /**

    * fallback 方法,原方法被降级的时候调用;若需要限流/系统保护的 fallback 可以配置 blockHandler.

    * */

    public String fallbackForGetUser(String id) {

    return "unknown";

    }

    步骤3:定义资源保护规则(同上)

    方法同上,只是要修改资源名为“getUserById”

    经过以上几个步骤也就完成了对资源“getUserById”的保护。

    展开全文
  • 今天打算总结一些分布式开发当中常用到了限流熔断与降级,供大家参考 1 限流 限流解决了什么问题 在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。缓存的目的是提升系统访问速度和增大系统能处理...
  • 简单来说,限流熔断本身也是一个独立的拦截器,对服务请求进行拦截,并判断当前限流熔断规则是否处于生效状态,如果处于生效状态就触发限流熔断操作,比如对访问请求进行拒绝。如果不生效状态,那么就放行服务请求...
  • 限流:地铁早高峰,地铁站都会做一件事情,就是限流了!想法很直接,就是想在一定时间内把请求限制在一定范围内,保证系统不被冲垮,同时尽可能提升系统的吞吐量。非常多的时候,限流就比较重要了。 附件例子就是...
  • Sentinel限流熔断

    2021-12-24 10:35:16
    1.Sentinel简介 ...在这种情况下,保证各种业务安全运营,系统在任何情况下都不会崩溃,我们可以在系统负载过高时,采用限流、降级和熔断,三种措施来保护系统,由此一些流量控制中间件诞生,例如S
  • 我们可以在系统负载过高时,采用限流,降级和熔断,三种措施来保护系统,由此一些流量控制中间件诞生。例如Sentinel。 Sentinel概述 Sentinel(分布式系统的流量防卫兵)是阿里开源的一套用于服..
  • 而结合系统负载、服务 QPS 等,可以对限流熔断的规则数据源进行实时调控,再结合 Watch 机制,就能够比较平滑的实现自适应限流熔断的接入。 总结 在分布式应用中,限流熔断是非常重要的一环,越早开始做越有益处。 ...
  • https://mp.csdn.net/console/uploadResources?spm=1011.2124.3001.4171
  • sentinel 限流熔断神器详细介绍

    万次阅读 2022-01-28 16:32:48
    Sentinel 是一款面向分布式服务架构的轻量级流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来保障服务的稳定性,核心思想是:根据对应资源配置的规则来为资源执行相应的流控/...
  • java -jar -Dserver.port=9100 sentinel-dashboard-1.8.0.jar 启动成功后,初次访问,需要登录用户名和密码,均为 : sentinel/sentinel 进来之后发现空空如也,别紧张,这个dashboard默认是懒加载的,意
  • 被调方:延时600ms ahas: user限流: trade熔断:(3秒内请求数>4)&&(3s内慢调用/请求数>50%) -》》开启熔断 慢调用标准:响应时间大于500ms ...测试限流: ...测试限流和rt熔断 ...
  • Sentinel 是面向分布式服务架构的轻量级流量控制产品,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助您保护服务的稳定性。 下载sentinel链接:...
  • 导读:本篇作为SpringCloud Alibaba微服务实战系列的第五篇,主要内容是使用Sentinel给微服务加上限流熔断功能,防止异常情况拖垮应用服务。系列文章,欢迎持续关注。简介Sentinel是面向分布式服务框架的轻量级流量...
  • 计数器算法:计数器算法指在一段时间内,进行计数,与伐值进行比较,如果超过了伐值则进行限流操作,到了时间临界点,将计数器清零重新计算. 漏桶算法:流量的流入是以不确定的速率率先进入到漏桶,然后漏桶以一定的速度...
  • 我们可以在系统负载过高时,采用限流、降级和熔断,三种措施来保护系统,由此一些流量控制中间件诞生。例如Sentinel。 Sentinel概述 Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决...
  • 围观:被HR怼了:估计你一辈子就是个程序员今天准备谈下微服务架构和API网关中的限流熔断,当前可以看到对于Spring Cloud框架本身也提供了Hystrix,主流的开源API网关产品类...
  • 一、服务限流 1.在gateway中更改版本号 <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source&...
  • 在SpringCloud体系中,sentinel主要是为了替换原Hystrix的功能,与Hystrix相比,sentinel的隔离级别更加精细,提供的Dashboard可以在线更改限流熔断规则,而且使用也越加方便。要了解更多详细信息请移步至Sentin...
  • 前言: 依赖: 限流示例: 注解使用: 熔断: 系统保护:
  • 微服务中——限流熔断、降级你知道什么意思吗?
  • 一、限流 1、含义 限流的目的是通过对并发访问/请求进行限速或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可由拒绝服务,就是定向到错误页或友好的展示页,排队或等待。 限流可以保障我们...
  • Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决方案。它以流量为切入点, 从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。
  • 限流熔断

    2019-07-24 10:38:32
    伴随着微服务架构被宣传得如火如荼,一些概念也...服务熔断 在介绍熔断机制之前,我们需要了解微服务的雪崩效应。在微服务架构中,微服务是完成一个单一的业务功能,这样做的好处是可以做到解耦,每个微服务可以独...
  • Sentinel使用 安装 打开sentinel下载网址 ... 下载对应Jar包(可以存储到一个sentinel目录),如图所示: ...java -Dserver.port=8180 -Dcsp.sentinel.dashboard.server=localhost:8180 -Dproject.name=se.

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,000
精华内容 8,400
关键字:

java 限流熔断

java 订阅