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 默认的 限流实现比较简单,用户可以自定义限流策略。业界令牌桶用的比较多。

  • 相关阅读:
    在页面中控制媒体流的起播点和播放长度
    缓冲区数据转换为字符串输出
    编程中注意的一个问题
    一个整合SQL语句的类
    注意服务器系统日期对防病毒软件的影响
    网络病毒源的排查(2005年3月22日维护记录)
    升级到 Microsoft .NET >Visual Basic 6.0 控件和 .NET 控件的区别
    修改您的站点设计以改善下载体验
    下一版本Windows&reg; CE 开发工具Smart Device Extensions for Microsoft Visual Studio&reg; .NET
    WINDOWS (服务器) 和 DOS(客户端) 网络互连 基于TCP/IP的编程实现
  • 原文地址:https://www.cnblogs.com/hansc-blog/p/9371990.html
Copyright © 2011-2022 走看看