首页  /  Nginx 进阶  /  正文

Nginx 限流日志与健康检查

Nginx 进阶 2026-10-02📖 15 分钟👁 —
🚀 Nginx 水平扩展与优化第 4 / 8 页12345678📖 完整导航 →

一、限流

漏桶算法和 JMeter 压测

漏桶算法限流

压测部分仅作了解。

为何限制?安全稳定少出事。

JMeter 是 java 开发的工具,需要装 java,在 win 解压后打开 jmeter.bat,用这个压测服务器即可。

JMeter 打开后的 Test Plan 界面

压测部分仅用视频内容做演示。

在 http 块 limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

变量是远程连接客户端 IP 地址($remote_addr 也可,前者是二进制数据到 zone 配置的缓存,后者是字节格式),zone 是该限速配置的名称,10MB 是记录远程地址的缓冲区,rate 是接收请求速率,1s 一个 request。

启用配置后配置压测参数测试:

还没配桶时的压测结果表

如果并发量很多,直接丢弃请求。

漏桶算法顾名思义,把请求都放到里面,然后按照速率处理,超出桶的部分丢弃,上图很明显不符合配置要求,因为没有配置"桶"。

在 location 块 limit_req zone=one burst=5;

测试(并发不大于 5):

画的桶,burst 是 5

(上图)相同请求类似于队列请求的状态(先放到桶再按速率处理请求),如果不设置 burst,有速率限制就会全部丢弃请求,直到符合速率才会继续处理请求。

处理请求速度是固定的,当用户请求量变大,桶也严重超出,就会有很多请求超时,此时用到快速失败。

limit_req zone=one burst=5 nodelay; nodelay 表示后边的队列请求,不在桶里,直接失败(此时才是真"桶",装得下就处理,装不下扔)。

瞬间处理了桶内 5 个请求,其余全失败

(上图)可以看到瞬间处理了桶内 5 个请求,其余的全失败了,因为配置的速率太低,可以改为 limit_req_zone $binary_remote_addr zone=one:10m rate=500r/s;

此时报错的概率会很低:

把速率提到 500r/s 之后基本都是绿的

并发的速率限制一定在产品上线前要测试好(测试干的),一般都是基于测试产品(先行服)进行数据统计然后基于日志测试。

一个网站的用户日志就在 /var/log/nginx/,其中 access.log 是用户的所有行为(日志很大需要进行管理,之后会了解到)。

access.log 里的几行记录

分别是用户请求 IP、时间、uri。

error.log 是错误日志。

具体配置区分

limit_req zone=one burst=5 nodelay; 和 limit_req zone=one burst=5;

加了 nodelay; 就是不看 rate 速率限制了,一下子处理桶内的请求。

加了 burst=5 nodelay 之后,前 5 个并发瞬间处理,第 6 个开始 rate 生效,按速率一个个处理。如果没 rate,桶外没任何限制,DDoS 直接打爆服务器。

漏桶算法的经典图,水龙头往里滴、桶底按固定速率漏出去

令牌桶算法

介绍

nginx 的限速方式基于漏桶算法实现,令牌桶和前者的区别就在于限速指标。漏桶算法限速很严格,只能按照配置的处理请求,令牌桶有一些区别。

每个用户到系统有"申请令牌"的操作,假设开始每秒生成 5 个令牌放到桶,用户带着牌子再请求。

令牌桶示意,用户先申请令牌

并发量大了,就没有牌子了,系统会按照固定速率向桶内放牌。

和漏桶算法很像,但是区别有很多,令牌桶算法有更灵活的处理方式,比如让一个人拿走很多牌子,针对于牌子区分用户,假设用户拿 1 个牌子分配 100M 带宽,2 个就是 200M(不同用户不同速),牌子不够,就等待(其实牌子就是 token)。

这个算法不匹配限制用户请求的需求,因为单位时间用户只会请求一次。令牌桶算法适用于限制带宽的需求,比如百度网盘会员和普通用户的限制。

限制网络带宽

官方文档只有两个配置:

limit_rate 1k; 发送请求传输文件的速率(以字节为单位,1k 就是 1KB,注意大小写)

限速之后浏览器里显示的下载速度

可以看到 900 多 b/s,这只是浏览器的显示速度(稍快的浏览器比较不要脸,显得很快而已)。

这是单线程的请求,多线程的请求每一个线程都能拿到一个牌子,就可能突破速率的限制,每一个令牌和用户并发的请求是不冲突的,所以 limit_req 和 limit_rate 是可以相互配合使用的。

另外一个配置 limit_rate_after 1m; 在下载指定数据之后对用户限速(单位依旧是比特),先快后慢,常用于多媒体网站,先让用户看视频,然后限制一下,不能让一个用户一直占据很多带宽。

客户端并发数限制

限制用户请求的线程个数,配置和 qps 限制配置很像。

limit_req_zone $binary_remote_addr zone=one:10m rate=500r/s;
配置选项 限流选项 命名空间:分配的缓冲内存空间 速率限制
limit_conn_zone $binary_remote_addr zone=two:10m;
配置选项 限流选项 命名空间:分配的缓冲内存空间

在 location 块配置

limit_conn two 1; 唯一的区别就是多了命名空间的配置。

限速配置一共三块,针对 req 漏桶算法限制,针对带宽的令牌桶算法限制,针对客户端并发线程的计数器算法限制,三个应用实际上很广,主要是测试方面配置的参数。

二、日志

Nginx 日志基本配置

简单了解

日志是低价值数据,是用户的行为,不是个人信息数据,商业行为中可以调整产品策略,比如页面停留时间,购买商品喜好等构建大数据推荐系统。

/var/log/ 日志相比于文件、目录等权限分配要复杂很多,所以这里了解到的肯定是不深入的,仅仅作为入门的引子来理解就可以。

像是浏览器控制台 size 很小的请求,很可能是在收集用户的行为(在某个位置停留时长、鼠标滑过的都可以通过 js 前端脚本访问日志接口,与 AI 也相关)。

数据标注可能用到日志,比如人机验证点图片,把用户的点击数据收集起来,然后放到特定的数据中心(比如红绿灯的人机验证就放到自动驾驶领域)。

access.log 相关配置

在官方文档直接搜 ngx_http_log_module,记录日志请求都是 http 协议,https 增加了四次握手很低效。

access_log 指令的语法和生效范围

access_log 记录了配置,buffer 缓冲区大小,gzip 压缩日志,以 gzip 格式放到文档,需要解压查看,flush 触发写日志的间隔,if 判断条件,如果匹配就不记录。

这里定义了全局路径但是 location 的块优先级高于全局,所以路径配置不能省略。

添加新的目录必须先建目录不然报错。

nginx.conf 里默认的 Logging Settings

其他的一些具体内容可以看官方文档,上述内容是正常访问日志的配置。

tail -f /var/log/nginx 是查看日志更新的常用命令,-f 可以滚动到最后一条。

关于 nginx 文档建议自己看,查看官方文档的能力是至关重要的。

官方样例配置如下:

官方 Example Configuration,log_format 加 access_log buffer
# 指定locaton块和access_log
    location / {
        # 日志配置
        access_log /var/log/nginx/test_access.log test buffer=32k;
        # buffer的配置是超出了32k缓冲就写入磁盘目录
        # 所以配置这个选项,刚开始目录没东西
        
    }


# 在nginx.conf的http块配置log_format
# 定义日志格式,决定日志记录内容
http {
        # 日志配置
        log_format test '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';
        # 官方文档说明了每个变量的功能

日志压缩和解压 & JSON 格式输出

压缩配置

运行过程内存缓冲区可能堆积不满,不写入磁盘,flush 就是强制写入磁盘的周期时间,一般以 h、min 为单位。

access_log /var/log/nginx/test_access.log test buffer=32k flush=1h;

如果日志太大,想缩小可以配置 gzip,但是需要注意日志是在缓冲区压缩的,所以想看日志必须解压出来才行,tail 也不行了。

access_log /var/log/nginx/test_access.log test buffer=32k gzip=6 flush=1h; 如果 gzip 什么都不写,就默认压缩等级为 1,等级过高会消耗性能的。

此时 tail 的文件是压缩形式,不可读:

压缩之后的日志文件是一堆乱码

开启 gzip 最好是开一个新文件从头开始记录。

以 gzip 压缩的文件,以 gzip 算法解压即可,解压时候最好复制一份再解压。

先 cp 一份再 gzip -d 解压

补充

官方还有其他的配置:缓存相关(buffer 是缓冲)

open_log_file_cache 的语法

不打开配置,每次写日志都会重新打开磁盘文件,追加然后关掉。

max 最大打开文件描述符,后面三个分别是活动时间、至少几个请求再缓冲、缓冲区的过期时间(之前遇到过这些选项,属于代码复用了)。

JSON 格式输出日志

默认的格式是文本格式,可以指定为 json 格式(不能配置 gzip)。

log_format 支持 escape=json

可以做一些转译。

log_format test json '{
        "timestamp":"$time_iso8601",
        "source":"$server_addr",
        "hostname":"$hostname",
        "remote_user":"$remote_user",
        "ip":"$http_x_forwarded_for",
        "client":"$remote_addr",
        "request_method":"$request_method",
        "scheme":"$scheme",
        "domain":"$server_name",
        "referer":"$http_referer",
        "request":"$request_uri",
        "requesturl":"$request",
        "args":"$args",
        "size":"$body_bytes_sent",
        "status":"$status",
        "responsetime":"$request_time",
        "upstreamtime":"$upstream_response_time",
        "upstreamaddr":"$upstream_addr",
        "http_user_agent":"$http_user_agent",
        "http_cookie":"$http_cookie",
        "https":"$https"
         }';


access_log /var/log/nginx/test_access.log test buffer=32k flush=1s;
# 记得把之前的配置删去,两个配置同样的名字组会冲突的

json 格式还是很有用的,如果想做数据分析,直接导入日志就很方便,也可以存入大数据的一些产品框架,很方便。

日志必须开,追根溯源很有用的。

error 日志与日志分割

error_log 配置

官方文档:没有独立的模块,在 core 模块下。

nginx.org/en/docs/ngx_core_module.html#error_log
error_log 的语法和错误等级

file 是记录位置,level 是错误等级,配置低了 debug 调试信息都会被记录,可以被收集和分析,不能自定义格式只能按照 nginx 自己的格式,或者导出后处理格式。

日志分割

脚本按照日期切割生成新的文件存放。

Logrotate 也可以。

三、健康检查

upstream 重试机制(被动)

位置:nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream

proxy_next_upstream 可以填哪些值

当发生了哪些错误之后启用 upstream 的下一个 server 服务器。

upstream httpget {
    server 172.16.0.9;
    server 10.1.4.16;

}

    location / {
    proxy_next_upstream error timeout;
    # 如果超时了就尝试匹配10.1.4.16
    # 官方也写了这是默认配置
    proxy_pass http://httpget;
    }
}
proxy_next_upstream_timeout 允许重试的总时间

允许上游服务器失败重试的总时间,超出就直接告诉用户失败了。

proxy_next_upstream_tries 重试次数

总时间内尝试多少次失败重试,直到被允许的最后一次(不能给很长时间,否则在一台机器很可能卡死)。

失败的次数包含第一次请求。

location 块里的三个 proxy_next_upstream 配置

简单来说就是对于一次请求,按照什么规则请求下一台服务器的配置。

如果下一次请求打到了,还是访问了刚才访问失败的机器,会降低效率,所以用到了额外的两个配置。

upstream httpget {
    server 172.16.0.9 max_fails=5 fail_timeout=10s;
    # 这台机器总共允许失败多少次,之后标记为不可用,不让用户访问
    # 假设它之后又修复了,需要重新被访问,就是后面起作用
    # 下线10s之后再上线一次。第二层含义:10s之内失败5次就下线
    server 10.1.4.16;

}

健康检查使用 tengine 模块(主动)

这部分内容了解即可,现在改为用 k8s 了。

tengine 版的模块地址和 nginx 商业版文档地址

又有 Tengine 版本和 nginx 商业版,此处内容演示的是 Tengine。

官方文档有好多模块都是商业版本的。

patch 文件列表,要挑和 nginx 版本对应的那个

这里的 patch 要和 nginx 版本对应。

Nginx 部分,至此完结,后续自己深化学习即可。

可喜可贺,めでたし めでたし