zoukankan      html  css  js  c++  java
  • dubbo 限流之TpsLimitFilter

    常见的限流方式有:计数器、滑动窗口、漏斗和令牌桶算法

    计数器 VS 滑动窗口

    计数器算法是最简单的算法,可以看成是滑动窗口的低精度实现。滑动窗口由于需要存储多份的计数器(每一个格子存一份),所以滑动窗口在实现上需要更多的存储空间。也就是说,如果滑动窗口的精度越高,需要的存储空间就越大。

    漏桶算法 VS 令牌桶算法

    漏桶算法和令牌桶算法最明显的区别是令牌桶算法允许流量一定程度的突发。因为默认的令牌桶算法,取走token是不需要耗费时间的,也就是说,假设桶内有100个token时,那么可以瞬间允许100个请求通过。

    令牌桶算法由于实现简单,且允许某些流量的突发,对用户友好,所以被业界采用地较多。当然我们需要具体情况具体分析,只有最合适的算法,没有最优的算法。

    dubbo 默认实现的是滑动窗口的方式。

    @Activate(group = Constants.PROVIDER, value = Constants.TPS_LIMIT_RATE_KEY)
    public class TpsLimitFilter implements Filter {
    
        private final TPSLimiter tpsLimiter = new DefaultTPSLimiter();
    
        @Override
        public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    
            if (!tpsLimiter.isAllowable(invoker.getUrl(), invocation)) {
                throw new RpcException(
                        "Failed to invoke service " +
                                invoker.getInterface().getName() +
                                "." +
                                invocation.getMethodName() +
                                " because exceed max service tps.");
            }
    
            return invoker.invoke(invocation);
        }
    
    }
    public class DefaultTPSLimiter implements TPSLimiter {
      // 存储每个服务的key和每个服务限制的请求数。
        private final ConcurrentMap<String, StatItem> stats = new ConcurrentHashMap<String, StatItem>();
        @Override
        public boolean isAllowable(URL url, Invocation invocation) {
            int rate = url.getParameter(Constants.TPS_LIMIT_RATE_KEY, -1); // 窗口内的最大请求数
            long interval = url.getParameter(Constants.TPS_LIMIT_INTERVAL_KEY, Constants.DEFAULT_TPS_LIMIT_INTERVAL); // 窗口大小
            String serviceKey = url.getServiceKey(); // 服务唯一key
            if (rate > 0) {
                StatItem statItem = stats.get(serviceKey);
                if (statItem == null) {
                    stats.putIfAbsent(serviceKey,
                            new StatItem(serviceKey, rate, interval));
                    statItem = stats.get(serviceKey);
                }
                return statItem.isAllowable();
            } else {
                StatItem statItem = stats.get(serviceKey);
                if (statItem != null) {
                    stats.remove(serviceKey);
                }
            }
    
            return true;
        }
    
    }
     public boolean isAllowable() {
            long now = System.currentTimeMillis();
            if (now > lastResetTime + interval) { // 重置窗口
                token.set(rate); 
                lastResetTime = now;
            }
    
            int value = token.get();
            boolean flag = false;
            while (value > 0 && !flag) {
                flag = token.compareAndSet(value, value - 1); // 每来一个请求减少一个许可
                value = token.get();
            }
    
            return flag;
        }

    总结:dubbo 默认的 限流实现比较简单,用户可以自定义限流策略。业界令牌桶用的比较多。

  • 相关阅读:
    封装成帧、帧定界、帧同步、透明传输(字符计数法、字符串的首尾填充法、零比特填充的首尾标志法、违规编码法)
    计算机网络之数据链路层的基本概念和功能概述
    物理层设备(中继器、集线器)
    计算机网络之传输介质(双绞线、同轴电缆、光纤、无线电缆、微波、激光、红外线)
    计算机网络之编码与调制
    0953. Verifying an Alien Dictionary (E)
    1704. Determine if String Halves Are Alike (E)
    1551. Minimum Operations to Make Array Equal (M)
    0775. Global and Local Inversions (M)
    0622. Design Circular Queue (M)
  • 原文地址:https://www.cnblogs.com/hansc-blog/p/9371990.html
Copyright © 2011-2022 走看看