Nginx 访问日志記錄了每個請求的完整信息,是排查性能瓶頸、發現攻擊、分析用戶行為的金礦。本文涵蓋日志格式自定義、緩衝刷盤策略、關鍵變量提取、控制字符分隔、AWK 實戰分析命令、實時監控、大規模日志處理架構。

# nginx.conf http 段
log_format main_escape '$remote_addr^A$http_x_forwarded_for^A$host^A$time_local^A$status^A'
'$request_time^A$request_length^A$bytes_sent^A$http_referer^A$request^A$http_user_agent';
access_log /var/log/nginx/access.log main_escape buffer=32k flush=5s;
關鍵點:
^A (Ctrl+V, Ctrl+A) 不可見字符,避免 URL/UA 中空格、引號干擾解析。buffer=32k flush=5s:累積 32KB 或 5 秒刷盤,平衡實時性與磁盤 IO。$request_time(請求處理時間)、$request_length(請求體大小)、$bytes_sent(響應體大小)、$connection(連接序號)、$connection_requests(該連接請求數)。
error_log /var/log/nginx/error.log warn; # 生產建議 warn,調試時 debug
假設日志文件 access.log,分隔符為 ^A(AWK 中用 \x01 表示)。
# Top 20 訪問 URL
awk -F'\x01' '{print $10}' access.log | sort | uniq -c | sort -rn | head -20
# Top 20 客戶端 IP
awk -F'\x01' '{print $1}' access.log | sort | uniq -c | sort -rn | head -20
# Top 20 User-Agent
awk -F'\x01' '{print $11}' access.log | sort | uniq -c | sort -rn | head -20
# 5xx 錯誤請求詳情
awk -F'\x01' '$5 ~ /^5/ {print $0}' access.log
# 5xx 錯誤計數
awk -F'\x01' '$5 ~ /^5/ {count++} END {print count}' access.log
# 特定分鐘 5xx 數量 (如 09:00)
awk -F'\x01' '$5 ~ /^5/ && $4 ~ /09:00/ {count++} END {print count}' access.log
# 404 頻繁 URL
awk -F'\x01' '$5 == 404 {print $10}' access.log | sort | uniq -c | sort -rn | head -20
# 請求耗時 > 1s 的慢請求 (實時跟蹤)
tail -f access.log | awk -F'\x01' '$6 > 1 {print $0}'
# 慢請求僅看關鍵字段 (URL、耗時、UA)
tail -f access.log | awk -F'\x01' '$6 > 1 {print $3 "|" $4 "|" $10 "|" $6}'
# 平均響應時間
awk -F'\x01' '{sum+=$6} END {if (NR>0) print sum/NR}' access.log
# 請求體/響應體大小分析
awk -F'\x01' '{req+=$7; resp+=$8} END {print "AvgReq:" req/NR " AvgResp:" resp/NR}' access.log
# 502 錯誤最多的 URL (上游故障)
awk -F'\x01' '$5 == 502 {print $10}' access.log | sort | uniq -c | sort -rn | head -20
# 200 但響應極小 (疑似空白頁/攔截)
awk -F'\x01' '$5 == 200 && $8 < 100 {print $3 "|" $4 "|" $10 "|" $6}' access.log
# 同一 IP 短時內高頻請求 (疑似 CC 攻擊)
awk -F'\x01' '{print $1 "|" $4}' access.log | sort | uniq -c | sort -rn | head -20
# 實時顯示帶分隔符的原始行
tail -f access.log | cat -vte # ^A 顯示為 ^A
# 實時替換 ^A 為 | 便於閱讀
tail -f access.log | tr '\x01' '|'
# 實時過濾特定狀態碼
tail -f access.log | awk -F'\x01' '$5 ~ /^5/ {print strftime("%H:%M:%S"), $0}'
| 階段 | 方案 | 適用規模 | 核心組件 |
|---|---|---|---|
| 單機臨時分析 | AWK / grep / sort / GoAccess | < 1GB/天 | 命令行工具 |
| 多機集中收集 | Filebeat/Fluentd + Kafka + Logstash + Elasticsearch | 10GB-1TB/天 | ELK Stack / EFK |
| 實時流計算 | Flink / Spark Streaming / ClickHouse | > 1TB/天 | 流處理引擎 + OLAP |
| 雲原生觀測 | Loki + Promtail + Grafana / Datadog / 阿里云 SLS | 全規模 | 托管服務 |
# 安裝
apt install goaccess # 或 yum/brew
# 生成 HTML 報告
goaccess /var/log/nginx/access.log \
--log-format='%h^A%^A%v^A%t^A%s^A%T^A%b^A%R^A%r^A%u' \
--date-format=%d/%b/%Y \
--time-format=%H:%M:%S \
-o /var/www/html/nginx-report.html \
--real-time-html
瀏覽器打開報告,獲得請求分布、狀態碼、瀏覽器、地理位置、熱力圖等儀表板。
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 640 nginx adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
log_format 過濾或 ngx_http_lua_module 處理。chmod 750、chown nginx:adm,僅運維/安全部訪問。善用 Nginx 日志,能將「黑盒」流量變為可觀測、可分析、可決策的資產。從控制字符分隔到 ELK 落地,每一步都在提升運維效能與業務洞察力。