没有预热,不叫高并发「限流算法第三把法器:令牌桶算法」- 第302篇

相关历史文章(阅读本文之前,您可能需要先看下之前的系列

「定制Spring Boot Admin UI的页面」- 第298篇

国内最全的Spring Boot系列之三

版本号命名的前世今生- 值得收藏 - 第299篇

「世界上最好的学习法:费曼学习法」

高并发,不怕不怕「限流算法第一把法器:计数器法」 - 第300篇

精度不够,滑动时间来凑「限流算法第二把法器:滑动时间窗口算法」- 第301篇

 

 

悟纤:师傅,师傅,你尿床了!

没有预热,不叫高并发「限流算法第三把法器:令牌桶算法」- 第302篇_第1张图片

师傅:(瞬间醒来,在床上一蹦)哪里哪里,这可丢大脸了。

 

没有预热,不叫高并发「限流算法第三把法器:令牌桶算法」- 第302篇_第2张图片

悟纤:哈哈… 哈哈… 逗你的,逗你的。

没有预热,不叫高并发「限流算法第三把法器:令牌桶算法」- 第302篇_第3张图片

师傅:你看看,待会不撕破你衣服,就不叫师傅。

没有预热,不叫高并发「限流算法第三把法器:令牌桶算法」- 第302篇_第4张图片

悟纤:师傅,师傅,师傅... 打在我身,痛在你心,师傅这又是何必呐。

师傅:好了,好了,算是怕了你了,说说这么早,把为师叫起来,这是要作甚?

悟纤:当然是学习上一节留下的问题了。

没有预热,不叫高并发「限流算法第三把法器:令牌桶算法」- 第302篇_第5张图片

师傅:为师咋就这么不相信呐,这太阳是打西边出来了嘛?

悟纤:反正今天没太阳,你说哪边就是哪边。

师傅:不要在皮了,我们还是赶紧来学习一下吧。

 

一、Warm Up缘起

1.1 现象

(1)DB重启后,瞬间死亡

一个高并发环境下的DB,进程死亡后进行重启。由于业务处在高峰期间,上游的负载均衡策略发生了重分配。刚刚启动的DB瞬间接受了1/3的流量,然后load疯狂飙升,直至再无响应。

原因就是:新启动的DB,各种Cache并没有准备完毕,系统状态与正常运行时截然不同。可能平常1/10的量,就能够把它带入死亡。

(2)服务重启后,访问异常

另外一个常见的问题是:我的一台服务器发生了问题,由于负载均衡的作用,剩下的机器立马承载了这些请求,运行的很好。当服务重新加入集群时,却发生了大量高耗时的请求,在请求量高的情况下,甚至大批大批的失败。

原因:

~ 服务启动后,jvm并未完全准备完毕,JIT未编译等。

~ 应用程序使用的各种资源未准备就绪。

~ 负载均衡发生了rebalance。

 

这两个问题,都是没有做好预热,那什么是预热呐。

 

1.2 Warm Up

Warm Up,即冷启动/预热的方式。当系统长期处于低水位的情况下,流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过”冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

 

       对于Warm Up可以通过令牌桶算法进行实现。

 

二、令牌桶算法

令牌桶算法,又称token bucket。同样为了理解该算法,我们来看一下该算法的示意图:

没有预热,不叫高并发「限流算法第三把法器:令牌桶算法」- 第302篇_第6张图片

 

 

首先,我们有一个固定容量的桶,桶里存放着令牌(token)。桶一开始是空的,token以 一个固定的速率r往桶里填充,直到达到桶的容量,多余的令牌将会被丢弃。每当一个请求过来时,就会尝试从桶里移除一个令牌,如果没有令牌的话,请求无法通过。

 

三、令牌桶算法小栗子

3.1 简易例子

       我们看一个使用Java代码写的最简单的例子:

public class TokenBucket {
    public long timeStamp = System.currentTimeMillis(); // 当前时间
    public long capacity; // 桶的容量
    public long rate; // 令牌放入速度
    public long tokens; // 当前令牌数量

    public boolean grant() {
        long now = System.currentTimeMillis();
        // 先添加令牌
        tokens = Math.min(capacity, tokens + (now - timeStamp) * rate);
        timeStamp = now;
        if (tokens < 1) {
            // 若不到1个令牌,则拒绝
            return false;
        } else {
            // 还有令牌,领取令牌
            tokens -= 1;
            return true;
        }
    }
}

 

说明:

(1)令牌发放:这里通过时间差来进行发送令牌。

(2)令牌领取:直接使用-1的方式。

(3)满了丢弃:使用Math.min取最小值,所以最大也就是初始设置的容量。

 

3.2 Google开源工具包Guava限流工具类RateLimiter

Google开源工具包Guava提供了限流工具类RateLimiter,该类基于令牌桶算法实现流量限制,使用十分方便,而且十分高效。

       添加依赖:



         com.google.guava

         guava

         

         28.2-jre

         

         

说明:对于23.0(包括23.0)版本之前java版本没有后缀-jre,框架提供者估计是为了能够更好的区分是给什么平台使用的吧 -jre(java),-android(安卓应用程序开发)。

       编写代码:

public class RateLimiterTest {
    public static void main(String[] args) {

        RateLimiter limiter = RateLimiter.create(1);

        for (int i = 1; i <= 5; i++) {
            double waitTime = limiter.acquire(i);
            System.out.println("acq:"+i+" cutTime=" + new Date()+" waitTime:" + waitTime);
        }
    }
}

   Run一下:

acq:1 cutTime=Wed Feb 26 14:46:36 CST 2020waitTime:0.0

acq:2 cutTime=Wed Feb 26 14:46:37 CST 2020waitTime:0.980988

acq:3 cutTime=Wed Feb 26 14:46:39 CST 2020waitTime:1.992958

acq:4 cutTime=Wed Feb 26 14:46:42 CST 2020waitTime:2.998297

acq:5 cutTime=Wed Feb 26 14:46:46 CST 2020waitTime:3.996815

说明:

(1)通过RateLimiter.create(1);创建一个限流器,参数代表每秒生成的令牌数。令牌的管理RateLimiter类就轻松帮我们搞定了。

(2)limiter.acquire(i);来以阻塞的方式获取令牌,也可以通过tryAcquire(intpermits, long timeout, TimeUnit unit)来设置等待超时时间的方式获取令牌,如果超timeout为0,则代表非阻塞,获取不到立即返回。

 

四、悟纤小结

师傅:为师今天讲了不少知识点,有点口干舌燥了,剩下的时间给你了。

没有预热,不叫高并发「限流算法第三把法器:令牌桶算法」- 第302篇_第7张图片

悟纤:师傅,您休息休息,请放心把舞台交到我手中。

悟纤:来,来来,music响起来。

没有预热,不叫高并发「限流算法第三把法器:令牌桶算法」- 第302篇_第8张图片

      

要记住几点:

(1)Warm Up(冷启动/预热):通过”冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

(2)Warm Up相应的实现算法是令牌桶算法。

(3)令牌桶算法简单理解就是由一个桶,桶里有令牌,也就是token,要请求前先从桶里拿一下令牌,如果拿到领牌,则可以访问资源,如果拿不到令牌,则拒绝访问;另外就是会根据一定的速率往桶里放入令牌。

没有预热,不叫高并发「限流算法第三把法器:令牌桶算法」- 第302篇_第9张图片

 

我就是我,是颜色不一样的烟火。
我就是我,是与众不同的小苹果。

学院中有Spring Boot相关的课程:

à悟空学院:https://t.cn/Rg3fKJD

SpringBoot视频:http://t.cn/A6ZagYTi

Spring Cloud视频:http://t.cn/A6ZagxSR

SpringBoot Shiro视频:http://t.cn/A6Zag7IV

SpringBoot交流平台:https://t.cn/R3QDhU0

SpringData和JPA视频:http://t.cn/A6Zad1OH

SpringSecurity5.0视频:http://t.cn/A6ZadMBe

Sharding-JDBC分库分表实战:http://t.cn/A6ZarrqS

分布式事务解决方案「手写代码」:http://t.cn/A6ZaBnIr

 

你可能感兴趣的:(从零开始学Spring,Boot,spring,boot,java)