zoukankan      html  css  js  c++  java
  • 漏斗算法 java

    import com.alibaba.fastjson.JSONObject;import org.apache.commons.lang.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    /**
     * @author haosenwei[haosenwei@dubmic.com]
     * @date 2019-06-14 14:59
     * <p>Copyright 2008-2019 snsndk.com</p>
     */
    @Component
    public class FunnelRateLimiter {
    
        @Autowired
        ICache iCache;
    
        /**
         * 漏斗容量
         */
        private static final int CAPACITY = 3;
        /**
         * 每单个单位时间允许的流量
         */
        private static final int ALLOWQUOTA = 3;
    
        /**
         * 单位时间(秒)
         */
        private static final int PERSECOND = 1;
    
        /**
         * 判断是否可以访问
         *
         * @param did    唯一标识
         * @param action 操作
         * @return 是否运行访问
         */
        public boolean isActionAllowed(String did, String action) {
            return this.isActionAllowed(did, action, CAPACITY, ALLOWQUOTA, PERSECOND);
        }
    
        /**
         * 根据给定的漏斗参数检查是否允许访问
         *
         * @param did        用户名
         * @param action     操作
         * @param capacity   漏斗容量
         * @param allowQuota 每单个单位时间允许的流量
         * @param perSecond  单位时间(秒)
         * @return 是否允许访问
         */
        public boolean isActionAllowed(String did, String action, int capacity, int allowQuota, int perSecond) {
            String key = "funnel:" + action + ":" + did;
            String s = iCache.get(key);
            Funnel funnel = null;
            if (StringUtils.isBlank(s)) {
                funnel = new Funnel(capacity, allowQuota, perSecond);
                this.iCache.set(key, JSONObject.toJSONString(funnel));
            } else {
                funnel = JSONObject.parseObject(s, Funnel.class);
            }
            return funnel.watering(1);
        }
    
        private static class Funnel {
            private int capacity;
            private float leakingRate;
            private int leftQuota;
            private long leakingTs;
    
            public Funnel(int capacity, int count, int perSecond) {
                this.capacity = capacity;
                // 因为计算使用毫秒为单位的
                perSecond *= 1000;
                this.leakingRate = (float) count / perSecond;
            }
    
            /**
             * 根据上次水流动的时间,腾出已流出的空间
             */
            private void makeSpace() {
                long now = System.currentTimeMillis();
                long time = now - leakingTs;
                int leaked = (int) (time * leakingRate);
                if (leaked < 1) {
                    return;
                }
                leftQuota += leaked;
                // 如果剩余大于容量,则剩余等于容量
                if (leftQuota > capacity) {
                    leftQuota = capacity;
                }
                leakingTs = now;
            }
    
            /**
             * 漏斗漏水
             *
             * @param quota 流量
             * @return 是否有足够的水可以流出(是否允许访问)
             */
            public boolean watering(int quota) {
                makeSpace();
                int left = leftQuota - quota;
                if (left >= 0) {
                    leftQuota = left;
                    return true;
                }
                return false;
            }
        }
    }
  • 相关阅读:
    请求失败或服务未及时响应。有关详细信息,请参见事件日志或其他适用的错误日志
    12篇学通C#网络编程——第一篇 基础之进程线程(转)
    关于XP和win7前置音频插孔无声音的解决办法
    进程,线程,主线程,异步
    SQL 在什么情况下使用全表扫描
    性能的一些设置
    清除Windows 7通知区域的旧图标
    操作office
    数据库索引
    SCSI
  • 原文地址:https://www.cnblogs.com/go4mi/p/11023411.html
Copyright © 2011-2022 走看看