當服務器壓力大時,需快速定位「訪問量大」且「響應慢」的頁面進行針對性優化。本文提供一個實用的 Shell 腳本,模仿 MySQL Slow Query 概念,從 Nginx Access Log 中統計 Top 30 高頻頁面與慢頁面。
關鍵在於 $request_time 放在最後一列,便於 awk 用 $NF 直接取值:
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';
access_log /var/log/nginx/access.log main buffer=32k;
字段結構:$1=客戶端 IP,$7=請求 URL(含查詢參數),$NF=請求耗時(秒)。
slow.sh#!/bin/sh
export PATH=/usr/bin:/bin:/usr/local/bin:/usr/X11R6/bin
export LANG=zh_CN.GB2312
usage() {
echo "Usage: $0 <1|2>"
echo " 1: Top 30 最高訪問量頁面"
echo " 2: Top 30 平均耗時最長頁面(慢查詢)"
exit 1
}
slowlog() {
local file=$1
local opt=$2
local field=3 end=4 msg="平均訪問時間統計"
[[ $opt == '1' ]] && { field=1; end=2; msg="總訪問次數統計"; }
echo -e "\n\n${msg}#############################"
awk -F' ' '
{
split($7, url_parts, "?") # 去除查詢參數
url = url_parts[1]
count[url]++
total_time[url] += $NF
}
END {
for (u in count) {
avg = total_time[u] / count[u]
printf "%s:%d:%.3f:%.4f\n", u, count[u], total_time[u], avg
}
}' "$file" | sort -t: -k${field},${field}nr | grep "pages" | head -30 | sed 's/:/\\t/g'
}
[[ $# -lt 2 ]] && usage
slowlog "$1" "$2"
chmod +x slow.sh
./slow.sh /var/log/nginx/access.log 1 # 高頻頁面
./slow.sh /var/log/nginx/access.log 2 # 慢查詢頁面
輸出格式(Tab 分隔):
URL 訪問次數 總耗時(秒) 平均耗時(秒)
/pages/abc.php 4 120.456 30.114
/pages/xyz.php 212 1122.49 5.295
split($7, "?") 去除查詢參數,聚合同一路徑count[url](次數)與 total_time[url](總耗時)sort -t: -k${field}nr 切換按次數(第1欄)或平均耗時(第4欄)倒序grep "pages" 僅關注業務頁面,排除靜態資源、健康檢查等awk '{print $7, $NF}' 抽取必要列再處理,減少 I/Ogoaccess、ELK 等可視化工具做長期趨勢分析