zoukankan      html  css  js  c++  java
  • 单个应用的限流

    应用限流

    前言

    对于一个高并发的系统来说,限流其实是非常重要的一个环节,当巨大的流量到达我们的服务器的时候,就很容易造成接口不可用。所以针对此类问题,本文对限流这个问题在业务代码层面进行深入探讨。

    (七牛云的图床不知道为啥在Markdown里解析不出来,今天用富文本编辑器吧)

    限流算法

    1,计数器算法

    算法如其名,对请求进行技术,超过了设定的上限,则拒绝请求,是比较粗暴简单的一种算法。比如设定上限为100,那么每来一次请求计数器就+1,当然这里的+1的过程肯定是原子性的,可以采用AtomicLong来实现,在接下里的一秒内,如果计数器的值达到了100,那么后面的请求全部被拒绝。

    缺点:计数器只在请求数上进行了考虑,并没有考虑请求到来的速率,也就是说如果一秒钟前面的100mm请求数就到达了100,那么在后面的900mm中,请求就只能全部被拒绝,这种现象叫做“突刺现象”。那么这样会造成问题呢,从安全角度来思考,如果我们的应用设置一分钟最多100请求,此时有一个不怀好意的用户,在这一分钟的最后一秒钟就直接发送了100个请求,然后在下一分钟的一开始又瞬间发送了100个请求,这样其实已经大大超过了请求速率的上限,这样应用就不提供服务了,这里的缺点在于,对于秒级的限流,我们没有没有做到精度控制,也就是一分钟的时间却只有一个计数器,这样自然是不行的。

    2,滑动窗口算法

    这个在学习计网的时候都一定有所接触,实际上就是对固定的时间片进行划分并且随着时间进行移动,这种算法可以克服上面的计数器算法的临界点的问题,在滑动从窗口算法中,将时间段进行了划分,比如将一分钟均等划分为六个小格子,每一个小格子有自己独立的计数器并且负责自己这一个格子的计数。每过去十秒钟,窗口就会往后走动一格。对于计数器的临界问题,在滑动窗口中就不会有这个问题了,比如在前一分钟的最后一秒恶意用户突然发送了100个请求(下图灰色部分),到后一分钟的第一秒的时候(下图橘色部分),又来了100个请求,但是此时滑动窗口也向后面移动了一格,所以移动后的时间窗口内的总请求是200,应用就能检测到请求速率超高进而进行限流。

    3, 漏桶算法

    顾名思义,这个算法类似于漏斗,上面口大,下面口小,来得及处理的就从下面的口子出去,来不及的就先存在桶里,如果桶满了,请求就先丢弃。

    图示:

    ​ 缺点:漏桶算法也有缺点,那就是不能应对短时间的突发流量。

    4,令牌桶算法

    令牌桶算法是对漏桶算法的一种改进,桶算法可以限制请求调用的速率,而令牌桶算法能够限制调用的平均速率,同时允许一定程度的突发调用。令牌桶算法会以一个恒定的速率向桶中放入令牌,每一次请求调用都需要获取令牌,只有获取到了,才有机会继续执行,当桶里没有令牌的时候,将当前请求丢弃或者阻塞。其中,放令牌的动作是不断地执行的,如果桶里的令牌数量达到上限,就丢弃令牌。所以这种算法可以抵挡瞬时增加的请求,只有在桶里没有令牌的时候,请求就会进行等待或者被丢弃。

    令牌桶算法demo

    针对生产中常用的限流方式,这里采用Guava中提供的RateLimiter来对令牌桶算法写个demo。代码理解起来也不难。

    /**
     * @author yintianhao
     * @createTime 2020/10/18 16:54
     * @description
     */
    @RestController
    @Slf4j
    public class DemoController {
    
    
        private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM--dd HH:mm:ss");
    
        /**
         * rateLimiter 限流器
         *
         * */
        private static final RateLimiter rateLimiter = RateLimiter.create(10);
    
    
        @GetMapping("/get")
        public String getResponse(){
    
            if(rateLimiter.tryAcquire()){
                //一次拿一个,默认返回时间是0,即拿不到就立即返回
                log.info(String.format("time:%s msg:%s",sdf.format(new Date()),"请求正常"));
                try {
                    Thread.sleep(500);
                }catch (Exception e){
                    e.printStackTrace();
                }
                return "正常请求";
            }else{
                log.error(String.format("time:%s msg:%s",sdf.format(new Date()),"请求限流"));
                return "限流了";
            }
        }
    
    
    }
    DemoController

    再用JMeter来进行测试,设置十个线程去请求。

    查看限流情况:

  • 相关阅读:
    外观模式
    虚拟专用网
    DHCP服务
    NFS文件服务器
    samba服务器
    fatal error: Invalid layout of preloaded class
    ftp上传与下载
    byte与char的区别
    android管理联系人操作
    android图像与图像处理系列(一、Bitmap和BitmapFactory)
  • 原文地址:https://www.cnblogs.com/Yintianhao/p/13837959.html
Copyright © 2011-2022 走看看