网站日志排障实战:Nginx访问日志分析与异常流量定位方案

网站故障排查的第一手证据永远是日志。Nginx访问日志记录每个请求的状态码、耗时、来源,掌握日志分析技能意味着故障定位从”猜测”变为”证据链”。本文围绕Nginx日志排障展开:日志格式定制、高频故障的日志特征、异常流量定位命令,全部可直接复用。

日志格式定制:为排障预留字段

默认的combined格式缺少请求耗时与上游耗时,排障时信息不足。建议在http块配置包含关键指标的日志格式:

logformat main '$remote_addr - $status [$time_local] "$request" '
               'body=$body_bytes_sent rt=$request_time '
               'urt=$upstream_response_time ustatus=$upstream_status '
               'ua="$http_user_agent" refer="$http_referer"';

access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;

字段含义:rt为Nginx整体处理耗时,urt为上游(PHP-FPM、Tomcat等)响应耗时,两者差值即Nginx自身开销。判断”慢在应用还是慢在转发”就靠这两个数字。按天切割日志交给logrotate,排障前先确认日志时间跨度覆盖故障时段。

五类高频故障的日志特征与定位命令

故障排查按状态码分类切入,每类对应不同的命令组合。

1. 5xx错误定位——先区分是上游挂了还是超时:

# 统计5xx的时间分布,看故障是否集中在某个时间段
awk '$9 ~ /^5/ {print substr($4,2,14)}' access.log | sort | uniq -c | sort -rn | head
# 输出形如: 3402 [16/Sep/2026:14 —— 14点故障爆发

# 提取5xx请求的上游耗时,urt为"-"表示请求根本没到上游(Nginx自身拒绝)
awk '$9 ~ /^5/ {print $11}' access.log | sort | uniq -c | sort -rn | head
# urt大量为"-" → 检查worker连接数与限流规则
# urt接近60s → 上游处理不过来,检查应用线程池/数据库连接池

# 对照error_log找具体原因
grep -i 'upstream timed out\|connect() failed' error.log | tail -20

2. 499状态码——客户端主动断开,通常是前端超时早于后端响应:

# 499请求的rt分布,rt普遍超过3秒说明接口拖死了客户端
awk '$9 == 499 {print $10}' access.log | sort -n | awk '{a[NR]=$1} END {print "中位数:" a[int(NR/2)] "s"}'

3. 慢请求定位——找出拖垮整体性能的接口:

# 按接口聚合平均与最大耗时
awk '{gsub(/\?.*/,"",$6); print $6, $10}' access.log   | awk '{sum[$1]+=$2; cnt[$1]++; if($2>max[$1]) max[$1]=$2} END {for (u in sum) printf "%s avg=%.2fs max=%.2fs cnt=%d
", u, sum[u]/cnt[u], max[u], cnt[u]}'   | sort -t= -k2 -rn | head -20

4. 异常流量识别——同一IP高频请求:

# 单IP请求量TOP10,配合状态码看是否为攻击
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10
# 进一步看这个IP在打哪些接口
grep '^1.2.3.4 ' access.log | awk '{print $6}' | sort | uniq -c | sort -rn

5. 爬虫与扫洞流量:

# 扫描器特征:大量探测路径+高频4xx
awk '$9 ~ /^4/ {print $6}' access.log | sort | uniq -c | sort -rn | head
# 提取可疑UA
awk '{print $14}' access.log | sort | uniq -c | sort -rn | head
# 高频UA直接封禁:在Nginx配置
# if ($http_user_agent ~* "sqlmap|nikto|masscan") { return 403; }

异常流量封禁:动态黑名单方案

静态封IP跟不上攻击节奏,用脚本周期分析日志动态拉黑是运维标配:

#!/bin/bash
# 每5分钟执行,将错误码触发超阈值的IP写入黑名单
LOG=/var/log/nginx/access.log
BLACKLIST=/etc/nginx/conf.d/blacklist.conf
LIMIT=100

awk -v limit=$LIMIT '$9 ~ /^[45]/ {cnt[$1]++} END {for (ip in cnt) if (cnt[ip] > limit) print ip}' $LOG   | sort -u > /tmp/suspects.txt

# 合并新旧黑名单(保留原有条目)
cat $BLACKLIST /tmp/suspects.txt 2>/dev/null | sort -u | while read ip; do
  echo "deny $ip;" >> $BLACKLIST.new
done
mv $BLACKLIST.new $BLACKLIST
nginx -t && nginx -s reload

注意保留白名单逻辑,办公网出口IP与监控探活IP要排除,防止把自己人拉黑。封禁动作本身要留审计记录,脚本中把本次封禁IP写入单独日志,便于事后回溯。

日志分析平台化:从命令行到ELK

单机排障awk够用,多台服务器规模下需要集中式方案:Filebeat采集Nginx日志 → Kafka缓冲 → Logstash解析(grok按上面main格式切字段)→ Elasticsearch存储 → Kibana做状态码趋势图与接口耗时仪表盘。平台化后原来分钟级的awk统计变成秒级面板查询,故障响应速度显著提升。日志保留策略建议:原始日志本机保留7天,ES热数据30天,超过90天的转冷存储。

日志排障的完整路径是:状态码定类 → 时间分布定范围 → 耗时字段定环节 → 命令取证定根因 → 动态封禁防复发。把这套流程固化成运维手册,故障响应不再依赖个人经验。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/wang-zhan-ri-zhi-pai-zhang-shi-zhan-nginx-fang-wen-ri-zhi/

(0)
小编小编
上一篇 1小时前
下一篇 1小时前

相关推荐