perf: server/status接口优化(cpu非阻塞+pm2直接调用+COUNT估算+5秒缓存)

This commit is contained in:
root 2026-02-27 18:46:56 +00:00
parent fbf84f2be5
commit 748f6f57a5

View File

@ -458,11 +458,40 @@ async def get_signal_trades(
import shutil, subprocess, psutil import shutil, subprocess, psutil
# 服务器状态缓存(避免重复调用慢操作)
_server_cache: dict = {"data": None, "ts": 0}
_PM2_BIN = None
def _find_pm2_bin():
"""找到pm2二进制路径避免每次走npx"""
global _PM2_BIN
if _PM2_BIN:
return _PM2_BIN
import shutil as _sh
for p in ["/home/fzq1228/.local/bin/pm2", "/usr/local/bin/pm2", "/usr/bin/pm2"]:
if os.path.exists(p):
_PM2_BIN = p
return p
found = _sh.which("pm2")
if found:
_PM2_BIN = found
return found
return "npx pm2"
# 启动时初始化CPU采样首次调用不阻塞
psutil.cpu_percent(interval=None)
@app.get("/api/server/status") @app.get("/api/server/status")
async def get_server_status(user: dict = Depends(get_current_user)): async def get_server_status(user: dict = Depends(get_current_user)):
"""服务器全状态CPU/内存/硬盘/负载/PM2进程/PG数据库/回补进度""" """服务器全状态CPU/内存/硬盘/负载/PM2进程/PG数据库/回补进度"""
# CPU
cpu_percent = psutil.cpu_percent(interval=0.5) # 5秒缓存避免频繁调用慢操作
now = time.time()
if _server_cache["data"] and (now - _server_cache["ts"]) < 5:
return _server_cache["data"]
# CPU非阻塞取上次采样间隔的值
cpu_percent = psutil.cpu_percent(interval=None)
cpu_count = psutil.cpu_count() cpu_count = psutil.cpu_count()
# 内存 # 内存
@ -482,12 +511,14 @@ async def get_server_status(user: dict = Depends(get_current_user)):
# 网络IO # 网络IO
net = psutil.net_io_counters() net = psutil.net_io_counters()
# PM2进程状态 # PM2进程状态直接调pm2二进制不走npx
pm2_procs = [] pm2_procs = []
try: try:
pm2_bin = _find_pm2_bin()
cmd = [pm2_bin, "jlist"] if not pm2_bin.startswith("npx") else ["npx", "pm2", "jlist"]
result = subprocess.run( result = subprocess.run(
["npx", "pm2", "jlist"], cmd,
capture_output=True, text=True, timeout=10 capture_output=True, text=True, timeout=5
) )
import json as _json import json as _json
procs = _json.loads(result.stdout) procs = _json.loads(result.stdout)
@ -504,7 +535,7 @@ async def get_server_status(user: dict = Depends(get_current_user)):
except Exception: except Exception:
pm2_procs = [] pm2_procs = []
# PG数据库大小 + agg_trades条数 # PG数据库大小 + agg_trades条数用估算值快1000倍
pg_info = {} pg_info = {}
try: try:
row = await async_fetchrow( row = await async_fetchrow(
@ -512,10 +543,15 @@ async def get_server_status(user: dict = Depends(get_current_user)):
) )
pg_info["db_size_mb"] = round(row["db_size"] / 1024 / 1024, 1) if row else 0 pg_info["db_size_mb"] = round(row["db_size"] / 1024 / 1024, 1) if row else 0
row2 = await async_fetchrow("SELECT COUNT(*) as cnt FROM agg_trades") # 用PG统计信息估算行数毫秒级而非COUNT(*)的秒级全表扫描)
pg_info["agg_trades_count"] = row2["cnt"] if row2 else 0 row2 = await async_fetchrow(
"SELECT SUM(n_live_tup)::bigint as cnt FROM pg_stat_user_tables WHERE relname LIKE 'agg_trades%'"
)
pg_info["agg_trades_count"] = row2["cnt"] if row2 and row2["cnt"] else 0
row3 = await async_fetchrow("SELECT COUNT(*) as cnt FROM rate_snapshots") row3 = await async_fetchrow(
"SELECT n_live_tup::bigint as cnt FROM pg_stat_user_tables WHERE relname = 'rate_snapshots'"
)
pg_info["rate_snapshots_count"] = row3["cnt"] if row3 else 0 pg_info["rate_snapshots_count"] = row3["cnt"] if row3 else 0
# 各symbol最新数据时间 # 各symbol最新数据时间
@ -542,7 +578,7 @@ async def get_server_status(user: dict = Depends(get_current_user)):
except Exception: except Exception:
pass pass
return { result = {
"timestamp": int(time.time() * 1000), "timestamp": int(time.time() * 1000),
"cpu": { "cpu": {
"percent": cpu_percent, "percent": cpu_percent,
@ -574,3 +610,6 @@ async def get_server_status(user: dict = Depends(get_current_user)):
"postgres": pg_info, "postgres": pg_info,
"backfill_running": backfill_running, "backfill_running": backfill_running,
} }
_server_cache["data"] = result
_server_cache["ts"] = now
return result