优化后台服务需先识别真实瓶颈:用pidstat、pstack、vmstat交叉验证CPU/内存/I/O,区分同步异步延时方式,合理配置systemd资源限制与数据库连接池。
优化后台服务进程不能靠“重启大法”或盲目调高并发数——关键在识别真实瓶颈,再针对性调整资源分配、i/o 模式和生命周期管理。
怎么判断是 CPU、内存还是 I/O 瓶颈?
直接看 top 或 htop 会误导:一个进程显示 90% CPU 占用,可能是它在死循环,也可能是它刚从磁盘读完数据正密集计算。更可靠的方式是交叉验证:
- 用
pidstat -u -p看该进程每秒实际用户态/内核态时间占比1 - 用
pidstat -d -p查块设备 I/O(1 Blk_read/s和Blk_wrtn/s是否持续高位) - 用
pstack抓栈,看线程是否卡在read()、epoll_wait()或malloc()上 - 如果
vmstat 1中wa(I/O wait)长期 >20%,且si/so(swap in/out)不为 0,大概率是内存不足触发了交换
Python 后台服务里 time.sleep() 和 asyncio.sleep() 别混用
同步框架(如 Flask + threading.Thread)里写 asyncio.sleep() 不生效,还会报 RuntimeWarning: coroutine 'sleep' was never awaited;而异步服务(FastAPI + uvicorn --loop asyncio)里用 time.sleep() 会阻塞整个事件循环。常见错误场景:
- 定时任务用
APScheduler+ThreadPoolExecutor,但任务函数里调了asyncio.sleep(5)→ 实际没暂停,还可能引发未处理的协程警告 - 用
aiofiles异步读配置文件,却在后续逻辑里穿插time.sleep(1)→ 整个 worker 被锁住 1 秒,QPS 直接腰斩 - 正确做法:同步服务统一用
time.sleep();异步服务所有延时、I/O 都走await,包括await asyncio.sleep()、await aiofiles.open()
systemd 服务配置里这 4 个参数最常被忽略
很多人只改 ExecStart 和 Restart,但以下参数直接影响进程行为:
-
MemoryLimit=512M:防止 OOM 杀掉进程前先软限流,比 kernel OOM killer 更可控 -
TasksMax=512:限制该服务能创建的线程/进程总数,避免 fork 爆炸(尤其 Python 多进程场景) -
LimitNOFILE=65536:必须和应用层ulimit -n一致,否则Too many open files错误照出 -
Environment="PYTHONUNBUFFERED=1":避免日志缓冲导致故障时看不到最后几行输出
改完别忘了 sudo systemctl daemon-reload && sudo systemctl restart your-service,光 reload 不重启不会生效。
数据库连接池大小不是越大越好
PostgreSQL 的 max_connections 默认 100,但你的 Python 服务设 pool_size=50 就已经危险——每个连接至少占几 MB 内存,且后端进程数超阈值后,CPU 会在连接间频繁切换,反而降低吞吐。实测经验:
- Web 请求类服务(短连接为主),
pool_size = CPU 核心数 × 2 ~ 4足够,比如 4 核机器设 8~12 - 长事务或批量导出类任务,单独建一个低频连接池,避免挤占主服务资源
- 用
ps aux | grep postgres | grep your_db数真实后端数,持续接近max_connections就得调小应用层池子,而不是去调大数据库上限
真正卡顿的时候,人第一反应往往是加资源,但多数情况是某条慢查询没加索引、某个日志级别设成了 DEBUG、或者健康检查接口没做缓存——这些比调 systemd 参数影响更大,也更容易被跳过。










