使用 Redis 实现分布式速率限制

作者 : 开心源码 本文共1800个字,预计阅读时间需要5分钟 发布时间: 2022-05-12 共133人阅读

问题

在许多应用中,对昂贵的资源的访问必需加以限制,此时速率限制是必不可少的。许多现代网络应用程序在多个进程和服务器上运行,状态需要被共享。一个理想的处理方案应该是高效、 快捷的,而不是依赖于被绑定到特定用户端的单个应用程序服务器(因为负载平衡) 或者本身持有任何状态。

处理方案

实现这一目标的一个简单有效的方法就是使用 Redis, 它有很多有用的数据结构和功能, 虽然实现速率限制只要要2个功能用: 一、在某个具体的键值上递增一个整数,二、给这个键值设置过期时间。

由于redis 有个单一的事件循环系统 (每个人每次在同一个时间只能执行一个操作),这是个原子操作, 也就是说无论有多少个用户端同时交互操作,对于同一个键值总有一个确定的数值。

这在对同一个资源进行多个速率限制的情况下通常是有利的, 由于这允许一些的破裂,以及更长的期限限制。例如每秒钟请求3次,没分钟请求20次。由于每个限制都是相对独立的,这就需要与其它限制分开进行单独的递增。

由于速率限制通常用在响应时间比较重要的资源(比方网页应用),所以尽量缩短速率限制的使用时间是非常有必要的。redis的最基本的应用就是发出命令,等待响应,而后发出另一个命令,如此往复。 这个花费是昂贵的,由于需要通过网络在应用程序和redis服务器之间屡次往返。因为在这个用例中,没有命令依赖其它命令的执行结果,这使得redis的一个叫做流水线技术的使用成为可能。这就是用户端缓存所有redis请求,而后把这写请求发送给redis,redis一次性返回所有的结果。

Redis不会维护用户端需要的限制的,由于redis会根据用户端设置的过期时间删除旧的记数。这消除了用户端统筹协调的需要,和删除竞争条件的可能性。

The Code

import redis

import time

def rate_limit_check(r, key, limits):

period_lengths = [_[0] for _ in sorted(limits.items())]

period_limits = [_[1] for _ in sorted(limits.items())]

pipe = r.pipeline()

for period_length in period_lengths:

current_period = int(time.time() / period_length)

redis_key = ‘rate_limit:{key}:{period_length}:{current_period}’.format(key=key, period_length=period_length, current_period=current_period)

pipe.incr(redis_key).expire(redis_key, period_length*3)

return not any(hits > period_limit for period_limit, hits in zip(period_limits, pipe.execute()[::2]))

if __name__ == ‘__main__’:

r = redis.Redis()

print rate_limit_check(r, ‘127.0.0.1’, {1: 3, 60: 20})

{1: 3, 60: 20} 意味着每秒钟3次的命中率是允许的,在任何限制下,都允许20次的命中。’127.0.0.1’在这里用作键值,虽然在真实的情况下,可能作为IP地址。更高级的用例将有一个全应用程序的速率限制,键值只有用户端的IP地址,以及一个为昂贵的终结点设置的特定终结点限制,这将用到用户端的IP地址和终结点,例如127.0.0.1+/login/。这些限制可以独立地设置。

return rate_limit_check(r, ‘127.0.0.1’, {1: 3, 60: 20}) and rate_limit_check(r, ‘127.0.0.1+/login/’, {1: 2, 60: 5})

这是一个用Python写的例子,它可以简单地移植到任何语言,只需这门语言包含Redis用户端库。

工作一到五年的java 开发工程师朋友可以加入我们Java架构交流群:760940986

群内提供 高可用,高并发,spring源码,mybatis源码,JVM,大数据,Netty等多个技术知识的架构视频资料

还有大把大牛在群内交流以及解答面试指导,问题答疑~~

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 使用 Redis 实现分布式速率限制

发表回复