You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法直连MySQL时,如何通过SqlAlchemy获取FastAPI应用的DB指标?

从SQLAlchemy获取数据库连接/性能指标排查FastAPI连接冻结问题

一、连接池核心指标(从Engine对象获取)

连接池状态是排查连接冻结的核心依据,这些指标能直接反映池内连接的使用负载:

  • 已被占用的连接数:engine.pool.checkedout()
  • 空闲待使用的连接数:engine.pool.checkedin()
  • 连接池配置的最大容量:engine.pool.size()
  • 超出池容量的临时连接数:engine.pool.overflow()

二、会话与连接关联指标(从Session对象获取)

每个Session对应一个底层数据库连接,这些指标能追踪会话的实时状态:

  • 会话是否绑定了活跃连接:db.is_active
  • 底层连接的唯一标识(用于区分不同连接实例):id(db.connection())
  • 连接存活时长(需配合事件监听实现):记录连接创建时间,计算当前时长

三、整合指标的日志示例(替换你的logger.info)

把这些指标嵌入到你的get_db函数中,修改后的代码如下:

from sqlalchemy import event
from datetime import datetime

# 存储连接创建时间的字典,用于计算连接存活时长
connection_create_times = {}

# 监听连接创建事件,记录每个连接的生成时间
@event.listens_for(engine, "connect")
def record_connect_time(dbapi_connection, connection_record):
    connection_create_times[id(dbapi_connection)] = datetime.now()

def get_db() -> Session:
    db = SessionLocal()
    # 提取连接池指标
    pool_checkedout = engine.pool.checkedout()
    pool_checkedin = engine.pool.checkedin()
    pool_size = engine.pool.size()
    pool_overflow = engine.pool.overflow()
    
    # 提取会话与连接的关联指标
    session_active = db.is_active
    conn_id = id(db.connection()) if session_active else "N/A"
    conn_age = (datetime.now() - connection_create_times.get(conn_id, datetime.now())).total_seconds() if session_active else 0
    
    # 输出整合后的指标日志
    logger.info(
        f"DB Session Metrics - "
        f"Pool: 已占用={pool_checkedout}, 空闲={pool_checkedin}, 容量={pool_size}, 溢出={pool_overflow} | "
        f"Session: 活跃={session_active}, 连接ID={conn_id}, 连接存活时长={conn_age:.2f}s"
    )
    try:
        yield db
    except Exception as exc:
        db.rollback()
        logger.error(f'DBRROR: {traceback.format_exc()}')
        raise exc
    finally:
        # 可选:会话关闭时记录连接归还日志
        logger.debug(f"会话关闭,连接{conn_id}归还至连接池")
        db.close()
        # 清理已关闭连接的时间记录
        if conn_id in connection_create_times:
            del connection_create_times[conn_id]

四、排查方向提示

  • 如果pool_checkedout长期等于pool_size+pool_overflow,说明连接池被完全占满,大概率是会话未被正确关闭(检查所有使用db的代码路径是否走到了finally块)
  • 若conn_age超过你设置的pool_recycle值(你当前设了57400秒,但MySQL默认wait_timeout是28800秒),说明连接可能已失效却未被回收,需要调整pool_recycle到小于MySQL的超时时间
  • 临时开启engine = create_engine(..., echo=True),可以看到所有SQL执行和连接的建立/关闭日志,快速定位慢查询或异常连接操作

内容的提问来源于stack exchange,提问作者Vyacheslav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 22:22:18