惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Martin Fowler
Martin Fowler
Webroot Blog
Webroot Blog
博客园 - 叶小钗
阮一峰的网络日志
阮一峰的网络日志
V
V2EX
雷峰网
雷峰网
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 【当耐特】
Hugging Face - Blog
Hugging Face - Blog
美团技术团队
云风的 BLOG
云风的 BLOG
IT之家
IT之家
S
Secure Thoughts
U
Unit 42
G
GRAHAM CLULEY
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
N
News and Events Feed by Topic
The Cloudflare Blog
月光博客
月光博客
V
Visual Studio Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Schneier on Security
Schneier on Security
O
OpenAI News
Hacker News - Newest:
Hacker News - Newest: "LLM"
P
Privacy International News Feed
The Hacker News
The Hacker News
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
Tailwind CSS Blog
SecWiki News
SecWiki News
M
MIT News - Artificial intelligence
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Simon Willison's Weblog
Simon Willison's Weblog
Stack Overflow Blog
Stack Overflow Blog
爱范儿
爱范儿
Last Week in AI
Last Week in AI
C
Check Point Blog
D
Docker
Scott Helme
Scott Helme
Engineering at Meta
Engineering at Meta
博客园_首页
W
WeLiveSecurity
MongoDB | Blog
MongoDB | Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
Vulnerabilities – Threatpost
D
Darknet – Hacking Tools, Hacker News & Cyber Security
J
Java Code Geeks
NISL@THU
NISL@THU
S
Security Affairs
C
Cybersecurity and Infrastructure Security Agency CISA
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 一名程序媛呀

Anki插件开发必知必会:钩子函数与右键菜单定制 httpx 传参总报错?这次把 GET、POST、文件上传到响应处理的坑给你一次填平 从卡顿到丝滑:FastAPI 调用外部 API 的正确姿势(httpx 实战) 还在 XHR、Fetch 和 Axios 之间纠结?我踩过的坑,希望你一个都不用碰到 你的REST接口还在“过度投喂”数据吗?——FastAPI + GraphQL实战避坑指南 Uvicorn、Gunicorn 傻傻分不清?FastAPI 生产部署避坑指南 Termux里的二进制和脚本,到底怎么运行才不踩坑?Termux-service 保活妙招! 刚部署的 LibreTranslate 频频翻车?我掏出了 20 年前的 StarDict 词典,用 FastAPI 搭了个本地词典翻译 API 别再用网页翻译看源码了!你的私人翻译神器LibreTranslate,部署避坑指南来了 掏出手机就能搭个 WebDAV 同步服务器?这操作有点香 别只盯着GitBook了!这个文档神器让你的笔记秒变网站 写爬虫时用了代理还被封?Python 代理的那些隐藏坑,我替你踩明白了 FastAPI 身份验证总踩坑?这份 FastAPI Users “避坑指南”请收好 旧手机别扔!用 Termux 搭个私人云盘,比网盘香多了 你的FastAPI又在服务器上“跑不起来”了?来,今天咱把打包这件事彻底聊透 写页面时别再把 Element Plus 整个搬进来啦!Vue3按需加载的坑我帮你踩平了 前端包管理咋选?我从npm叛逃到pnpm的血泪史(附避坑指南) 聊聊 fetch 使用中我踩过的那些坑和正确打开方式 FastApiAdmin 后端接口开发好了,前端管理界面怎么调用与显示? 给 FastApiAdmin 加个“会议纪要”模块,我把后端二次开发的坑踩了个遍 我用了FastApiAdmin后,连夜把踩过的坑都整理出来了 告别 Typora 后的新欢:我把所有笔记迁移到了 Obsidian 这个“第二大脑” 你的Agent API还在裸奔?从认证到沙箱,我用FastAPI搭了几道防线 让 FastAPI Agent 思考不阻塞:手把手教你实现异步任务与后台处理方案 让FastAPI Agent真正记住你:聊聊会话记忆与持久化存储的落地实践 FastAPI Agent 函数调用实战:我让 AI 学会了“自己动手查天气“ 初探:用 FastAPI 搭建你的第一个 AI Agent 接口 FastAPI 少有人提的实用技巧:把 Depends 依赖提到路由层,代码少写60% FastAPI 生产环境静态文件完全指南:从 /favicon.ico 404 到 HSTS 混合内容,一次全根治 用了loguru我才明白,Python日志还能这么写 FastAPI 后台任务:BackgroundTasks 的使用场景与注意事项 FastAPI配置管理避坑指南:从硬编码到 .env 与 pydantic_settings 类,连路由用法都给你捋清楚 FastAPI 文件上传避坑全指南:分块存盘、类型校验与安全兜底 FastAPI + Pydantic 模型终极实战手册:从能跑就行到固若金汤,这些技巧你一定用得上 FastAPI + SQLAlchemy 2.0 通用CRUD操作手册 —— 从同步到异步,一次讲透 FastAPI订单防超卖实战:从数据库锁到Saga分布式事务,这一篇给你理清了 FastAPI 生产环境避坑指南:用 Alembic 管理数据库迁移,别再手动改表结构了! FastAPI数据库ORM怎么选?我肝了三个Demo后,终于不再纠结了 Vue 3 组件通信,别只会用 Props 和 Emits 了,这几个狠活儿你得看看 Vue 3 组合式 API 香是香,但从Vue2迁移时你可别像我当初一样踩进这 3 个深坑里 我用fastapi-scaff搭了个项目,两天工期缩到两小时,老板以为我开挂了 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! FastAPI自动生成的API文档太丑?我花了一晚上把它改成了客户愿意付费的样子 告别手写 API 胶水代码:FastAPI 与 Vue 的“契约自动机” OpenAPI 实战 FastAPI + Vue 前后端分离实战:我的项目结构“避坑指南” FastAPI + Celery 实战:异步任务里调用 Redis 和数据库的全解析,及生产级组织方案 FastAPI里玩转Redis和数据库的正确姿势,别让异步任务把你坑哭了! FastAPI + Celery 实战:异步任务的坑与解法,我帮你踩了一遍 FastAPI子应用挂载:别再让root_path坑你一夜 FastAPI项目半夜报警吵醒你?聊聊告警这事儿怎么搞! 别再数据线了!用FastAPI 5分钟搭个局域网文件+剪贴板神器 FastAPI单元测试实战:别等上线被喷才后悔,TestClient用对了真香! FastAPI状态共享秘籍:别再让中间件、依赖和路由“各自为政”了! FastAPI实战:WebSocket vs Socket.IO,这回真给我整明白了! 从0到1,FastAPI + PostgreSQL + Tortoise ORM 实战避坑指南 FastAPI + PostgreSQL 实战:给应用装上“缓存”和“日志”翅膀 FastAPI + PostgreSQL 实战:从入门到不踩坑,一次讲透
FastAPI服务半夜又挂了?先别急着重启,查查你的数据库连接池“池子”是不是漏了
一名程序媛呀 · 2026-04-20 · via 博客园 - 一名程序媛呀

是不是觉得你的 FastAPI 服务像个长不大的孩子,白天活蹦乱跳,一到夜深人静流量低谷时就给你来个假死、无响应?然后你迷迷糊糊被报警叫醒,骂骂咧咧重启一下又好了,仿佛什么都没发生过。第二天顶着黑眼圈去看日志,除了几条模糊的 “connection timeout” 啥也抓不住。🎯 如果这剧情你熟,那今天这篇,大概率是你的菜。

今天咱们不扯虚的,就解决一件事:让你的 FastAPI 跟数据库打交道时,别再因为连接池那点破事儿掉链子。我会从原理到参数,再到监控,把我踩过的坑变成你的垫脚石。


🎯 案例模拟

那是某个凌晨三点,手机跟抽风一样狂震。线上服务接口响应时间从 50ms 飙升到 30s,然后直接 timeout。

你睡眼惺忪地连上服务器,一看进程还在,但就是死活连不上数据库。日志里躺着一堆 QueuePool limit of size ... overflow ... reached ,当时就懵了,心想:“我这大半夜的又没流量,连接池怎么就满了呢?”

重启大法好啊,服务瞬间恢复。但这就像止疼药,治标不治本。第二天你扒了一层皮才发现,原来是 MySQL 那边的 wait_timeout 把空闲连接给杀了,而 SQLAlchemy 的连接池还傻乎乎地以为连接活着,拿起来就用,结果一用一个不吱声。

所以,官方文档还是要仔细看啊,以前总觉得默认参数就是最佳实践,结果被现实狠狠打脸。数据库连接池这玩意儿,没有银弹,默认配置只保证你能跑,不保证你跑得稳。

🍜 先听个故事:为啥非得要个“池子”?

好,咱们先来点轻松的。把数据库想象成一家火爆的餐厅后厨,每个请求就是一个来吃饭的客人。

- 没有连接池的时候:

来一个客人,服务员现场跑去后厨招一个厨师(建立TCP连接,握手认证),做完菜立马把厨师开了(关闭连接)。客人一多,光雇厨师和开厨师的时间就占了90%,后厨门都要被挤爆了。

- 有连接池的时候:

提前雇好一群厨师在后厨待命( pool_size ),来客人了直接分配一个厨师去炒菜,炒完了厨师不辞退,而是回到休息室等着(回到池子)。这效率,天差地别。

所以连接池的核心就是仨字:复用、省心、有序。 减少了 TCP 握手的开销,还能限制你最多能开多少连接,防止把数据库给冲垮。

🔧 四个参数,保你平安(重点!)

FastAPI 底下通常用 SQLAlchemy,而 SQLAlchemy 的队列池(QueuePool)有四个参数,你必须在配置里混个脸熟。别怕,我用大白话给你翻译。

- pool_size=5 常驻厨师数量。 后厨里常年保持待命的“正式工”。设太小了吞吐量上不去,设太大了数据库那边该骂娘了(数据库总连接数有限制)。

- max_overflow=10 临时工上限。 高峰期客人太多,正式工忙不过来,可以招点临时工。但最多只能再招这么多。高峰期一过,临时工会自动辞退。

- pool_recycle=3600 健康体检时间。 每个连接(厨师)上岗满1小时,不管有没有活,强制让他退休,换新人。
这就是为了防止数据库那边因为长时间没动静,偷偷把连接给掐了(比如MySQL默认8小时wait_timeout),咱们自己先主动点。

- pool_pre_ping=True 上岗前喊一嗓子。 从池子里拿连接之前,先发个简单的 SELECT 1 探探路。如果对面没反应(连接被杀了),直接扔掉换个新的。
这个参数是救命稻草,我强烈建议你设为 True,虽然有一丢丢性能开销,但跟半夜被叫起来相比,这都不是事儿。

再说个容易翻车的点:
pool_size 到底设多少?网上那些抄来抄去的公式 (CPU核心数 * 2) + 有效磁盘数 是个参考,但千万别当圣旨。
根据以往的经验,对于 FastAPI 这种异步框架,因为并发高,连接占用时间短, pool_size 反而可以比同步框架(Django)设得小一点,比如 10-20 之间,然后靠 max_overflow 去扛突发流量。具体是多少,往下看监控部分。

👀 光说不练假把式,监控得支棱起来

是不是以为参数配好就完了?Too young!参数调优没有监控,那就跟盲人开车一样——全靠运气。咱们得把连接池的底裤扒开看看。

好在 SQLAlchemy 留了后门——事件监听。我们可以写几行代码,把连接池的状态暴露给 Prometheus。

# 这段代码可以直接塞进你的 FastAPI 启动事件里
from sqlalchemy import event
from prometheus_client import Gauge

# 定义几个仪表盘指标
pool_size_gauge = Gauge('db_pool_size', 'Current pool size')
checked_out_gauge = Gauge('db_pool_checked_out', 'Connections currently in use')
overflow_gauge = Gauge('db_pool_overflow', 'Current overflow connections')

def collect_pool_metrics(db_pool):
    pool_size_gauge.set(db_pool.size())
    checked_out_gauge.set(db_pool.checkedout())
    overflow_gauge.set(db_pool.overflow())

# 监听从池子里拿连接的事件(checkout)
@event.listens_for(engine, 'checkout')
def receive_checkout(dbapi_conn, conn_record, conn_proxy):
    collect_pool_metrics(conn_proxy._pool)

# 监听归还连接的事件(checkin)
@event.listens_for(engine, 'checkin')
def receive_checkin(dbapi_conn, conn_record):
    collect_pool_metrics(conn_record._pool)

把这几个指标挂到 /metrics 端点,用 Grafana 画个图,你会看到一个全新的世界:

- 场景一: checked_out  长时间逼近 pool_size + max_overflow,并且出现等待。结论:池子太小了,加人!

- 场景二: overflow 常年大于0,高峰期更离谱。结论:把 pool_size 调大点,别老招临时工,不稳定。

- 场景三: 半夜一看图,checked_out 归零,但 overflow 偶尔跳一下。结论:没事,那是 pool_pre_ping 在体检呢。

🚨 两个经典陷阱,早看早脱身

1. 连接泄漏(Leak):

用了 Depends 注入 Session 但忘了关闭?或者在一个无限循环里开了连接没 commit/close?这就是典型的“厨师借出去没还回来”。时间一长,池子里的连接全被占着,新请求直接排队等死。

解法: 死都要用 with 上下文管理器,或者 FastAPI 里用 yield 依赖,保证请求结束把连接还回去。

2. 首次请求卡顿:

服务刚启动,池子是空的。第一个倒霉蛋请求进来时,不仅要处理业务,还得负责把 pool_size 个连接建立起来。这就是“冷启动”的代价。

解法:startup 事件里,手动执行一次 await db.execute("SELECT 1") ,强迫连接池提前预热,别让第一个用户当冤大头。


最后啰嗦一句

技术这玩意儿,说白了就是经验的积累。今天我把那些坑填平了给你看,就是希望你的服务器日志能干干净净,你也能安安稳稳睡到大天亮。这篇文章里的代码和思路,都是我亲手试过的,放心拿去用,不好使回来打我脸(反正也打不着😏)。

如果你觉得这顿“技术烧烤”吃得还算过瘾,或者帮你省下了一瓶速效救心丸的钱,别藏着掖着,点个赞,加个关注,分享给那个还在为连接池抓狂的同事。关注我,咱们下次接着聊 FastAPI 那些不能说的秘密,保你少走几年弯路。🚀