漏斗算法 java

本文介绍了一种基于漏斗算法的限流实现,通过控制单位时间内请求的频率,有效防止系统过载。该算法利用Spring框架进行依赖注入,通过缓存机制存储每个用户的请求状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
        }
    }
}

 

转载于:https://www.cnblogs.com/go4mi/p/11023411.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值