43 | 灵活实现动态限流限速,其实没有那么难
温铭
该思维导图由 AI 生成,仅供参考
你好,我是温铭。
前面的课程中,我为你介绍了漏桶和令牌桶算法,它们都是应对突发流量的常用手段。同时,我们也学习了如何通过 Nginx 配置文件的方式,来实现对请求的限流限速。不过很显然,使用 Nginx 配置文件的方式,仅仅停留在可用的层面,距离好用还是有不小的距离的。
第一个问题便是,限速的 key 被限制在 Nginx 的变量范围内,不能灵活地设置。比如,根据不同的省份和不同的客户端渠道,来设置不同的限速阈值,这种常见的需求用 Nginx 就没有办法实现。
另外一个更大的问题是,不能动态地调整速率,每次修改都需要重载 Nginx 服务,这一点我们在上节课的最后也提到过。这样一来,根据不同的时间段限速这种需求,就只能通过外置的脚本来蹩脚地实现了。
要知道,技术是为业务服务的,同时,业务也在驱动着技术的进步。在 Nginx 诞生的时代,并没有什么动态调整配置的需求,更多的是反向代理、负载均衡、低内存占用等类似的需求,在驱动着 Nginx 的成长。在技术的架构和实现上,并没有人能够预料到,在移动互联网、IoT、微服务等场景下,对于动态和精细控制的需求会大量爆发。
而 OpenResty 使用 Lua 脚本的方式,恰好能够弥补 Nginx 在这方面的缺失,形成了有效的互补。这也是 OpenResty 被广泛地用于替换 Nginx 的根源所在。在后面几节课中,我会为你继续介绍更多 OpenResty 中动态的场景和示例。今天,就让我们先来看下,如何使用 OpenResty 来实现动态限流和限速。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
使用OpenResty实现动态限流和限速是一种灵活的解决方案。本文介绍了OpenResty通过Lua脚本来弥补Nginx配置文件在动态调整速率方面的不足。详细介绍了在OpenResty中使用limit-req、limit-count和limit-conn这三种不同的限制方式,以及如何组合使用这些限速器来满足复杂的业务需求。通过示例代码和解释,读者可以了解如何使用这些限速器来限制请求速率、请求次数和并发连接数,并且可以根据不同的需求设置不同的限速阈值和key,实现灵活的限流限速效果。文章还提到了limit.traffic的功能,可以管理任何有incoming和uncommit接口的限速器。最后,作者留下了一个作业题,鼓励读者分享和交流。整体而言,本文通过介绍OpenResty的限速器的使用方法,为读者提供了一种灵活实现动态限流限速的解决方案。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《OpenResty 从入门到实战》,新⼈⾸单¥59
《OpenResty 从入门到实战》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(8)
- 最新
- 精选
- FF请教个问题。如果把 lua 模块用 lua_by_* 的方式引入 ngx 的 location 指令块里面,那每次请求,都会执行一遍 lua 模块中的 top level 变量和那些不是定义在函数中的全局代码块吗 ? 我测了一下好像每次请求都执行一遍 ?那全局变量不是每次请求都要初始化一次啊 ?这样的话如果想在函数执行的上下文中再将一些数据保存到全局变量里面,那不是没办法用全局变量实现了 ? 盼温老师解惑。
作者回复: 如果你要使用全局变量, 可以写到 init 阶段,这样就只会执行一遍了。但是全局变量是不推荐使用的,在最新的OpenResty 1.15.8 版本中,增加了全局变量的检测,如果发现就会打印一条 warn 级别的日志。 如果你希望保持函数上下文的全局数据,可以试试模块的 top level 变量。 同时,在你测试的时候,记得保持 lua_code_cache on,并且不要在 Windows 下测试。
2019-09-032 - wusiration老师,限制器的组合小节里面的代码,limit_req重复了,应该有一个limit_count。 课后习题: local limit_rate = require "resty.limit.rate" local limit_count = require "resty.limit.count" local limit_conn = require "resty.limit.conn" local lim_rate, err = limit_rate.new("my_rate_store", 100, 6000, 2) -- 将resty.limit.req替换成resty.limit.rate即可 local lim_count, err = limit_count.new("my_count_store", 200, 100) local lim_conn, err = limit_conn.new("my_conn_store", 1000, 1000, 0.5) local limiters = {lim_rate, lim_count, lim_conn} local host = ngx.var.host local client = ngx.var.binary_remote_addr local keys = {host, client, client} local delay, err = limit_traffic.combine(limiters, keys, states)
作者回复: 多谢指正,看的真仔细👍
2019-09-022 - Sir老师好,我把这段代码也在location中,是不是相当于我每次请求都new了一次,比较迷惑 local lim, err = limit_req.new("my_limit_req_store", 200, 100)
作者回复: 这种对象的 new 一般都是放在 module 的 top level 中,避免重复创建
2019-09-182 - jackstraw老师,这里的限流都是针对一台NGINX的,我们的业务是N台NGINX同时提供服务的,这种情况下可以怎么做限流啊?2019-12-2019
- 温暖岁月老师,请教个问题,对于limit_rate限速配置,如果是动态去改这个值,对于已经在下载的连接来说是没有作用的,该如何让已经连上的也生效?2020-12-291
- 张靳之前有用过limit-req方法,tps比较高的时候不是很准,老师有遇到过吗2022-02-08
- 春夏秋冬老师,我想要将限速限流参数放置在memcached中,每次请求时通过读取相关的配置来达到动态配置限流限速的功能(代码如下),当我扩大memcached中limit_num值后,发现返回的剩余的调用次数(remaining)并未发生变化,其中原理并不清楚,期望老师解惑或者提供更好的动态修改限流配置的方向 local memcached = require "resty.memcached" local memc, err = memcached:new() memc:set_timeout(1000) local ok, err = memc:connect("127.0.0.1", 11211) local limit_num, flags, err = memc:get("limit_num") local limit_time, flags, err = memc:get("limit_time") local limit_count = require "resty.limit.count" local lim, err = limit_count.new("global_count_limit", tonumber(limit_num), tonumber(limit_time)) local delay, remaining = lim:incoming('global', true) if not delay then return ngx.exit(503) end ngx.say(remaining)2019-11-101
- 许童童跟着老师一起精进。2019-09-02
收起评论