【问题标题】:Nginx: In which order rate limiting and caching are executed?Nginx:限速和缓存按什么顺序执行?
【发布时间】:2018-05-02 06:56:21
【问题描述】:

我想使用 nginx 进行速率限制和缓存。

nginx 以什么顺序应用它们?换句话说,它是仅限制对上游服务器的请求还是所有请求(包括缓存 HIT)?

如何更改此顺序?我认为可以通过两个 server 上下文来改变它。因此,例如,在一个 server 上执行缓存。它有第二个server 上下文作为上游。第二个限制对“真实”上游的请求。但这可能不是最有效的方法...

【问题讨论】:

  • 缓存和限速是怎么做的?

标签: caching nginx rate-limiting nginx-reverse-proxy


【解决方案1】:

如果您有网络负载均衡器,那么您必须在两台服务器上实现速率和缓存。

限速是这样的。

location /login/ {
    limit_req zone=mylimit burst=20;
 
    proxy_pass http://my_upstream;
}

burst 参数定义了客户端可以发出多少请求超过区域指定的速率(对于我们的示例 mylimit 区域,速率限制为每秒 10 个请求,或每 100 毫秒 1 个)。在前一个请求放入队列后 100 毫秒内到达的请求,这里我们将队列大小设置为 20。

这意味着如果 21 个请求同时来自给定 IP 地址,NGINX 会立即将第一个请求转发到上游服务器组,并将剩余的 20 个放入队列中。然后它每 100 毫秒转发一个排队请求,并且仅当传入请求使排队请求的数量超过 20 时才向客户端返回 503。 现在,如果您只在一台服务器上限制评级,那么发送到不同服务器的两个后续请求将会出现问题。 所有缓存变量也需要同步。您需要 Redis 或持久存储来进行缓存。

https://www.nginx.com/blog/rate-limiting-nginx/

【讨论】:

    【解决方案2】:

    请求处理

    Nginx 请求处理是通过许多不同的阶段完成的,每个阶段都有一个或多个处理程序。模块可以注册以在特定阶段运行。

    http://www.nginxguts.com/phases/ http://nginx.org/en/docs/dev/development_guide.html#http_phases

    速率限制

    ngx_http_limit_req_module 在预访问阶段应用速率限制。来自ngx_http_limit_req_module.c:

    h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
    

    缓存

    缓存是稍后完成的,我认为在内容阶段。

    通过查看代码或文档,我无法完全弄清楚这一点。但我能够通过调试构建来证明这一点。我的配置有速率限制每秒 1 个请求,并启用缓存。请参阅我的日志中的以下摘录。

    缓存请求

    ...
    2020/08/01 11:11:07 [debug] 17498#0: *7 http header done
    2020/08/01 11:11:07 [debug] 17498#0: *7 rewrite phase: 0
    2020/08/01 11:11:07 [debug] 17498#0: *7 test location: "/"
    2020/08/01 11:11:07 [debug] 17498#0: *7 using configuration "=/"
    2020/08/01 11:11:07 [debug] 17498#0: *7 http cl:-1 max:1048576
    2020/08/01 11:11:07 [debug] 17498#0: *7 rewrite phase: 2
    2020/08/01 11:11:07 [debug] 17498#0: *7 post rewrite phase: 3
    2020/08/01 11:11:07 [debug] 17498#0: *7 generic phase: 4
    2020/08/01 11:11:07 [debug] 17498#0: *7 http script var: ....
    2020/08/01 11:11:07 [debug] 17498#0: shmtx lock
    2020/08/01 11:11:07 [debug] 17498#0: shmtx unlock
    2020/08/01 11:11:07 [debug] 17498#0: *7 limit_req[0]: 0 0.000
    2020/08/01 11:11:07 [debug] 17498#0: *7 generic phase: 5
    2020/08/01 11:11:07 [debug] 17498#0: *7 access phase: 6
    2020/08/01 11:11:07 [debug] 17498#0: *7 access phase: 7
    2020/08/01 11:11:07 [debug] 17498#0: *7 post access phase: 8
    2020/08/01 11:11:07 [debug] 17498#0: *7 generic phase: 9
    2020/08/01 11:11:07 [debug] 17498#0: *7 generic phase: 10
    2020/08/01 11:11:07 [debug] 17498#0: *7 http init upstream, client timer: 0
    2020/08/01 11:11:07 [debug] 17498#0: *7 http cache key: "http://127.0.0.1:9000"
    2020/08/01 11:11:07 [debug] 17498#0: *7 http cache key: "/"
    2020/08/01 11:11:07 [debug] 17498#0: *7 add cleanup: 00005609F7C51578
    2020/08/01 11:11:07 [debug] 17498#0: shmtx lock
    2020/08/01 11:11:07 [debug] 17498#0: shmtx unlock
    2020/08/01 11:11:07 [debug] 17498#0: *7 http file cache exists: 0 e:1
    2020/08/01 11:11:07 [debug] 17498#0: *7 cache file: "/home/poida/src/nginx-1.15.6/objs/cache/157d4d91f488c05ff417723d74d65b36"
    2020/08/01 11:11:07 [debug] 17498#0: *7 add cleanup: 00005609F7C46810
    2020/08/01 11:11:07 [debug] 17498#0: *7 http file cache fd: 12
    2020/08/01 11:11:07 [debug] 17498#0: *7 read: 12, 00005609F7C46890, 519, 0
    2020/08/01 11:11:07 [debug] 17498#0: *7 http upstream cache: 0
    2020/08/01 11:11:07 [debug] 17498#0: *7 http proxy status 200 "200 OK"
    2020/08/01 11:11:07 [debug] 17498#0: *7 http proxy header: "Server: SimpleHTTP/0.6 Python/3.8.5"
    2020/08/01 11:11:07 [debug] 17498#0: *7 http proxy header: "Date: Sat, 01 Aug 2020 01:11:03 GMT"
    2020/08/01 11:11:07 [debug] 17498#0: *7 http proxy header: "Content-type: text/html; charset=utf-8"
    2020/08/01 11:11:07 [debug] 17498#0: *7 http proxy header: "Content-Length: 340"
    2020/08/01 11:11:07 [debug] 17498#0: *7 http proxy header done
    2020/08/01 11:11:07 [debug] 17498#0: *7 http file cache send: /home/poida/src/nginx-1.15.6/objs/cache/157d4d91f488c05ff417723d74d65b36
    2020/08/01 11:11:07 [debug] 17498#0: *7 posix_memalign: 00005609F7C46DC0:4096 @16
    2020/08/01 11:11:07 [debug] 17498#0: *7 HTTP/1.1 200 OK
    ...
    

    速率限制请求

    ...
    2020/08/01 11:17:04 [debug] 17498#0: *10 http header done
    2020/08/01 11:17:04 [debug] 17498#0: *10 rewrite phase: 0
    2020/08/01 11:17:04 [debug] 17498#0: *10 test location: "/"
    2020/08/01 11:17:04 [debug] 17498#0: *10 using configuration "=/"
    2020/08/01 11:17:04 [debug] 17498#0: *10 http cl:-1 max:1048576
    2020/08/01 11:17:04 [debug] 17498#0: *10 rewrite phase: 2
    2020/08/01 11:17:04 [debug] 17498#0: *10 post rewrite phase: 3
    2020/08/01 11:17:04 [debug] 17498#0: *10 generic phase: 4
    2020/08/01 11:17:04 [debug] 17498#0: *10 http script var: ....
    2020/08/01 11:17:04 [debug] 17498#0: shmtx lock
    2020/08/01 11:17:04 [debug] 17498#0: shmtx unlock
    2020/08/01 11:17:04 [debug] 17498#0: *10 limit_req[0]: -3 0.707
    2020/08/01 11:17:04 [error] 17498#0: *10 limiting requests, excess: 0.707 by zone "mylimit", client: 127.0.0.1, server: , request: "GET / HTTP/1.1", host: "localhost:8080"
    2020/08/01 11:17:04 [debug] 17498#0: *10 http finalize request: 503, "/?" a:1, c:1
    2020/08/01 11:17:04 [debug] 17498#0: *10 http special response: 503, "/?"
    2020/08/01 11:17:04 [debug] 17498#0: *10 http set discard body
    2020/08/01 11:17:04 [debug] 17498#0: *10 HTTP/1.1 503 Service Temporarily Unavailable
    ...
    

    对于速率受限的请求,处理在服务器尝试生成内容或检查缓存之前停止。

    TL;DR;在缓存之前首先应用速率限制。

    【讨论】:

    • 所以大概需要有两个 nginx 服务器进程(即,具有完全独立的配置并作为两个独立的守护进程启动)?如果是这样的话,我很惊讶这会如此笨拙。
    【解决方案3】:

    NGINX

    How does Nginx rate limiter works

    NGINX 限速采用漏桶算法,广泛应用于 用于电信和分组交换计算机网络 在带宽有限时处理突发性。类比是 顶部倒入水,底部漏水的桶; 如果注入水的速度超过注入水的速度 漏水,水桶溢出。在请求处理方面,水 代表来自客户端的请求,桶代表一个队列 请求根据先进先出等待处理 (FIFO) 调度算法。漏水代表请求 退出缓冲区供服务器处理,溢出 表示被丢弃且从未得到服务的请求。

    从我的一台服务器添加配置快照:

    ngx_http_limit_conn_module 模块用于限制每个已定义键的连接数,特别是来自单个 IP 地址的连接数。

    并非所有连接都被计算在内。只有当服务器正在处理一个请求并且已经读取了整个请求标头时,才计算一个连接。

    所以基本上你可以为实际和所有其他单独的虚拟服务器进行两种设置。

    通过限制IP 通过限制连接

    可能有多个 limit_conn 指令。例如, 以下配置将限制连接到 每个客户端 IP 的服务器,同时,服务器的总数 与虚拟服务器的连接:

    下面是同样的例子

    limit_conn_zone $binary_remote_addr zone=perip:10m;
    limit_conn_zone $server_name zone=perserver:10m;
    
    server {
        ...
        limit_conn perip 10;
        limit_conn perserver 100;
    }
    

    共同前进!

    达尔潘

    You can find in detail example and explanation here too

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多