漏斗限流是最常用的限流方法之一,漏斗流水的速率大于灌水的速率,漏斗就永远装不满,反之水就会溢出。

所以漏斗的剩余空间就代表当前行为可以持续进行的数量,水流出的速率代表系统允许该行为的最大频率。

import time

class Funnel:
def __init__(self, capacity, leaking_rate):
self.capacity = capacity # 漏斗容量
self.leaking_rate = leaking_rate # 流出速率
self.left_quota = capacity # 漏斗剩余空间
self.leaking_ts = time.time() # 上一次漏水时间 def make_space(self):
now_ts = time.time()
delta_ts = now_ts - self.leaking_ts # 距离上一次漏水过去了多久
delta_quota = delta_ts * self.leaking_rate # 腾出的空间
if delta_quota < 1: # 腾的空间过小等待下一次
return
self.left_quota += delta_quota # 增加剩余空间
self.leaking_ts = now_ts # 记录漏水时间
if self.left_quota > self.capacity: # 剩余空间不得高于容量
self.left_quota = self.capacity def watering(self, quota):
self.make_space()
if self.left_quota >= quota: # 判断剩余空间是否足够
self.left_quota -= quota
return True
return False funnels = {} # 所有的漏斗 def is_action_allowed(
user_id, action_key, capacity, leaking_rate):
key = '{}:{}'.format(user_id, action_key)
funnel = funnels.get(key)
if not funnel:
funnels[key] = Funnel(capacity, leaking_rate)
return funnel.watering(1) for i in range(20):
print is_action_allowed('tom', 'reply', 15, 0.5)

make_space方法是漏斗算法的核心,其在每次灌水前都会被调用以触发漏水,给漏斗腾出空间,Funnel占据的空间大小不与行为频率成正比,其空间占用是一个常量。

问题是分布式漏斗算法如何实现?

Funnel类其实就是一个高级字典,那么我们可以利用Redis中的hash结构来存储对应字段,灌水时将字段取出进行逻辑运算后再存入hash结构中即可完成一次行为频度的检测。但这有个问题就是整个过程的原子性无法保证,意味着要用锁来控制,但如果加锁失败,就要重试或者放弃,这回导致性能下降和影响用户体验,同时代码复杂度也升高了,此时Redis提供了一个插件,Redis-Cell出现了。

Redis-Cell

Redis 4.0提供了一个限流Redis模块,名称为redis-cell,该模块提供漏斗算法,并提供原子的限流指令。

该模块只有一条指令cl.throttle,其参数和返回值比较复杂。

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

该指令意思为,允许用户tom的reply行为的频率为每60s最多30次,漏斗初始容量为15(因为是从0开始计数,到14为15个),默认每个行为占据的空间为1(可选参数)。

如果被拒绝,取返回数组的第四个值进行sleep即可作为重试时间,也可以异步定时任务来重试。

注意事项

由于Redis-Cell是基于Rust语言写的插件,因此在安装插件前要先安装rust。

具体方法看GitHub

深入Redis漏斗限流的更多相关文章

  1. 基于Redis的限流系统的设计

    本文讲述基于Redis的限流系统的设计,主要会谈及限流系统中限流策略这个功能的设计:在实现方面,算法使用的是令牌桶算法来,访问Redis使用lua脚本.   1.概念 In computer netw ...

  2. redis之漏斗限流

    Redis 4.0 提供了一个限流 Redis 模块,它叫 redis-cell.该模块也使用了漏斗算法,并提供了原子的限流指令.有了这个模块,限流问题就非常简单了.

  3. Envoy实现.NET架构的网关(五)集成Redis实现限流

    什么是限流 限流即限制并发量,限制某一段时间只有指定数量的请求进入后台服务器,遇到流量高峰期或者流量突增时,把流量速率限制在系统所能接受的合理范围之内,不至于让系统被高流量击垮.而Envoy可以通过e ...

  4. Redis解读(4):Redis中HyperLongLog、布隆过滤器、限流、Geo、及Scan等进阶应用

    Redis中的HyperLogLog 一般我们评估一个网站的访问量,有几个主要的参数: pv,Page View,网页的浏览量 uv,User View,访问的用户 一般来说,pv 或者 uv 的统计 ...

  5. 库存秒杀问题-redis解决方案- 接口限流

    <?php/** * Created by PhpStorm. * redis 销量超卖秒杀解决方案 * redis 文档:http://doc.redisfans.com/ * ab -n 1 ...

  6. 限流(三)Redis + lua分布式限流

    一.简介 1)分布式限流 如果是单实例项目,我们使用Guava这样的轻便又高性能的堆缓存来处理限流.但是当项目发展为多实例了以后呢?这时候我们就需要采用分布式限流的方式,分布式限流可以以redis + ...

  7. 【分布式架构】--- 基于Redis组件的特性,实现一个分布式限流

    分布式---基于Redis进行接口IP限流 场景 为了防止我们的接口被人恶意访问,比如有人通过JMeter工具频繁访问我们的接口,导致接口响应变慢甚至崩溃,所以我们需要对一些特定的接口进行IP限流,即 ...

  8. 分布式限流组件-基于Redis的注解支持的Ratelimiter

    原文:https://juejin.im/entry/5bd491c85188255ac2629bef?utm_source=coffeephp.com 在分布式领域,我们难免会遇到并发量突增,对后端 ...

  9. Redis除了做缓存--Redis做消息队列/Redis做分布式锁/Redis做接口限流

    1.用Redis实现消息队列 用命令lpush入队,rpop出队 Long size = jedis.lpush("QueueName", message);//返回存放的数据条数 ...

随机推荐

  1. Delphi Thread

    Thread给几点说明:1.MyThread的实例作为TForm1的成员变量2.不要使用Form1这个全局变量,线程中可要使用它的Handle,你可以在Form中创建MyThread的实例时把Hand ...

  2. WebStorm中部署网页到Tomcat

    1. 新建一个Deployment 在上面过程中Add Server弹窗下如下输入 2. 配置Deployment的Connection选项卡 3. 配置Deployment的Mappings选项卡 ...

  3. 【JVM】调优笔记1-----堆栈概念的对碰

    关于JVM的工作原理以及调优是一个向往已久的模块,终于有幸接触到:http://pengjiaheng.iteye.com/blog/518623 那就顺着这个思路,来梳理一下自己看到后的结论和感想. ...

  4. projecteuler----&gt;problem=11----Largest product in a grid

    In the 2020 grid below, four numbers along a diagonal line have been marked in red. 08 02 22 97 38 1 ...

  5. 【AS3 Coder】任务四:噪音的魅力(上)

    使用框架:AS3任务描述:使用AS3中BitmapData的noise方法以及perlinNoise方法构建自然景观效果以及其他一些比较cool的效果难度系数:2 本文章源码下载:www.iamsev ...

  6. org.hibernate.exception.ConstraintViolationException: could not delete:

    转自:http://fireinwind.iteye.com/blog/848515 异常描述: org.hibernate.exception.ConstraintViolationExceptio ...

  7. rails delegate机制

    Delegate是一种应用composite来代替extend的机制,可以有效地降低代码的耦合性. Rails 2.2增加了delegate方法,可以十分方便地实现delegate机制. 01.def ...

  8. 倍福TwinCAT(贝福Beckhoff)应用教程12.2 TwinCAT控制松下伺服 NC初步

    在前面我们已经学会了使用贝福自带的调试软件完成试运行,接下来是使用TWINCAT PLC实现这个功能,右击PLC添加一个PLC项目   在VISUs上右击添加一个HMI人机界面   目前PLC程序和人 ...

  9. css - 小程序样式

    /* * @Author: WJ_LONG * @Date: 2018-09-15 17:25:37 * @Last Modified by: WJ_LONG * @Last Modified tim ...

  10. sqlite3 sqlite3_prepare、sqlite3_step使用

    void select_by_prepare (sqlite3* pDB){ 51     int i; 52     int ret = 0; 53     int time; 54     cha ...