V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
dzdh
V2EX  ›  Go 编程语言

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

  •  
  •   dzdh · 2022-08-01 11:41:18 +08:00 · 1719 次点击
    这是一个创建于 848 天前的主题,其中的信息可能已经有所发展或是发生改变。

    场景:

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

    22 条回复    2022-08-02 18:23:55 +08:00
    bais
        1
    bais  
       2022-08-01 11:45:11 +08:00
    建议直接拿 go 重写....
    dzdh
        2
    dzdh  
    OP
       2022-08-01 11:46:48 +08:00
    @bais

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

    想要的是:

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

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

    必须要 200 其实有点过。

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

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

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

    还有,限流的功能,一般是会有注入延迟的。这个还是应该加一下。
    dzdh
        15
    dzdh  
    OP
       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
        16
    gengchun  
       2022-08-02 13:20:52 +08:00
    @dzdh 你前面用 go 怎么实现的不是说去看 redis 吗?怎么又变成 fpm worker 了?你用 golang 怎么实现的?而且看 fpm 状态不是有 status 页面吗?

    而且你都已经说是秒杀了,还要动态变更 fpm worker 数量?你不觉得很矛盾吗?
    dzdh
        17
    dzdh  
    OP
       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
        18
    yc8332  
       2022-08-02 16:45:29 +08:00
    @dzdh 那没必要啊,把 php-fpm 弄成静态的就行了。假设 200 个,你就 nginx 开 200 连接,多了不让进。这样不就一直和 php-fpm 同步了吗?不过这样体验应该不怎么样,本身 php-fpm 也支持排队的。
    dzdh
        19
    dzdh  
    OP
       2022-08-02 17:13:48 +08:00
    @yc8332

    对对对。就是这个。

    比如说可能是这样,假设 200 个 staticworker 也好动态也罢。有没有一种可能是一旦到达 200 的后续请求立刻返回一个 code 叫 waiting, sid=hashid ,然后前端在一直轮询。lua 能不能把请求暂存,等 worker 空闲了再放过去。前端轮询。这样总比 nginx-fpm 然后一直无限等最后返回 504 好吧。
    dzdh
        20
    dzdh  
    OP
       2022-08-02 17:14:32 +08:00
    @yc8332
    还有就是性能突发实例(套路云)成本相对便宜点。所以现在是动态的。
    yc8332
        21
    yc8332  
       2022-08-02 18:20:38 +08:00
    @dzdh 那看你的突发流量是多少了。如果不是海量还好吧,直接返回错误 php-fpm 问题不大,搞个 redis 自增就限流,超了直接返回你要的内容。
    yc8332
        22
    yc8332  
       2022-08-02 18:23:55 +08:00
    就是你把并发限制开小一点。。剩下的进程去处理其他请求
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3623 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 00:48 · PVG 08:48 · LAX 16:48 · JFK 19:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.