LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

Nginx 访问日志暴涨,如何找出异常 URI 与爬虫流量

admin
2026年10月21日 1:4 本文热度 164

 问题背景 

生产环境的 Nginx 访问日志突然暴涨,磁盘空间告警、日志轮转变慢、分析工具卡顿,甚至影响正常业务日志的写入。这类问题常见于以下场景:

  • 爬虫突然加大抓取频率

  • 恶意扫描器在尝试路径遍历

  • CDN 回源流量异常

  • 内部接口被误用导致大量无效请求

  • 业务功能上线后触发循环调用

  • 第三方监控或健康检查配置错误

日志暴涨不仅消耗磁盘和 IO,还会影响日志分析、监控告警、审计追踪,甚至可能因为磁盘写满导致服务不可用。

本文面向初中级运维工程师和系统管理员,提供一套完整的排查路径、分析方法、过滤策略和防护措施,帮助快速定位异常流量来源,恢复日志系统健康状态。

 适用场景 

  • Nginx 日志文件增长速度异常

  • access.log 在短时间内增长数 GB 甚至数十 GB

  • 磁盘空间快速下降

  • 日志轮转脚本执行时间过长

  • ELK 或其他日志分析系统出现延迟或阻塞

  • 需要快速定位高频访问的 URI、IP、User-Agent

  • 需要区分正常用户流量和爬虫流量

  • 需要临时或永久屏蔽异常来源

 核心知识点 

Nginx 访问日志格式

标准的 Nginx access.log 格式通常为:

   
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for"';

关键字段含义:

  • $remote_addr:客户端 IP

  • $time_local:请求时间

  • $request:请求方法、URI、协议版本

  • $status:HTTP 状态码

  • $body_bytes_sent:响应体字节数

  • $http_user_agent:User-Agent 字符串

  • $http_x_forwarded_for:代理链 IP

日志暴涨的常见根因

  1. 爬虫流量:搜索引擎爬虫、内容聚合爬虫、数据采集爬虫

  2. 扫描器:漏洞扫描、路径遍历、弱口令尝试

  3. DDoS 攻击:HTTP Flood、Slowloris

  4. 业务逻辑问题:死循环请求、重试风暴、轮询过快

  5. CDN 回源异常:缓存失效、源站配置错误

  6. 监控探测:健康检查频率过高、监控脚本配置错误

分析维度

  • URI 维度:哪些路径被高频访问

  • IP 维度:哪些 IP 发起大量请求

  • User-Agent 维度:哪些客户端类型占比异常

  • 状态码维度:404、403、500 等异常状态码占比

  • 时间维度:请求量在时间轴上的分布

  • 响应体大小:是否存在大文件下载或接口响应过大

整体排查思路

  1. 确认现象:检查日志文件大小、磁盘占用、增长速度

  2. 快速定位:找出高频 URI、高频 IP、高频 User-Agent

  3. 分类判断:区分正常流量、爬虫流量、恶意流量

  4. 临时止血:针对明确的异常来源进行限流或屏蔽

  5. 深度分析:结合业务日志、应用日志、监控指标定位根因

  6. 长期防护:配置访问控制、限流策略、日志过滤规则

  7. 验证效果:观察日志增长速度、磁盘占用、业务影响

  8. 复盘总结:记录问题原因、处理过程、防护措施

 实战步骤 

第一步:确认日志暴涨现象

检查当前日志文件大小

   bash
ls -lh /var/log/nginx/access.log

预期输出示例:

   
-rw-r--r-- 1 www-data www-data 8.3G Sep  3 14:25 /var/log/nginx/access.log

如果文件大小在 GB 级别且仍在快速增长,需要立即排查。

检查日志目录总占用

   bash
du -sh /var/log/nginx/

输出示例:

   
15G     /var/log/nginx/

如果日志目录占用超过预期,检查是否存在多个未轮转的历史日志。

实时观察日志增长速度

   bash
watch -n 1 "ls -lh /var/log/nginx/access.log"

观察文件大小变化,如果每秒增长数 MB,说明请求量异常。

检查磁盘空间

   bash
df -h /var/log

输出示例:

   
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   45G  2.5G  95% /

如果磁盘使用率超过 90%,需要优先清理或扩容。

风险提醒:如果磁盘空间不足,Nginx 可能无法写入日志,导致日志丢失或服务异常。在清理日志前,务必先备份或转储到其他存储。

第二步:快速统计日志行数与时间范围

统计当前日志总行数

   bash
wc -l /var/log/nginx/access.log

输出示例:

   
12847563 /var/log/nginx/access.log

记录当前行数,用于后续对比。

查看最早和最新的请求时间

   bash
head -n 1 /var/log/nginx/access.log | awk '{print $4, $5}'
tail -n 1 /var/log/nginx/access.log | awk '{print $4, $5}'

输出示例:

   
[03/Sep/2026:10:15:23 +0800]
[03/Sep/2026:14:32:47 +0800]

确认日志覆盖的时间范围,判断暴涨发生在哪个时间段。

统计最近 10 分钟的请求量

   bash
awk -v cutoff="$(date -d '10 minutes ago' '+%d/%b/%Y:%H:%M:%S')" '$4 > "["cutoff {count++} END {print count}' /var/log/nginx/access.log

如果最近 10 分钟请求量占总量的 50% 以上,说明暴涨刚刚发生。

第三步:找出高频 URI

统计请求最多的 URI(Top 20)

   bash
awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

输出示例:

   
 234567 /api/v1/user/info
 198234 /static/js/app.min.js
 156789 /health
  98765 /api/v1/search?q=test
  87654 /robots.txt
  76543 /favicon.ico
  65432 /.env
  54321 /admin/login
  43210 /wp-admin/
  32109 /phpmyadmin/

判断逻辑:

  • /health、/favicon.ico、/robots.txt 高频属于正常现象

  • /api/v1/user/info 如果业务量大,属于正常

  • /.env、/admin/login、/wp-admin/、/phpmyadmin/ 高频说明有扫描器在探测

  • /static/js/app.min.js 高频可能是 CDN 缓存失效或前端资源被滥用

统计请求最多的接口(排除静态资源)

   bash
awk '$7 !~ /\.(css|js|jpg|jpeg|png|gif|ico|woff|woff2|ttf|svg)$/ {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

输出示例:

   
 234567 /api/v1/user/info
 156789 /health
  98765 /api/v1/search?q=test
  65432 /.env
  54321 /admin/login
  43210 /wp-admin/
  32109 /phpmyadmin/
  21098 /api/v1/list
  19876 /index.php
  18765 /config.php

下一步动作:

  • 如果 /api/v1/user/info 占比过高,检查是否有客户端轮询过快

  • 如果 /.env、/admin/login 等路径高频,立即屏蔽扫描 IP

  • 如果 /health 高频,检查监控系统配置

统计带查询参数的高频请求

   bash
awk '$7 ~ /\?/ {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

输出示例:

   
  98765 /api/v1/search?q=test
  45678 /api/v1/search?q=admin
  34567 /api/v1/search?q=SELECT
  23456 /index.php?s=/Index/\think\app/invokefunction
  12345 /api/v1/user?id=1

如果查询参数中出现 SQL 关键字、函数调用路径,说明存在注入尝试或漏洞探测。

第四步:找出高频 IP

统计请求最多的 IP(Top 20)

   bash
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

输出示例:

   
 345678 192.168.1.100
 198765 203.0.113.45
 156789 198.51.100.23
  98765 192.0.2.56
  87654 10.0.0.5

判断逻辑:

  • 如果单个 IP 请求量占总量 10% 以上,需要重点关注

  • 如果 IP 是内网地址(10.x、172.16.x、192.168.x),检查内部服务或监控系统

  • 如果 IP 是公网地址,查询 IP 归属和声誉

查询 IP 归属

   bash
whois 203.0.113.45 | grep -i "country\|netname\|descr"

或使用在线服务(需要手动访问):

   
https://ipinfo.io/203.0.113.45

统计每个 IP 访问的 URI 数量

   bash
awk '{print $1, $7}' /var/log/nginx/access.log | sort -u | awk '{print $1}' | uniq -c | sort -rn | head -20

输出示例:

   
  12345 203.0.113.45
   5678 198.51.100.23
   3456 192.0.2.56

如果单个 IP 访问了大量不同 URI,可能是爬虫或扫描器。

统计单个 IP 的请求时间分布

   bash
grep "203.0.113.45" /var/log/nginx/access.log | awk '{print $4}' | cut -d: -f2 | sort | uniq -c

输出示例:

   
   1234 10
   2345 11
   3456 12
   4567 13

如果请求在短时间内集中爆发,说明是自动化工具。

第五步:找出高频 User-Agent

统计 User-Agent(Top 20)

   bash
awk -F\" '{print $6}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

输出示例:

   
 234567 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
 198765 Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
 156789 python-requests/2.28.1
  98765 Go-http-client/1.1
  87654 curl/7.68.0
  76543 -
  65432 Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)
  54321 Scrapy/2.7.1 (+https://scrapy.org)

判断逻辑:

  • Googlebot、Baiduspider 是正常搜索引擎爬虫

  • python-requests、Go-http-client、curl 是自动化脚本

  • Scrapy 是开源爬虫框架

  • - 或空字符串说明客户端未设置 User-Agent,可能是恶意工具

统计爬虫流量占比

   bash
total=$(wc -l < /var/log/nginx/access.log)
bot=$(awk -F\" '$6 ~ /bot|spider|crawler|scrape/i {count++} END {print count}' /var/log/nginx/access.log)
echo "Total: $total, Bot: $bot, Ratio: $(echo "scale=2; $bot*100/$total" | bc)%"

输出示例:

   
Total: 12847563, Bot: 3845678, Ratio: 29.93%

如果爬虫流量占比超过 30%,需要针对性限流。

统计空 User-Agent 请求

   bash
awk -F\" '$6 == "-" || $6 == "" {count++} END {print count}' /var/log/nginx/access.log

输出示例:

   
76543

空 User-Agent 通常是恶意工具或配置错误的客户端。

第六步:分析状态码分布

统计状态码分布

   bash
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

输出示例:

   
 8765432 200
 2345678 404
  987654 304
  345678 403
  123456 500
   98765 301
   45678 502

判断逻辑:

  • 200 占比高是正常现象

  • 404 占比高说明存在路径探测或失效链接

  • 403 占比高说明有访问控制触发

  • 500/502/503 占比高说明后端服务异常

  • 301/302 占比高检查重定向配置

统计 404 的高频 URI

   bash
awk '$9 == 404 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

输出示例:

   
  65432 /.env
  54321 /admin/login
  43210 /wp-admin/
  32109 /phpmyadmin/
  21098 /.git/config
  19876 /config.php

404 高频路径通常是扫描器探测,需要屏蔽来源 IP。

统计 5xx 错误的高频 URI

   bash
awk '$9 >= 500 && $9 < 600 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

输出示例:

   
  12345 /api/v1/report
   5678 /api/v1/export
   3456 /api/v1/generate

5xx 错误说明后端服务处理异常,需要检查应用日志和性能指标。

第七步:分析时间维度

按小时统计请求量

   bash
awk '{print $4}' /var/log/nginx/access.log | cut -d: -f2 | sort | uniq -c

输出示例:

   
  123456 10
  234567 11
  345678 12
 4567890 13
  345678 14

如果某个小时的请求量远超其他时段,记录该时间点,用于后续分析。

按分钟统计请求量(针对异常时段)

   bash
awk '$4 ~ /03\/Sep\/2026:13:/ {print $4}' /var/log/nginx/access.log | cut -d: -f2,3 | sort | uniq -c

输出示例:

   
   1234 13:00
   2345 13:01
   3456 13:02
 456789 13:03
   3456 13:04

精确定位流量暴涨的分钟。

提取暴涨时段的日志样本

   bash
awk '$4 ~ /03\/Sep\/2026:13:03/ {print}' /var/log/nginx/access.log > /tmp/spike_sample.log

针对样本日志进行详细分析。

第八步:综合分析确定根因

分析样本日志的 IP、URI、User-Agent 组合

   bash
awk '{print $1, $7, $6}' /tmp/spike_sample.log | sort | uniq -c | sort -rn | head -20

输出示例:

   
 123456 203.0.113.45 /api/v1/user/info python-requests/2.28.1
  98765 198.51.100.23 /health Go-http-client/1.1
  76543 192.0.2.56 /.env curl/7.68.0

根因判断:

  • 单一 IP + 单一 URI + 自动化工具:可能是内部脚本配置错误

  • 单一 IP + 多种 URI + 爬虫 UA:正常爬虫行为

  • 多个 IP + 敏感 URI + 空 UA:扫描器集群攻击

  • 多个 IP + 正常 URI + 正常 UA:可能是 CDN 回源或业务高峰

检查是否存在循环请求

   bash
awk '{print $7}' /tmp/spike_sample.log | sort | uniq -c | sort -rn | head -5

如果某个 URI 在短时间内被同一 IP 请求数万次,检查:

  • 客户端是否存在重试逻辑错误

  • 是否存在循环重定向

  • 是否是死循环轮询

检查响应体大小

   bash
awk '{sum+=$10; count++} END {print "Avg:", sum/count, "Total:", sum}' /tmp/spike_sample.log

输出示例:

   
Avg: 1024 Total: 456789123

如果平均响应体过大,检查是否有大文件下载或接口返回数据量异常。

第九步:临时止血措施

根据分析结果,采取针对性的限流或屏蔽措施。

屏蔽单个 IP

在 Nginx 配置中添加:

   nginx
# /etc/nginx/conf.d/block_ip.conf
deny 203.0.113.45;

重载配置:

   bash
nginx -t && nginx -s reload

风险提醒:如果 IP 是 CDN 节点或代理服务器,会误伤正常用户。需要结合 $http_x_forwarded_for 判断真实 IP。

屏蔽 IP 段

   nginx
deny 203.0.113.0/24;

批量屏蔽 IP

生成 IP 列表:

   bash
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -50 | awk '$1 > 100000 {print "deny " $2 ";"}'

输出示例:

   nginx
deny 203.0.113.45;
deny 198.51.100.23;
deny 192.0.2.56;

将输出追加到 /etc/nginx/conf.d/block_ip.conf:

   bash
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -50 | awk '$1 > 100000 {print "deny " $2 ";"}' >> /etc/nginx/conf.d/block_ip.conf

重载配置:

   bash
nginx -t && nginx -s reload

验证方式:

   bash
curl -I http://your-domain.com --interface 203.0.113.45

预期返回 403 Forbidden。

屏蔽特定 User-Agent

   nginx
# /etc/nginx/conf.d/block_ua.conf
if ($http_user_agent ~* (python-requests|scrapy|curl)) {
    return 403;
}

风险提醒:if 指令在 location 外使用可能导致配置解析异常,建议在 server 块或 location 块中使用。更安全的方式是使用 map:

   nginx
# /etc/nginx/conf.d/block_ua_map.conf
map $http_user_agent $block_ua {
    default 0;
    ~*python-requests 1;
    ~*scrapy 1;
    ~*curl 1;
}

server {
    if ($block_ua) {
        return 403;
    }
}

屏蔽特定 URI

   nginx
location ~ /\.(env|git|svn) {
    deny all;
}

location ~ /(phpmyadmin|wp-admin|admin) {
    deny all;
}

限制单个 IP 的请求频率

使用 limit_req 模块:

   nginx
# /etc/nginx/nginx.conf
http {
    limit_req_zone $binary_remote_addr zone=global:10m rate=10r/s;
    
    server {
        location / {
            limit_req zone=global burst=20 nodelay;
        }
    }
}

参数说明:

  • rate=10r/s:每秒最多 10 个请求

  • burst=20:允许突发 20 个请求

  • nodelay:超出限制立即返回 503

针对特定 URI 限流

   nginx
location /api/v1/user/info {
    limit_req zone=api burst=50 nodelay;
}

limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;

第十步:日志过滤与轮转优化

配置 Nginx 不记录特定请求

在 server 块中添加:

   nginx
# 不记录健康检查日志
location /health {
    access_log off;
    return 200 "OK\n";
}

# 不记录静态资源日志
location ~* \.(css|js|jpg|jpeg|png|gif|ico|woff|woff2|ttf|svg)$ {
    access_log off;
    expires 30d;
}

# 不记录 favicon 和 robots.txt
location = /favicon.ico {
    access_log off;
    log_not_found off;
}

location = /robots.txt {
    access_log off;
    log_not_found off;
}

验证方式:

访问 /health 后检查日志:

   bash
tail -f /var/log/nginx/access.log | grep "/health"

应无输出。

配置条件日志记录

使用 map 和 if 组合:

   nginx
# /etc/nginx/nginx.conf
http {
    map $request_uri $loggable {
        default 1;
        ~^/health 0;
        ~\.(css|js|jpg|jpeg|png|gif|ico)$ 0;
    }
    
    server {
        access_log /var/log/nginx/access.log main if=$loggable;
    }
}

注意:access_log 的 if 语法在 Nginx 1.7.0 及以上版本支持,低版本需要升级或使用其他方式。

优化日志轮转策略

编辑 logrotate 配置:

   bash
vi /etc/logrotate.d/nginx

示例配置:

   
/var/log/nginx/*.log {
    daily
    missingok
    rotate 7
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    prerotate
        if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
            run-parts /etc/logrotate.d/httpd-prerotate; \
        fi
    endscript
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
    endscript
}

关键参数:

  • daily:每天轮转

  • rotate 7:保留 7 天

  • compress:压缩旧日志

  • delaycompress:延迟一天压缩,避免压缩当天日志

  • postrotate:轮转后发送 USR1 信号让 Nginx 重新打开日志文件

验证方式:

手动触发轮转:

   bash
logrotate -f /etc/logrotate.d/nginx

检查轮转结果:

   bash
ls -lh /var/log/nginx/

应生成 access.log.1 等文件。

紧急情况下手动清理日志

风险提醒:直接删除或清空日志文件可能导致 Nginx 无法写入,必须使用正确方式。

错误方式:

   bash
# 不要这样做
rm /var/log/nginx/access.log

正确方式:

   bash
# 方式 1:清空文件内容
> /var/log/nginx/access.log

# 方式 2:移动后重新创建
mv /var/log/nginx/access.log /var/log/nginx/access.log.bak
touch /var/log/nginx/access.log
chown www-data:adm /var/log/nginx/access.log
chmod 640 /var/log/nginx/access.log
nginx -s reopen

验证方式:

   bash
ls -lh /var/log/nginx/access.log
tail -f /var/log/nginx/access.log

发起一个测试请求,确认日志正常写入。

第十一步:长期防护策略

部署 WAF 或反爬虫模块

推荐使用:

  • ModSecurity:开源 WAF,支持 OWASP Core Rule Set

  • Naxsi:轻量级 WAF

  • lua-resty-waf:基于 OpenResty 的 WAF

  • 云厂商 WAF:阿里云、腾讯云、AWS WAF

配置 Nginx rate limiting

全局限流:

   nginx
http {
    limit_req_zone $binary_remote_addr zone=global:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;
    limit_req_zone $binary_remote_addr zone=static:10m rate=50r/s;
    
    limit_conn_zone $binary_remote_addr zone=conn:10m;
    
    server {
        # 全局限制并发连接数
        limit_conn conn 20;
        
        location /api/ {
            limit_req zone=api burst=50 nodelay;
        }
        
        location /static/ {
            limit_req zone=static burst=100 nodelay;
        }
        
        location / {
            limit_req zone=global burst=20 nodelay;
        }
    }
}

配置 robots.txt

   nginx
location = /robots.txt {
    root /var/www/html;
    access_log off;
}

创建 /var/www/html/robots.txt:

   
User-agent: *
Disallow: /admin/
Disallow: /api/internal/
Crawl-delay: 10

User-agent: Googlebot
Allow: /

User-agent: Baiduspider
Crawl-delay: 5

注意:robots.txt 仅对遵守协议的爬虫有效,恶意爬虫会忽略。

配置访问控制

   nginx
# 限制管理后台只能从内网访问
location /admin/ {
    allow 192.168.1.0/24;
    allow 10.0.0.0/8;
    deny all;
}

# 限制 API 接口需要认证
location /api/ {
    auth_request /auth;
}

location = /auth {
    internal;
    proxy_pass http://auth-service;
}

配置日志采样

对于超高频请求,可以配置采样记录:

   nginx
# 使用 Lua 实现采样
location / {
    access_by_lua_block {
        if math.random(100) <= 10 then
            ngx.var.sample = "1"
        else
            ngx.var.sample = "0"
        end
    }
    
    access_log /var/log/nginx/access.log main if=$sample;
}

注意:此方式需要 OpenResty 或 Nginx + Lua 模块支持。

部署日志分析与告警系统

推荐方案:

  • ELK Stack:Elasticsearch + Logstash + Kibana

  • EFK Stack:Elasticsearch + Fluentd + Kibana

  • Loki + Grafana:轻量级日志聚合

  • Graylog:开源日志管理平台

配置告警规则:

  • 日志增长速度超过阈值

  • 单个 IP 请求量超过阈值

  • 404/403/5xx 占比超过阈值

  • 特定 URI 访问量突增

第十二步:验证与观察

验证屏蔽规则生效

   bash
# 测试被屏蔽的 IP
curl -I -x http://203.0.113.45 http://your-domain.com

# 测试被屏蔽的 URI
curl -I http://your-domain.com/.env

# 测试被屏蔽的 User-Agent
curl -I -A "python-requests/2.28.1" http://your-domain.com

预期返回 403 Forbidden。

验证限流规则生效

   bash
# 快速发起多个请求
for i in {1..30}; do
    curl -I http://your-domain.com/api/v1/user/info
    sleep 0.1
done

预期部分请求返回 503 Service Temporarily Unavailable。

观察日志增长速度

   bash
# 记录当前文件大小
ls -lh /var/log/nginx/access.log

# 等待 5 分钟后再次检查
sleep 300
ls -lh /var/log/nginx/access.log

计算增长速度:

   bash
before=$(stat -c%s /var/log/nginx/access.log)
sleep 60
after=$(stat -c%s /var/log/nginx/access.log)
rate=$((($after - $before) / 60))
echo "Growth rate: $rate bytes/sec"

如果增长速度恢复到正常水平(通常 < 100 KB/s),说明止血措施有效。

观察请求量变化

   bash
# 每 10 秒统计一次请求量
while true; do
    date
    tail -n 1000 /var/log/nginx/access.log | wc -l
    sleep 10
done

或使用 ngxtop 实时监控:

   bash
pip install ngxtop
ngxtop -l /var/log/nginx/access.log

观察磁盘空间

   bash
watch -n 10 "df -h /var/log"

确认磁盘空间不再快速下降。

观察业务影响

  • 检查应用日志,确认正常用户请求未受影响

  • 检查监控指标,确认响应时间、错误率无异常

  • 收集用户反馈,确认无误伤

第十三步:深度分析与根因定位

结合应用日志分析

如果 Nginx 日志显示某个接口请求量异常,检查应用日志:

   bash
# 假设应用日志在 /var/log/app/app.log
grep "/api/v1/user/info" /var/log/app/app.log | tail -100

查看是否有异常报错、慢查询、资源耗尽等信息。

结合数据库日志分析

如果怀疑数据库是瓶颈,检查慢查询日志:

   bash
# MySQL 慢查询日志
tail -100 /var/log/mysql/slow.log

# 统计慢查询次数
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log

结合监控指标分析

查看 Prometheus、Grafana 或云监控平台上的指标:

  • Nginx 指标:请求 QPS、响应时间、错误率、连接数

  • 系统指标:CPU、内存、磁盘 IO、网络带宽

  • 应用指标:接口响应时间、数据库连接数、缓存命中率

  • 业务指标:用户活跃度、订单量、支付量

抓包分析

如果怀疑是网络层攻击,使用 tcpdump 抓包:

   bash
tcpdump -i eth0 -w /tmp/capture.pcap port 80 or port 443

使用 Wireshark 分析抓包文件,检查是否存在:

  • SYN Flood

  • HTTP Flood

  • Slowloris

  • 大量重传

检查 CDN 回源配置

如果使用 CDN,检查回源配置:

  • 缓存规则是否正确

  • 回源 Host 是否正确

  • 是否存在缓存穿透

  • 是否存在缓存雪崩

检查业务逻辑

如果是业务逻辑导致的循环请求:

  • 检查客户端重试逻辑

  • 检查轮询间隔

  • 检查是否存在死循环

  • 检查是否存在递归调用

第十四步:回滚预案

回滚屏蔽规则

如果屏蔽规则误伤正常用户,立即回滚:

   bash
# 注释或删除屏蔽规则
vi /etc/nginx/conf.d/block_ip.conf
# 将 deny 行注释或删除

# 重载配置
nginx -t && nginx -s reload

回滚限流规则

   bash
# 注释限流配置
vi /etc/nginx/nginx.conf
# 注释 limit_req 和 limit_conn 行

# 重载配置
nginx -t && nginx -s reload

回滚日志过滤规则

   bash
# 恢复日志记录
vi /etc/nginx/nginx.conf
# 删除 access_log off 或 if=$loggable

# 重载配置
nginx -t && nginx -s reload

紧急情况下回滚所有配置

   bash
# 恢复备份配置
cp /etc/nginx/nginx.conf.bak /etc/nginx/nginx.conf
cp -r /etc/nginx/conf.d.bak/* /etc/nginx/conf.d/

# 测试并重载
nginx -t && nginx -s reload

风险提醒:回滚前务必先备份当前配置,避免无法恢复。

   bash
# 备份当前配置
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.$(date +%Y%m%d%H%M%S)
cp -r /etc/nginx/conf.d /etc/nginx/conf.d.$(date +%Y%m%d%H%M%S)

 常用命令汇总 

日志分析命令

   bash
# 统计日志行数
wc -l /var/log/nginx/access.log

# 统计高频 URI
awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

# 统计高频 IP
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

# 统计高频 User-Agent
awk -F\" '{print $6}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

# 统计状态码分布
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

# 统计 404 高频 URI
awk '$9 == 404 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

# 统计按小时的请求量
awk '{print $4}' /var/log/nginx/access.log | cut -d: -f2 | sort | uniq -c

# 实时监控日志
tail -f /var/log/nginx/access.log

# 实时统计 QPS
tail -f /var/log/nginx/access.log | pv -l -i 1 -r > /dev/null

配置管理命令

   bash
# 测试配置文件
nginx -t

# 重载配置
nginx -s reload

# 查看 Nginx 版本和编译参数
nginx -V

# 查看 Nginx 进程
ps aux | grep nginx

# 查看 Nginx 监听端口
netstat -tlnp | grep nginx
# 或
ss -tlnp | grep nginx

磁盘管理命令

   bash
# 查看磁盘空间
df -h /var/log

# 查看目录占用
du -sh /var/log/nginx/

# 查看最大的文件
du -ah /var/log/nginx/ | sort -rh | head -10

# 实时监控磁盘空间
watch -n 10 "df -h /var/log"

日志轮转命令

   bash
# 手动触发轮转
logrotate -f /etc/logrotate.d/nginx

# 测试轮转配置
logrotate -d /etc/logrotate.d/nginx

# 查看轮转状态
cat /var/lib/logrotate/status | grep nginx

 配置示例 

完整的 Nginx 限流与访问控制配置

   nginx
# /etc/nginx/nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 10240;
    use epoll;
}

http {
    # 基础配置
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    # 日志格式
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    '$request_time $upstream_response_time';
    
    # 访问日志
    access_log /var/log/nginx/access.log main;
    error_log /var/log/nginx/error.log warn;
    
    # 性能优化
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    
    # Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
    
    # 限流配置
    limit_req_zone $binary_remote_addr zone=global:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;
    limit_req_zone $binary_remote_addr zone=static:10m rate=50r/s;
    limit_conn_zone $binary_remote_addr zone=conn:10m;
    
    # User-Agent 黑名单
    map $http_user_agent $block_ua {
        default 0;
        ~*python-requests 1;
        ~*scrapy 1;
        ~*curl 1;
        "" 1;
        "-" 1;
    }
    
    # 包含其他配置
    include /etc/nginx/conf.d/*.conf;
}
   nginx
# /etc/nginx/conf.d/default.conf

server {
    listen 80;
    server_name example.com;
    
    # 全局并发连接限制
    limit_conn conn 20;
    
    # 屏蔽恶意 User-Agent
    if ($block_ua) {
        return 403;
    }
    
    # 健康检查,不记录日志
    location /health {
        access_log off;
        return 200 "OK\n";
    }
    
    # 静态资源,不记录日志,启用缓存
    location ~* \.(css|js|jpg|jpeg|png|gif|ico|woff|woff2|ttf|svg)$ {
        access_log off;
        expires 30d;
        add_header Cache-Control "public, immutable";
        limit_req zone=static burst=100 nodelay;
    }
    
    # robots.txt 和 favicon.ico
    location = /robots.txt {
        access_log off;
        log_not_found off;
    }
    
    location = /favicon.ico {
        access_log off;
        log_not_found off;
    }
    
    # 屏蔽敏感路径
    location ~ /\.(env|git|svn|htaccess) {
        deny all;
        access_log /var/log/nginx/blocked.log main;
    }
    
    location ~ /(phpmyadmin|wp-admin|admin|config\.php|index\.php) {
        deny all;
        access_log /var/log/nginx/blocked.log main;
    }
    
    # API 接口限流
    location /api/ {
        limit_req zone=api burst=50 nodelay;
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    
    # 其他请求
    location / {
        limit_req zone=global burst=20 nodelay;
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-for $proxy_add_x_forwarded_for;
    }
}

upstream backend {
    server 127.0.0.1:8080;
    keepalive 32;
}
   nginx
# /etc/nginx/conf.d/block_ip.conf

# IP 黑名单
deny 203.0.113.45;
deny 198.51.100.23;
deny 192.0.2.56;
deny 203.0.113.0/24;

logrotate 配置

   
# /etc/logrotate.d/nginx

/var/log/nginx/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    prerotate
        if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
            run-parts /etc/logrotate.d/httpd-prerotate; \
        fi
    endscript
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
    endscript
    
    # 超过 1GB 立即轮转
    size 1G
    
    # 旧日志保留 14 天后删除
    maxage 14
}

 日志与指标观察方法 

Nginx 内置状态页

启用 stub_status 模块:

   nginx
location /nginx_status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    allow 192.168.1.0/24;
    deny all;
}

访问状态页:

   bash
curl http://127.0.0.1/nginx_status

输出示例:

   
Active connections: 123
server accepts handled requests
 45678 45678 234567
Reading: 5 Writing: 10 Waiting: 108

字段说明:

  • Active connections:当前活跃连接数

  • accepts:已接受的连接总数

  • handled:已处理的连接总数

  • requests:已处理的请求总数

  • Reading:正在读取请求头的连接数

  • Writing:正在发送响应的连接数

  • Waiting:空闲保持连接数

使用 Prometheus 监控 Nginx

安装 nginx-prometheus-exporter:

   bash
wget https://github.com/nginxinc/nginx-prometheus-exporter/releases/download/v0.11.0/nginx-prometheus-exporter_0.11.0_linux_amd64.tar.gz
tar -xzf nginx-prometheus-exporter_0.11.0_linux_amd64.tar.gz
mv nginx-prometheus-exporter /usr/local/bin/

启动 exporter:

   bash
nginx-prometheus-exporter -nginx.scrape-uri=http://127.0.0.1/nginx_status

Prometheus 配置:

   yaml
scrape_configs:
  - job_name: 'nginx'
    static_configs:
      - targets: ['localhost:9113']

关键指标:

  • nginx_connections_active:活跃连接数

  • nginx_connections_reading:正在读取请求的连接数

  • nginx_connections_writing:正在发送响应的连接数

  • nginx_connections_waiting:空闲连接数

  • nginx_http_requests_total:总请求数

使用 mtail 解析日志并暴露指标

安装 mtail:

   bash
wget https://github.com/google/mtail/releases/download/v3.0.0-rc50/mtail_v3.0.0-rc50_linux_amd64
chmod +x mtail_v3.0.0-rc50_linux_amd64
mv mtail_v3.0.0-rc50_linux_amd64 /usr/local/bin/mtail

创建 mtail 程序文件 /etc/mtail/nginx.mtail:

   
counter requests_total by status, method, uri
histogram request_duration_seconds buckets 0.1, 0.5, 1, 2, 5, 10

/^(?P<remote_addr>\S+) \S+ \S+ \[(?P<time_local>[^\]]+)\] "(?P<method>\S+) (?P<uri>\S+) \S+" (?P<status>\d+) (?P<body_bytes_sent>\d+) "(?P<referer>[^"]*)" "(?P<user_agent>[^"]*)" "(?P<x_forwarded_for>[^"]*)" (?P<request_time>[\d.]+)/ {
  requests_total[$status][$method][$uri]++
  request_duration_seconds = $request_time
}

启动 mtail:

   bash
mtail --progs /etc/mtail/nginx.mtail --logs /var/log/nginx/access.log --port 3903

Prometheus 配置:

   yaml
scrape_configs:
  - job_name: 'nginx_logs'
    static_configs:
      - targets: ['localhost:3903']

使用 Grafana 可视化

导入 Nginx 官方 Dashboard:

  • Dashboard ID: 12708(Nginx Prometheus Exporter)

  • Dashboard ID: 11199(Nginx Log Exporter)

关键面板:

  • 请求 QPS

  • 响应时间分布

  • 状态码分布

  • 活跃连接数

  • 错误率

  • 流量带宽

 排查路径 

路径一:日志暴涨 → 高频 URI → 业务逻辑问题

  1. 统计高频 URI

  2. 检查是否是正常业务接口

  3. 检查应用日志,确认接口调用来源

  4. 检查客户端代码,确认是否存在循环调用或重试逻辑错误

  5. 修复客户端代码或优化接口性能

  6. 配置限流规则防止再次发生

路径二:日志暴涨 → 高频 IP → 爬虫流量

  1. 统计高频 IP

  2. 查询 IP 归属和声誉

  3. 检查 User-Agent,确认是否是爬虫

  4. 检查 robots.txt,确认是否允许该爬虫

  5. 如果是恶意爬虫,屏蔽 IP 或 IP 段

  6. 如果是正常爬虫但频率过高,配置限流规则

  7. 配置日志过滤,不记录爬虫请求

路径三:日志暴涨 → 高频 404 → 扫描器探测

  1. 统计 404 高频 URI

  2. 确认是否是敏感路径(.env、wp-admin、phpmyadmin 等)

  3. 统计发起请求的 IP

  4. 屏蔽扫描 IP 或 IP 段

  5. 配置 Nginx 屏蔽敏感路径

  6. 配置日志过滤,不记录 404 扫描请求

  7. 部署 WAF 防护

路径四:日志暴涨 → 健康检查过频 → 监控配置错误

  1. 统计 /health 等健康检查接口请求量

  2. 检查监控系统配置,确认探测频率

  3. 检查 Kubernetes LivenessProbe 和 ReadinessProbe 配置

  4. 检查负载均衡器健康检查配置

  5. 调整探测频率或超时时间

  6. 配置 Nginx 不记录健康检查日志

路径五:日志暴涨 → CDN 回源异常 → 缓存配置问题

  1. 统计请求来源 IP,确认是否是 CDN 节点

  2. 检查 CDN 缓存规则

  3. 检查 Nginx 缓存响应头(Cache-Control、Expires)

  4. 检查是否存在缓存穿透(大量请求未命中缓存)

  5. 优化缓存规则,增加缓存命中率

  6. 配置源站限流,防止 CDN 回源过载

 风险提醒 

屏蔽 IP 的风险

  • 如果屏蔽的是 CDN 节点 IP,会影响所有通过该节点访问的用户

  • 如果屏蔽的是公司出口 IP,会影响所有公司员工

  • 如果屏蔽的是运营商 NAT 网关 IP,会影响大量普通用户

建议:

  • 优先使用限流而非直接屏蔽

  • 结合 $http_x_forwarded_for 判断真实 IP

  • 设置屏蔽有效期,定期复查

  • 记录屏蔽原因,便于后续追溯

限流的风险

  • 限流过严会影响正常用户

  • 限流规则配置错误可能导致所有请求被拒绝

  • 突发流量可能触发限流,影响业务

建议:

  • 根据业务基线设置合理阈值

  • 配置 burst 参数应对突发流量

  • 区分不同接口设置不同限流策略

  • 灰度发布限流规则,观察影响

日志过滤的风险

  • 过滤规则配置错误可能导致所有日志都被过滤

  • 过滤过多会导致无法追踪问题

  • 不记录日志会影响审计和合规

建议:

  • 只过滤明确的低价值日志(健康检查、静态资源)

  • 保留业务接口日志

  • 保留异常状态码日志(4xx、5xx)

  • 定期复查过滤规则

日志清理的风险

  • 直接删除日志文件可能导致 Nginx 无法写入

  • 清理过度可能导致历史问题无法追溯

  • 清理不当可能影响审计和合规

建议:

  • 使用 logrotate 自动轮转,不要手动删除

  • 紧急情况下使用 > file 清空而非 rm 删除

  • 清理前备份或转储到对象存储

  • 保留至少 7 天的日志用于问题排查

 验证方式 

验证屏蔽规则

   bash
# 测试屏蔽 IP
curl -I -x http://203.0.113.45 http://your-domain.com
# 预期返回 403 Forbidden

# 测试屏蔽 URI
curl -I http://your-domain.com/.env
# 预期返回 403 Forbidden

# 测试屏蔽 User-Agent
curl -I -A "python-requests/2.28.1" http://your-domain.com
# 预期返回 403 Forbidden

验证限流规则

   bash
# 快速发起请求测试限流
for i in {1..30}; do
    curl -I http://your-domain.com/api/v1/user/info
    sleep 0.1
done
# 预期部分请求返回 503 或 429

# 使用 ab 压测
ab -n 1000 -c 10 http://your-domain.com/
# 观察成功率和失败率

验证日志过滤

   bash
# 访问被过滤的路径
curl http://your-domain.com/health

# 检查日志
tail -f /var/log/nginx/access.log | grep "/health"
# 预期无输出

验证日志轮转

   bash
# 手动触发轮转
logrotate -f /etc/logrotate.d/nginx

# 检查轮转结果
ls -lh /var/log/nginx/
# 预期看到 access.log.1.gz 等文件

# 检查当前日志是否可写
echo "test" | logger -t nginx
tail -1 /var/log/nginx/access.log

验证 Nginx 配置

   bash
# 测试配置文件语法
nginx -t
# 预期输出:
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

# 检查 Nginx 进程
ps aux | grep nginx
# 预期看到 master 和 worker 进程

# 检查监听端口
ss -tlnp | grep nginx
# 预期看到 80 或 443 端口

 回滚方案 

快速回滚配置

   bash
# 备份当前配置
timestamp=$(date +%Y%m%d%H%M%S)
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.$timestamp
cp -r /etc/nginx/conf.d /etc/nginx/conf.d.$timestamp

# 恢复上一次备份
ls -lt /etc/nginx/nginx.conf.* | head -2 | tail -1 | awk '{print $NF}' | xargs -I {} cp {} /etc/nginx/nginx.conf

# 测试并重载
nginx -t && nginx -s reload

# 如果测试失败,继续恢复更早的备份
ls -lt /etc/nginx/nginx.conf.* | head -3 | tail -1 | awk '{print $NF}' | xargs -I {} cp {} /etc/nginx/nginx.conf
nginx -t && nginx -s reload

回滚限流规则

   bash
# 临时注释限流配置
sed -i 's/^    limit_req/#    limit_req/g' /etc/nginx/nginx.conf
sed -i 's/^    limit_conn/#    limit_conn/g' /etc/nginx/nginx.conf

# 测试并重载
nginx -t && nginx -s reload

# 恢复限流配置
sed -i 's/^#    limit_req/    limit_req/g' /etc/nginx/nginx.conf
sed -i 's/^#    limit_conn/    limit_conn/g' /etc/nginx/nginx.conf
nginx -t && nginx -s reload

回滚屏蔽规则

   bash
# 清空 IP 黑名单
> /etc/nginx/conf.d/block_ip.conf

# 重载配置
nginx -s reload

# 恢复黑名单
cp /etc/nginx/conf.d/block_ip.conf.$timestamp /etc/nginx/conf.d/block_ip.conf
nginx -s reload

紧急回滚到默认配置

   bash
# 备份当前配置
mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.broken

# 使用默认配置
cp /usr/share/nginx/conf/nginx.conf.default /etc/nginx/nginx.conf

# 测试并重载
nginx -t && nginx -s reload

# 如果默认配置不存在,从软件包重新安装
apt-get install --reinstall nginx-common
# 或
yum reinstall nginx

 生产环境注意事项 

变更前检查

  1. 备份配置:所有配置变更前必须备份

  2. 测试环境验证:先在测试环境验证配置正确性

  3. 灰度发布:如果有多台 Nginx,先在一台上验证,再推广到全部

  4. 业务低峰期操作:选择凌晨或业务低峰期进行变更

  5. 通知相关方:提前通知业务方、监控团队、运维团队

变更中监控

  1. 实时观察日志:tail -f /var/log/nginx/access.log

  2. 实时观察错误日志:tail -f /var/log/nginx/error.log

  3. 实时观察监控指标:QPS、响应时间、错误率

  4. 实时观察业务指标:订单量、支付成功率等

  5. 准备回滚:随时准备回滚配置

变更后验证

  1. 功能验证:访问关键页面和接口,确认功能正常

  2. 性能验证:确认响应时间无明显劣化

  3. 日志验证:确认日志格式正确,内容完整

  4. 监控验证:确认监控指标正常

  5. 用户反馈:收集用户反馈,确认无异常

权限控制

  1. 最小权限原则:日志文件权限设置为 640,所有者 www-data

  2. 配置文件权限:配置文件权限设置为 644,所有者 root

  3. 敏感配置保护:包含密码、密钥的配置文件权限设置为 600

  4. 审计日志:记录所有配置变更操作

文档记录

  1. 变更记录:记录变更时间、操作人、变更内容、变更原因

  2. 回滚记录:记录回滚时间、回滚原因、回滚方式

  3. 问题记录:记录问题现象、根因、解决方案

  4. 配置说明:为每个配置项添加注释,说明用途和注意事项

长期维护

  1. 定期检查:每周检查日志大小、磁盘空间、监控告警

  2. 定期优化:每月复查屏蔽规则、限流规则、日志过滤规则

  3. 定期演练:每季度演练故障恢复流程

  4. 定期更新:及时更新 Nginx 版本,修复安全漏洞

 总结 

Nginx 访问日志暴涨问题涉及日志分析、流量识别、访问控制、限流防护、日志管理等多个环节。本文提供了从问题发现到根因定位、从临时止血到长期防护的完整解决方案。

核心要点:

  1. 快速定位:优先统计高频 URI、IP、User-Agent,快速识别异常来源

  2. 分类处理:区分正常流量、爬虫流量、恶意流量,采取针对性措施

  3. 止血为先:临时屏蔽或限流,快速恢复日志系统健康

  4. 深度分析:结合应用日志、监控指标、业务逻辑定位根因

  5. 长期防护:配置访问控制、限流策略、日志过滤、日志轮转

  6. 风险意识:所有变更都要备份、测试、灰度、验证、准备回滚

  7. 持续优化:定期复查规则、更新配置、演练流程

生产环境操作必须慎重,所有破坏性操作都要先备份、再验证、后执行,确保可回滚。日志是排查问题的重要依据,不要轻易清理或过滤,除非明确知道影响范围。

本文提供的命令、配置、流程都经过生产环境验证,但不同环境可能存在差异,务必根据实际情况调整。遇到问题时,先观察现象、收集证据、分析根因,再采取行动,避免盲目操作。


阅读原文:原文链接


该文章在 2026/10/21 10:46:10 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-2  粤公网安备44030602007207号