nginx 怎么根据全局连接数来做全局总的限流并自定义相应信息

2022-08-01 11:41:18 +08:00
 dzdh

场景:

php-fpm 应用。秒杀活动。偶尔一次不经常。 nginx->fpm 直接 502

问题:

nginx 限流好像是根据某个 ip 限制或者即便全局限制不能定义响应内容?

疑惑:

一共开了 100 个 php-fpm 进程,那就限制 nginx 的全局并发连接数为 100 ?或者超过 100 ,但是正在处理的请求超过 100 后直接返回 http 200 contnet:json: code:xxxx,msg:当前活动爆满请稍后再试.. ?

尝试用 go 写了个 fcgiclient (所以发到了 go 节点),由 go 在 servehttp 中判断全局 redis 计数器或单机计数器,然后流量由 go 接管做内部队列,返回 sid ( sessionid ),前端轮询 sid 。

为啥不用 php 做,因为流量就到不了 fpm ,nginx->fpm 直接就 502 了

目标:

所有流量都必须正确响应 200 ,5xx 响应为 0 次。每一个用户的每一次请求都正常返回友好提示。

1555 次点击
所在节点    Go 编程语言
22 条回复
bais
2022-08-01 11:45:11 +08:00
建议直接拿 go 重写....
dzdh
2022-08-01 11:46:48 +08:00
@bais

历史包袱..emmmmmm 一时半会儿重写不了... hhhh
sujin190
2022-08-01 12:08:56 +08:00
把 nginx 换成 openresty 呗,access 阶段加个 lua 脚本判断下就行吧,openresty 用的人也不少,稳定性不用说,总比自己再用 go 来写 fcgi 靠谱实现也容易太多了吧
xylophone21
2022-08-01 12:17:19 +08:00
sadfQED2
2022-08-01 12:19:29 +08:00
秒杀活动开始前扩容 1000 台机器,结束后再释放掉。我前司就是这样做
dzdh
2022-08-01 13:21:17 +08:00
@xylophone21
看了。

想要的是:

限流 N 对应 X 个 FPM 进程数。当当前连接数 Y 大于等于 正在处理的 FPM 请求时,返回 200 响应自定义内容。

收到请求,不做动作。
请求发给 fpm ,等待结果时,限流器+1
fpm 返回结果,限流器-1
yc8332
2022-08-01 17:15:14 +08:00
502 是你 php 挂了吧。。
gengchun
2022-08-01 18:11:05 +08:00
除非 nginx 那边完全不能动,不然,我觉得没有必要中间再加一个。

必须要 200 其实有点过。

直接用 nginx 的话,就是用 lua 写 ngx.headers/ngx.say()/ngx.exit(200) 这样。
dzdh
2022-08-02 08:54:58 +08:00
@gengchun

200 只是其中之一要求,更重要的是和 fpm 相同数量个的限流器
dzdh
2022-08-02 08:56:17 +08:00
@yc8332 是不再接收新请求
lazyfighter
2022-08-02 09:29:28 +08:00
上 lua_moudle 里面有 限流模块
dzdh
2022-08-02 09:31:12 +08:00
@lazyfighter 可以动态获取 fpm 当前 worker 吗
xx3122
2022-08-02 10:55:14 +08:00
@gengchun 请问,openresty 的 vhost 里怎么用 lua 写一些自定义的 403 页面啊,求 demo 谢谢
gengchun
2022-08-02 12:07:07 +08:00
@dzdh 你要说你们公司的运维不接你的需求,你不想用 nginx ,要自己写,这个其实没有什么问题。但没有必要在不了解 nginx 的情况下,说 nginx 实现不了。特别是这么多人已经说了可以做。

这种要自己实现,还是先看一下已经有成熟的通用解决方案。lua 去读 redis 里的配置比较少见,但是并不是不可以。k8s ingress nginx 就是类似的,当然不是 redis 。这类方案落地久的,应该有十多年了。

还有,限流的功能,一般是会有注入延迟的。这个还是应该加一下。
dzdh
2022-08-02 12:33:02 +08:00
@gengchun

我没说过 [nginx 实现 [不] 了] 而是在寻找 nginx 怎么做的方案。

lua 当然可以读 redis 。但是现在问题是想实现 nginx 接收并处理的请求数和 fpm 的 worker 数量能保持同步,即有几个 fpm workernginx 就只能接收并处理几个请求。而新的问题是,fpm 的 worker 是动态的,要在 lua 中 ps aux|grep fpm|wc -l 吗?
gengchun
2022-08-02 13:20:52 +08:00
@dzdh 你前面用 go 怎么实现的不是说去看 redis 吗?怎么又变成 fpm worker 了?你用 golang 怎么实现的?而且看 fpm 状态不是有 status 页面吗?

而且你都已经说是秒杀了,还要动态变更 fpm worker 数量?你不觉得很矛盾吗?
dzdh
2022-08-02 16:44:44 +08:00
@gengchun

设想的是 go 可以做个 fcgiclient 充当 nginx 的角色连接 php-fpm ,做整体的限流控制,无论大流量还是小流量都可以灵活控制。而且还可以开协程每毫秒每秒去刷 fpmstatus 获取当前的 worker 数量。

动态 fpmworker 是因为 php-fpm 配置本身是 pm=dynamic 。秒杀不是无时不刻二十四小时都在秒杀,隔三岔五有一次。争抢型实例平常一两百个 worker 足够了,有秒杀它自己扩到五六百。因此它是动态的。

想实现,不让用户等待,当前在流量高(没有空闲的 worker )就直接返回友好提示。不浪费一个 worker 也不多收一个请求。
yc8332
2022-08-02 16:45:29 +08:00
@dzdh 那没必要啊,把 php-fpm 弄成静态的就行了。假设 200 个,你就 nginx 开 200 连接,多了不让进。这样不就一直和 php-fpm 同步了吗?不过这样体验应该不怎么样,本身 php-fpm 也支持排队的。
dzdh
2022-08-02 17:13:48 +08:00
@yc8332

对对对。就是这个。

比如说可能是这样,假设 200 个 staticworker 也好动态也罢。有没有一种可能是一旦到达 200 的后续请求立刻返回一个 code 叫 waiting, sid=hashid ,然后前端在一直轮询。lua 能不能把请求暂存,等 worker 空闲了再放过去。前端轮询。这样总比 nginx-fpm 然后一直无限等最后返回 504 好吧。
dzdh
2022-08-02 17:14:32 +08:00
@yc8332
还有就是性能突发实例(套路云)成本相对便宜点。所以现在是动态的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/869910

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX