zoukankan      html  css  js  c++  java
  • 漏斗桶和令牌桶

     漏斗桶和令牌桶都属于服务端常用的限流手段

    漏斗桶

    如图:把请求比作水,漏斗有一个进水口 和 一个出水口,出水口以一定速率出水,并且有一个最大出水速率,当桶里有水并且一直在进水时,就会直接溢出(拒绝服务)

    优点:能够强行限制数据的传输速度,因为流出速率为固定值,能够让自身的流量平稳的打到下游的接口上,所以对下游系统起到保护作用

    缺点:没有有效的使用网络资源,因为流出速率为固定值,即使部分网络为空闲,也无法接收到请求,因此,漏桶算法对于突发特性的流量来说缺乏效率

    比如某一个时刻有10个请求,漏斗桶的流出速率为2,漏斗容量为5,那么将会有5个请求被拒绝,漏斗中的5个按照2的速率处理。

    public class FunnelBucketTest {
    
        //漏斗桶的容量
        private final int capacity = 5;
    
        //漏斗桶的流出速率
        private int rate;
    
        //剩余容量
        private int leaveCap = 0;
    
        //漏斗桶中请求的存储
        private LinkedList<SimulationRequest> requestList = new LinkedList<>();
    
    
        public FunnelBucketTest(final int rate) {
            this.rate = rate;
    
            //初始化时,leaveCap为桶的容量
            leaveCap = capacity;
    
            new Thread(new Runnable() {
                public void run() {
                    while(true){
                        if (!requestList.isEmpty()){
                            SimulationRequest simulationRequest = requestList.removeFirst();
                            System.out.println("第"+simulationRequest.getI()+"个请求被处理");
                        }
    
                        //这里设置每秒处理几个
                        try {
                            Thread.sleep(1000/rate);
                        }catch (Exception e){
                            System.out.println("error");
                        }
                    }
                }
            }).start();
        }
    
        public synchronized boolean tryAcqure(SimulationRequest request){
            if (leaveCap <=0){
                return false;
            } else {
                leaveCap--;
                requestList.add(request);
                return true;
            }
        }
    
        public static void main(String[] args) {
            FunnelBucketTest funnelBucketTest = new FunnelBucketTest(2);
            for (int i = 1 ; i <=10;i++){
                SimulationRequest simulationRequest = new SimulationRequest(i);
                if (funnelBucketTest.tryAcqure(simulationRequest)){
                    System.out.println("第"+simulationRequest.getI()+"个请求成功执行");
                } else {
                    System.out.println("第"+simulationRequest.getI()+"个请求被拒绝");
                }
            }
        }
    
    
        //模拟请求对象
        static class SimulationRequest{
    
            /**
             * 当前为第几个
             */
            private int i;
    
            public SimulationRequest(int i) {
                this.i = i;
            }
    
            public int getI() {
                return i;
            }
    
            public void setI(int i) {
                this.i = i;
            }
        }
    }

    令牌桶

    令牌桶是系统以恒定的速率产生令牌,令牌桶有个容量,当令牌桶满了之后,再放入令牌会被丢弃;当处理一个请求时,会从令牌桶中取出一个令牌,如果拿到了令牌,那么请求会被处理,否则请求会被丢弃。

    相比漏斗桶的优点

    令牌桶同样可以做到限制流量;

    令牌桶对突发流量,有比较好的处理,比如:还是同一时刻有10个请求,令牌桶的大小为5,同样也是拒绝5个请求,但是令牌桶可以瞬间放过5个请求,而漏斗桶却实际处理1个,所以单从瞬间的话,令牌桶处理了更多的请求。

    令牌桶算法一般用于保护自身的系统,对调用者进行限流,保护自身的系统不被突发的流量打垮

    模仿令牌桶:

    public class TokenBucketTest {
    
        //令牌桶容量
        private final int capacity = 5;
    
        //令牌产生速率
        private int rate;
    
        //令牌的剩余数量
        private int leaveCap = 0;
    
        public TokenBucketTest(final int rate) {
            this.rate = rate;
    
            //设置令牌剩余数量为容量
            leaveCap = capacity;
    
            new Thread(new Runnable() {
                public void run() {
                    while (true) {
                        leaveCap++;
                        if (leaveCap > capacity){
                            leaveCap = capacity;
                        }
                        //这里设置每秒增加几个令牌
                        try {
                            Thread.sleep(1000/rate);
                        }catch (Exception e){
                            System.out.println("error");
                        }
                    }
                }
            }).start();
        }
    
        public synchronized boolean tryAcqure(FunnelBucketTest.SimulationRequest request){
            if (leaveCap <=0){
                return false;
            } else {
                leaveCap--;
                return true;
            }
        }
    
        public static void main(String[] args) {
            TokenBucketTest funnelBucketTest = new TokenBucketTest(2);
            for (int i = 1 ; i <=10;i++){
                FunnelBucketTest.SimulationRequest simulationRequest = new FunnelBucketTest.SimulationRequest(i);
                if (funnelBucketTest.tryAcqure(simulationRequest)){
                    System.out.println("第"+simulationRequest.getI()+"个请求成功执行");
                } else {
                    System.out.println("第"+simulationRequest.getI()+"个请求被拒绝");
                }
            }
        }
    }

    比较常用的令牌桶的实现方式:Ratelimiter,使用方式参考:http://ifeve.com/guava-ratelimiter/

    参考:

    秒杀系统的设计方案:https://blog.csdn.net/weixin_43188031/article/details/108304960

    《消息队列高手课》

    https://blog.csdn.net/Px01Ih8/article/details/108764655

    一个入行不久的Java开发,越学习越感觉知识太多,自身了解太少,只能不断追寻
  • 相关阅读:
    C#调用VC++.net托管库程序集DLL
    SQL Server 2008 评估期已过期解决办法
    TFS2010安装(转)
    将dll添加到GAC(Global Assembly Cache)中
    LINQ to SQL with NOLOCK
    SQL Server 2008创建定期自动备份任务(转)
    问题解决记录(一)
    控制台读入
    数据库
    a标签的onclick与href的执行顺序
  • 原文地址:https://www.cnblogs.com/fengtingxin/p/14243283.html
Copyright © 2011-2022 走看看