131 lines
4.9 KiB
Bash
131 lines
4.9 KiB
Bash
#!/bin/bash
|
||
# 服务器卡顿定位 — 一次跑完,输出「卡在哪一层」结论
|
||
# 用法: bash deploy/profile-server-lag.sh
|
||
|
||
DJANGO_DIR="/opt/1panel/apps/openresty/nginx/www/sites/43.142.166.152.443/django"
|
||
NGINX_LOG="/opt/1panel/apps/openresty/nginx/log/access.log"
|
||
PYTHON="${DJANGO_DIR}/venv/bin/python3"
|
||
cd "$DJANGO_DIR"
|
||
|
||
echo "=============================================="
|
||
echo " 星阙服务器卡顿定位 — $(date '+%Y-%m-%d %H:%M:%S')"
|
||
echo "=============================================="
|
||
|
||
echo ""
|
||
echo ">>> [A] Gunicorn 进程 / 端口"
|
||
systemctl is-active gunicorn-dianjing.service 2>/dev/null || echo "systemd: inactive"
|
||
GC=$(pgrep -cf 'gunicorn.*a_long_dianjing' 2>/dev/null || echo 0)
|
||
echo "gunicorn 进程数: $GC (正常=5: 1master+4worker)"
|
||
ss -ltn 2>/dev/null | grep ':8001' || netstat -ltn 2>/dev/null | grep ':8001' || echo "8001 未监听"
|
||
|
||
echo ""
|
||
echo ">>> [A2] 本机直连 Gunicorn(绕过 Nginx)"
|
||
for path in "/" "/hqhd/"; do
|
||
T=$(curl -s -o /dev/null -w '%{time_total}' --connect-timeout 3 "http://127.0.0.1:8001${path}" 2>/dev/null || echo "FAIL")
|
||
echo " 127.0.0.1:8001${path} -> ${T}s"
|
||
done
|
||
|
||
echo ""
|
||
echo ">>> [B] MySQL 延迟(Django 连接池)"
|
||
"$PYTHON" manage.py shell -c "
|
||
import time
|
||
from django.db import connection
|
||
import app_secrets
|
||
print(f' 当前配置: {app_secrets.DATABASE_HOST}:{app_secrets.DATABASE_PORT} / {app_secrets.DATABASE_NAME}')
|
||
for label, sql in [('连接+查询', 'SELECT 1'), ('订单count', 'SELECT COUNT(*) FROM orders_order WHERE Status IN (1,7)')]:
|
||
t0 = time.perf_counter()
|
||
with connection.cursor() as c:
|
||
c.execute(sql)
|
||
c.fetchone()
|
||
ms = (time.perf_counter() - t0) * 1000
|
||
print(f' [{label}] {ms:.0f}ms')
|
||
" 2>/dev/null || echo " B段失败,请确认 venv 可用"
|
||
|
||
echo ""
|
||
echo ">>> [C] 订单列表 ORM(近似 dddhq 核心查询)"
|
||
"$PYTHON" manage.py shell -c "
|
||
import time
|
||
from django.db import connection, reset_queries
|
||
from django.conf import settings
|
||
from django.db.models import Q
|
||
from orders.models import Order
|
||
settings.DEBUG = True
|
||
reset_queries()
|
||
t0 = time.perf_counter()
|
||
qs = Order.query.filter(Q(Status__in=[1, 7])).order_by('-CreateTime')
|
||
total = qs.count()
|
||
page = list(qs[:5].values('OrderID', 'Status', 'CreateTime'))
|
||
elapsed = (time.perf_counter() - t0) * 1000
|
||
n = len(connection.queries)
|
||
sql_ms = sum(float(q.get('time', 0)) for q in connection.queries) * 1000
|
||
print(f' SQL条数={n} SQL耗时={sql_ms:.0f}ms 总耗时={elapsed:.0f}ms 订单总数={total}')
|
||
" 2>/dev/null || echo " C段失败"
|
||
|
||
echo ""
|
||
echo ">>> [D] Nginx 真实接口 rt=(这是最终体感,最重要)"
|
||
if [ -f "$NGINX_LOG" ]; then
|
||
echo " 最近20条 hqhd:"
|
||
grep -a 'hqhd' "$NGINX_LOG" | tail -20 | while read -r line; do
|
||
RT=$(echo "$line" | grep -oP 'rt=\K[0-9.]+' || echo "?")
|
||
URI=$(echo "$line" | grep -oP '"(GET|POST) \K[^ ]+' || echo "?")
|
||
echo " rt=${RT}s $URI"
|
||
done
|
||
echo ""
|
||
STATS=$(grep -a 'hqhd' "$NGINX_LOG" | tail -500 | grep -oP 'rt=\K[0-9.]+' | sort -n | awk '
|
||
{ a[NR]=$1; sum+=$1 }
|
||
END {
|
||
if(NR==0){ print "NONE"; exit }
|
||
mid=(NR%2)?a[(NR+1)/2]:(a[NR/2]+a[NR/2+1])/2
|
||
printf "%d %.3f %.3f %.3f", NR, mid, sum/NR, a[NR]
|
||
}')
|
||
if [ "$STATS" != "NONE" ]; then
|
||
N=$(echo "$STATS" | awk '{print $1}')
|
||
MID=$(echo "$STATS" | awk '{print $2}')
|
||
AVG=$(echo "$STATS" | awk '{print $3}')
|
||
MAX=$(echo "$STATS" | awk '{print $4}')
|
||
echo " 最近500条: 样本=$N 中位rt=${MID}s 平均rt=${AVG}s 最大rt=${MAX}s"
|
||
echo ""
|
||
if awk -v m="$MID" 'BEGIN{exit(m>0.15)}'; then
|
||
echo " >>> 结论D: API 偏慢(中位>150ms),查数据库/B/C段"
|
||
elif awk -v m="$MID" 'BEGIN{exit(m>0.08)}'; then
|
||
echo " >>> 结论D: API 略慢但可接受(80~150ms)"
|
||
else
|
||
echo " >>> 结论D: 服务器 API 正常(中位<80ms),和2月一样快"
|
||
echo " 若小程序还卡,不是后端接口慢,查:手机网络/图片加载/页面连发多个接口"
|
||
fi
|
||
fi
|
||
echo ""
|
||
echo " 最近慢请求 rt>500ms:"
|
||
grep -a 'hqhd' "$NGINX_LOG" | grep -E 'rt=0\.[5-9]|rt=[1-9]' | tail -10 | while read -r line; do
|
||
RT=$(echo "$line" | grep -oP 'rt=\K[0-9.]+' || echo "?")
|
||
URI=$(echo "$line" | grep -oP '"(GET|POST) \K[^ ]+' || echo "?")
|
||
echo " rt=${RT}s $URI"
|
||
done
|
||
else
|
||
echo " 找不到 $NGINX_LOG"
|
||
fi
|
||
|
||
echo ""
|
||
echo ">>> [E] 系统资源"
|
||
echo " load: $(cat /proc/loadavg 2>/dev/null || uptime)"
|
||
free -h 2>/dev/null | head -2 || true
|
||
journalctl --disk-usage 2>/dev/null | head -1 || true
|
||
|
||
echo ""
|
||
echo ">>> [F] 请求最多的 IP+接口"
|
||
if [ -f "$NGINX_LOG" ]; then
|
||
tail -3000 "$NGINX_LOG" | grep -a 'hqhd' | awk '{
|
||
for(i=1;i<=NF;i++) if($i ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) ip=$i
|
||
if(match($0, /"(GET|POST) ([^ ]+)/, m)) uri=m[2]
|
||
if(ip && uri) c[ip" "uri]++
|
||
} END {
|
||
n=0
|
||
for(k in c) arr[n++]=c[k]" "k
|
||
asort(arr)
|
||
for(i=n;i>0 && i>n-10;i--) print " "arr[i]
|
||
}' 2>/dev/null || true
|
||
fi
|
||
|
||
echo ""
|
||
echo "=============================================="
|