Files
Django/deploy/profile-server-lag.sh
2026-07-09 04:41:07 +08:00

131 lines
4.9 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 "=============================================="