分布式计数器限流
分布式计算器的限流是利用Redis来存储限流关键字key的统计计数。
这里有两种限流实现:Nginx Lua分布式计数器限流和RedisLua分布式计数器限流。
实战:Nginx Lua分布式计数器限流
本节以用户IP计数器的限流功能为例,实现单个IP在一定时间段内只能访问一定次数(如10次)的限流功能(如10 秒)。由于Redis是用来存储分布式访问计数的,所有功能都是通过Nginx Lua编程完成的,所以这种限流方式称为Nginx Lua分布式计数器限流。
本节Nginx Lua分布式计数器限流案例的架构如图9-3所示。
图9-3 Nginx Lua分布式计数器限流架构
首先介绍限流计数器脚本RedisKeyRateLimiter.lua,它负责完成访问计数和限流结果判断,其中涉及到Redis存储访问,具体代码如下:
以上代码位于练习项目LuaDemoProject中
在src/luaScript/module/ratelimit/文件夹下,文件名为access_auth_nginx.lua。 access_auth_nginx.lua在拼接计数器的key时使用Nginx的内置变量$remote_addr获取客户端的IP地址,最后将访问计数的key按如下格式存储在Redis中:
192.168.233.1这里是作者的本地测试IP,这个IP存储在Redis中的限流计数结果如图9-4所示。
图 9-4 此 IP 存储在 Redis 中的当前限制计数结果
在Nginx的访问请求处理阶段,使用access_auth_nginx.lua脚本限制请求流量的配置代码如下:
以上配置位于练习项目LuaDemoProject的src/conf/nginxratelimit.conf文件中。生效前需要替换openresty-start.sh脚本中的配置文件,然后重启Nginx。
接下来,开始限流自验证。
在上面的代码中,由于RedisKeyRateLimiter设置的限流规则是单个IP在10秒内限制访问10次,所以在验证时8位可逆计数器设计代码,浏览器刷新10次后限流。在浏览器中输入以下测试地址:
10秒内连续刷新,第6次输出如图9-5所示。
图 9-5 自验证时第 6 次刷新的输出
10 秒内持续刷新。发现第10次后请求被限制,说明Lua限流脚本工作正常,限流后的输出如图9-6所示。
图 9-6 自验证时刷新 10 次后的输出
上面的代码有两个缺陷:
(1)数据一致性问题:计数器的读取和自增是由两个Redis远程操作完成的,如果有多个网关同时限流,可能会出现数据一致性问题。
p>
(2)性能问题:同样的限流操作需要多次访问Redis,并且有多次网络传输,大大降低了限流性能。
实战:Redis Lua分布式计数器限流
众所周知,Redis 允许将 Lua 脚本加载到 Redis 服务器中执行,并且可以调用大部分 Redis 命令,并且 Redis 保证了脚本的原子性。由于Redis是用来存储分布式访问计数的,而限流计数器的Lua脚本是通过Redis来执行的8位可逆计数器设计代码,所以这种限流方式称为RedisLua分布式计数器限流。
本节Redis Lua分布式计数器限流案例的架构如图9-7所示。
图9-7 Redis Lua分布式计数器限流架构
首先我们看一下限流计数器脚本redis_rate_limiter.lua。该脚本负责完成对访问计数和限流结果的判断,其中会涉及到Redis计数的存储访问。需要注意的是,脚本将在 Redis 中加载和执行。
计数器脚本redis_rate_limiter.lua的代码如下:
以上代码位于练习项目LuaDemoProject中
在src/luaScript/module/ratelimit/文件夹下,文件名为redis_rate_limiter.lua。在调用该脚本之前,必须先将其加载到Redis中,并获取加载后的sha1代码,供Nginx上的限流脚本access_auth_evalsha.lua使用。
将redis_rate_limiter.lua加载到Redis中的Linux shell命令如下:
然后看access_auth_evalsha.lua限流脚本,它使用Redis的evalsha操作命令远程访问Redis上加载的redis_rate_limiter.lua访问计算器脚本,完成对同一IP的限流操作。
access_auth_evalsha.lua限流脚本代码如下:
以上代码位于练习项目LuaDemoProject中
在src/luaScript/module/ratelimit/文件夹中,文件名为access_auth_evalsha.lua。在Nginx的访问请求处理阶段,使用access_auth_evalsha.lua脚本限制请求流量的配置如下:
以上配置位于练习项目LuaDemoProject中
在src/conf/nginx-ratelimit.conf文件中,需要替换openresty-start.sh脚本中的配置文件才能生效,然后重启Nginx。
然后启动限流自验证。在浏览器中访问以下地址:
10 秒内持续刷新。发现请求在第10次后被限流,说明Redis内部的Lua限流脚本工作正常,限流后的输出如图9-8所示。
图 9-8 自验证时刷新 10 次后的输出
通过将Lua脚本加载到Redis中执行有以下优点:
(1)减少网络开销:不使用Lua的代码需要向Redis发送多个请求,而脚本只需要一次,减少网络传输。
(2)原子操作:Redis将整个脚本作为一个原子执行,无需担心并发,无事务。
(3)重用:只要不重启Redis,脚本加载后会一直缓存在Redis中,其他客户端可以通过sha1编码执行。
本文讲解的内容是高并发核心编程、限流原理与实战、分布式计数器限流
下一篇会讲解高并发核心编程、限流原理和实战,详细讲解Nginx漏桶限流;
觉得文章不错的朋友可以转发这篇文章关注小编;
感谢您的支持!
这篇文章是我希望天上没有虫子分享给大家的。如果你有什么要分享的,你可以分享。想了解更多,可以在微信公众号找我。我会等你的。
请登录后发表评论
注册
社交帐号登录