场景:
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 次。每一个用户的每一次请求都正常返回友好提示。
1
bais 2022-08-01 11:45:11 +08:00
建议直接拿 go 重写....
|
3
sujin190 2022-08-01 12:08:56 +08:00 1
把 nginx 换成 openresty 呗,access 阶段加个 lua 脚本判断下就行吧,openresty 用的人也不少,稳定性不用说,总比自己再用 go 来写 fcgi 靠谱实现也容易太多了吧
|
4
xylophone21 2022-08-01 12:17:19 +08:00
|
5
sadfQED2 2022-08-01 12:19:29 +08:00 via Android
秒杀活动开始前扩容 1000 台机器,结束后再释放掉。我前司就是这样做
|
6
dzdh OP @xylophone21
看了。 想要的是: 限流 N 对应 X 个 FPM 进程数。当当前连接数 Y 大于等于 正在处理的 FPM 请求时,返回 200 响应自定义内容。 收到请求,不做动作。 请求发给 fpm ,等待结果时,限流器+1 fpm 返回结果,限流器-1 |
7
yc8332 2022-08-01 17:15:14 +08:00
502 是你 php 挂了吧。。
|
8
gengchun 2022-08-01 18:11:05 +08:00
除非 nginx 那边完全不能动,不然,我觉得没有必要中间再加一个。
必须要 200 其实有点过。 直接用 nginx 的话,就是用 lua 写 ngx.headers/ngx.say()/ngx.exit(200) 这样。 |
11
lazyfighter 2022-08-02 09:29:28 +08:00
上 lua_moudle 里面有 限流模块
|
12
dzdh OP @lazyfighter 可以动态获取 fpm 当前 worker 吗
|
13
xx3122 2022-08-02 10:55:14 +08:00
@gengchun 请问,openresty 的 vhost 里怎么用 lua 写一些自定义的 403 页面啊,求 demo 谢谢
|
14
gengchun 2022-08-02 12:07:07 +08:00
@dzdh 你要说你们公司的运维不接你的需求,你不想用 nginx ,要自己写,这个其实没有什么问题。但没有必要在不了解 nginx 的情况下,说 nginx 实现不了。特别是这么多人已经说了可以做。
这种要自己实现,还是先看一下已经有成熟的通用解决方案。lua 去读 redis 里的配置比较少见,但是并不是不可以。k8s ingress nginx 就是类似的,当然不是 redis 。这类方案落地久的,应该有十多年了。 还有,限流的功能,一般是会有注入延迟的。这个还是应该加一下。 |
15
dzdh OP @gengchun
我没说过 [nginx 实现 [不] 了] 而是在寻找 nginx 怎么做的方案。 lua 当然可以读 redis 。但是现在问题是想实现 nginx 接收并处理的请求数和 fpm 的 worker 数量能保持同步,即有几个 fpm workernginx 就只能接收并处理几个请求。而新的问题是,fpm 的 worker 是动态的,要在 lua 中 ps aux|grep fpm|wc -l 吗? |
16
gengchun 2022-08-02 13:20:52 +08:00
@dzdh 你前面用 go 怎么实现的不是说去看 redis 吗?怎么又变成 fpm worker 了?你用 golang 怎么实现的?而且看 fpm 状态不是有 status 页面吗?
而且你都已经说是秒杀了,还要动态变更 fpm worker 数量?你不觉得很矛盾吗? |
17
dzdh OP @gengchun
设想的是 go 可以做个 fcgiclient 充当 nginx 的角色连接 php-fpm ,做整体的限流控制,无论大流量还是小流量都可以灵活控制。而且还可以开协程每毫秒每秒去刷 fpmstatus 获取当前的 worker 数量。 动态 fpmworker 是因为 php-fpm 配置本身是 pm=dynamic 。秒杀不是无时不刻二十四小时都在秒杀,隔三岔五有一次。争抢型实例平常一两百个 worker 足够了,有秒杀它自己扩到五六百。因此它是动态的。 想实现,不让用户等待,当前在流量高(没有空闲的 worker )就直接返回友好提示。不浪费一个 worker 也不多收一个请求。 |
18
yc8332 2022-08-02 16:45:29 +08:00
@dzdh 那没必要啊,把 php-fpm 弄成静态的就行了。假设 200 个,你就 nginx 开 200 连接,多了不让进。这样不就一直和 php-fpm 同步了吗?不过这样体验应该不怎么样,本身 php-fpm 也支持排队的。
|
19
dzdh OP @yc8332
对对对。就是这个。 比如说可能是这样,假设 200 个 staticworker 也好动态也罢。有没有一种可能是一旦到达 200 的后续请求立刻返回一个 code 叫 waiting, sid=hashid ,然后前端在一直轮询。lua 能不能把请求暂存,等 worker 空闲了再放过去。前端轮询。这样总比 nginx-fpm 然后一直无限等最后返回 504 好吧。 |
21
yc8332 2022-08-02 18:20:38 +08:00
@dzdh 那看你的突发流量是多少了。如果不是海量还好吧,直接返回错误 php-fpm 问题不大,搞个 redis 自增就限流,超了直接返回你要的内容。
|
22
yc8332 2022-08-02 18:23:55 +08:00
就是你把并发限制开小一点。。剩下的进程去处理其他请求
|