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

发布于 1周前 作者 songsunli 来自 Go语言

场景:

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 次。每一个用户的每一次请求都正常返回友好提示。


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

更多关于Golang Go语言中 nginx 怎么根据全局连接数来做全局总的限流并自定义相应信息的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

23 回复

建议直接拿 go 重写…

更多关于Golang Go语言中 nginx 怎么根据全局连接数来做全局总的限流并自定义相应信息的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html




历史包袱…emmmmmm 一时半会儿重写不了… hhhh

把 nginx 换成 openresty 呗,access 阶段加个 lua 脚本判断下就行吧,openresty 用的人也不少,稳定性不用说,总比自己再用 go 来写 fcgi 靠谱实现也容易太多了吧

秒杀活动开始前扩容 1000 台机器,结束后再释放掉。我前司就是这样做


看了。

想要的是:

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

收到请求,不做动作。
请求发给 fpm ,等待结果时,限流器+1
fpm 返回结果,限流器-1

502 是你 php 挂了吧。。

除非 nginx 那边完全不能动,不然,我觉得没有必要中间再加一个。

必须要 200 其实有点过。

直接用 nginx 的话,就是用 lua 写 ngx.headers/ngx.say()/ngx.exit(200) 这样。



200 只是其中之一要求,更重要的是和 fpm 相同数量个的限流器

是不再接收新请求

上 lua_moudle 里面有 限流模块

可以动态获取 fpm 当前 worker 吗

请问,openresty 的 vhost 里怎么用 lua 写一些自定义的 403 页面啊,求 demo 谢谢

你要说你们公司的运维不接你的需求,你不想用 nginx ,要自己写,这个其实没有什么问题。但没有必要在不了解 nginx 的情况下,说 nginx 实现不了。特别是这么多人已经说了可以做。

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

还有,限流的功能,一般是会有注入延迟的。这个还是应该加一下。



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

lua 当然可以读 redis 。但是现在问题是想实现 nginx 接收并处理的请求数和 fpm 的 worker 数量能保持同步,即有几个 fpm workernginx 就只能接收并处理几个请求。而新的问题是,fpm 的 worker 是动态的,要在 lua 中 ps aux|grep fpm|wc -l 吗?

你前面用 go 怎么实现的不是说去看 redis 吗?怎么又变成 fpm worker 了?你用 golang 怎么实现的?而且看 fpm 状态不是有 status 页面吗?

而且你都已经说是秒杀了,还要动态变更 fpm worker 数量?你不觉得很矛盾吗?



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

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

想实现,不让用户等待,当前在流量高(没有空闲的 worker )就直接返回友好提示。不浪费一个 worker 也不多收一个请求。

那没必要啊,把 php-fpm 弄成静态的就行了。假设 200 个,你就 nginx 开 200 连接,多了不让进。这样不就一直和 php-fpm 同步了吗?不过这样体验应该不怎么样,本身 php-fpm 也支持排队的。



对对对。就是这个。

比如说可能是这样,假设 200 个 staticworker 也好动态也罢。有没有一种可能是一旦到达 200 的后续请求立刻返回一个 code 叫 waiting, sid=hashid ,然后前端在一直轮询。lua 能不能把请求暂存,等 worker 空闲了再放过去。前端轮询。这样总比 nginx-fpm 然后一直无限等最后返回 504 好吧。


还有就是性能突发实例(套路云)成本相对便宜点。所以现在是动态的。

那看你的突发流量是多少了。如果不是海量还好吧,直接返回错误 php-fpm 问题不大,搞个 redis 自增就限流,超了直接返回你要的内容。

就是你把并发限制开小一点。。剩下的进程去处理其他请求

在Golang应用中,通过Nginx根据全局连接数进行限流并自定义响应信息,可以结合Nginx的第三方模块(如ngx_http_limit_conn_module)和Lua脚本来实现。以下是一个基本的实现思路:

  1. 启用并配置ngx_http_limit_conn_module

    • 在Nginx配置文件中启用连接限制模块。
    • 定义一个变量来存储全局连接数,并通过limit_conn_zone指令来限制连接数。
    • 使用limit_conn指令在特定的location中限制连接。
  2. 使用Lua脚本进行更复杂的逻辑处理

    • 安装并配置Nginx的Lua模块(如ngx_lua)。
    • 编写Lua脚本,通过共享字典(shared dict)来维护全局连接数。
    • 在Lua脚本中实现自定义的限流逻辑,当连接数超过限制时,返回自定义的响应信息。
  3. 集成Golang应用

    • Golang应用作为后端服务,通过Nginx反向代理来处理请求。
    • Nginx配置中的location块将请求转发到Golang应用的后端服务器。
    • 确保Nginx和Golang应用之间的通信顺畅,且Nginx能够正确解析和处理Golang应用的响应。
  4. 测试与优化

    • 在实际环境中测试配置,确保限流逻辑和自定义响应信息按预期工作。
    • 根据测试结果调整Nginx和Lua脚本的配置,以优化性能和可靠性。

通过上述步骤,你可以在Golang应用中实现基于Nginx全局连接数的限流,并自定义响应信息。

回到顶部