Redis深度历险-Redis 漏斗限流

本文大部分内容引自《Redis深度历险:核心原理和应用实践》,感谢作者!!!

漏斗限流灵感

限流算法

漏斗限流:https://blog.csdn.net/dadiyang/article/details/82887663

令牌桶限流:https://www.cnblogs.com/cjsblog/p/9379516.html

漏斗限流单机实现

public class FunnelRateLimiter {
    static class Funnel {
        //容量
        int capacity;
        //流出速率
        float leakingRate;
        //剩余容量
        int leftQuota;
        //计算起始时间
       long leakingTs;
       public Funnel(int capacity, float leakingRate) {
           this.capacity = capacity;
           this.leakingRate = leakingRate;
           this.leftQuota = capacity;
           this.leakingTs = System.currentTimeMillis();
       }
       void makeSpace() {
           long nowTs = System.currentTimeMillis();
           long deltaTs = nowTs - leakingTs;
           int deltaQuota = (int) (deltaTs * leakingRate);
           if (deltaQuota < 0) { 
               //间隔时间太长,整数数字过大溢出
               this.leftQuota = capacity;
               this.leakingTs = nowTs;
               return;
           }
           if (deltaQuota < 1) { 
               //腾出空间太小,最小单位是1
               return;
           }
           //剩余容量 = 当前容量 + 流出速率 * 间隔时间
           this.leftQuota += deltaQuota;
           this.leakingTs = nowTs;
           if (this.leftQuota > this.capacity) {
               this.leftQuota = this.capacity;
           }
       }
       //判断是否能加入交易
       boolean watering(int quota) {
           makeSpace();
           if (this.leftQuota >= quota) {
               this.leftQuota -= quota;
               return true;
           }
           return false;
       }
	}
	private Map<String, Funnel> funnels = new HashMap<>();
	public boolean isActionAllowed(String userId, String actionKey, int capacity, float leakingRate) {
        String key = String.format("%s:%s", userId, actionKey);
        Funnel funnel = funnels.get(key);
        if (funnel == null) {
            funnel = new Funnel(capacity, leakingRate);
            funnels.put(key, funnel);
        }
        //需要1个quota
        return funnel.watering(1);
	}
}

Redis漏斗限流使用方法

允许用户回复行为的频率为每60s最多30次(漏水速率),漏斗的初始容量为15,也就是说一开始可以连续回复15个帖子,然后才开始受影响,每次行为占用1个空间。恢复速率是30/60s=0.5个/s

cl.throttle [key] [capacity] [operation_times] [time_span] [quota]
cl.throttle laoqian:reply 15 30 60 1
1) (integer) 0  # 0表示允许,1表示拒绝
2) (integer) 15 # 漏斗容量capacity
3) (integer) 14 # 漏斗剩余空间left_quota
4) (integer) -1 # 如果拒绝了,需要多长时间后再试(漏斗有空间了,单位秒)
5) (integer) 2  # 多长时间后,漏斗完全空出来(left_quota==capacity,单位秒)

    在执行限流指令时,如果被拒绝了,就需要丢弃或重试。cl.throttle 指令考虑的重试时间都计算好了,直接取返回结果数组的第四个值进行 sleep 即可,如果不想阻塞线程,也可以异步定时任务来重试

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值