故障表现

接口压测到几十并发就开始报连接池超限,等一会儿又恢复,日志里 timeout 30 秒的字样反复出现。

问题出在哪

会话没有在请求结束时关闭,或者长事务一直占用连接,池子被少数请求占满后新请求只能排队。判断时先分清是 SQLAlchemy 连接池耗尽 本身的配置问题,还是上游调用、运行环境带进来的差异;前者改配置就能收口,后者要沿着请求链路一层层往上找,处理顺序不能颠倒。先在出问题的机器上复现一次,把报错原文和发生时间记下来,再对着日志定位。

按这个顺序处理

  1. 确认每个请求路径都有 session.close 或上下文管理
  2. 检查是否有查询忘了提交导致事务挂起
  3. 按实际并发调整池大小并加超时

对应的命令或配置片段如下,可直接复制:

engine = create_engine(URL, pool_size=20, max_overflow=10, pool_timeout=10, pool_recycle=1800)
with Session(engine) as s:
    rows = s.execute(text('select 1')).all()

不要一次改多个参数,每次只动一处并记录下来,否则现象变了也说不清是哪个改动起的作用。改完只在一台机器上验证不够,至少从外网和移动网络各试一次,才能确认不是本地缓存造成的假象。

怎么确认改好了

压测时观察连接数稳定在池上限以内且不再出现超时报错,接口平均耗时回落即正常。

作者 9823189