使用Lambda+pymysql连接AWS RDS的最佳实践及连接复用疑问
AWS Lambda 连接 Aurora Serverless:连接池使用指南
一、每次请求新建连接是否可行?
短期低并发场景下,直接在Lambda函数内用pymysql.connect(...)新建数据库连接是可以正常工作的,但在高并发或频繁触发的场景下会暴露明显问题:
- 每次新建连接都要经历TCP握手、身份验证等流程,会额外增加请求延迟
- Aurora Serverless(尤其是v1版本)有连接数上限,大量并发请求会快速耗尽连接配额,导致请求失败
- Lambda冷启动时,新建连接的开销会进一步拉长响应时间
二、Lambda场景下连接池的适用时机
当你的业务符合以下任一情况时,建议使用连接池:
- 高并发请求:每秒触发多次Lambda,执行环境复用概率高
- 频繁触发的业务:比如定时任务或高频API请求,容器会被AWS持续复用
- 延迟敏感型应用:需要尽可能降低数据库连接带来的额外耗时
三、Lambda中实现连接池的正确方式
核心原则:连接池放在全局作用域
Lambda的执行环境会被复用,把连接池初始化代码放在函数外部(全局变量区),就能让后续请求复用已创建的连接池,避免重复初始化。
代码示例(基于pymysql + DBUtils)
- 先在Lambda层或部署包中安装依赖:
DBUtils、pymysql - 编写Lambda代码:
import pymysql from DBUtils.PooledDB import PooledDB # 全局作用域初始化连接池 pool = None def init_pool(): global pool pool = PooledDB( creator=pymysql, host=rds_host, user=name, passwd=password, db=db_name, mincached=1, # 初始空闲连接数 maxcached=5, # 最大空闲连接数 maxconnections=10, # 最大连接数 blocking=True # 连接耗尽时阻塞等待 ) def lambda_handler(event, context): global pool # 首次执行或连接池未初始化时创建 if not pool: init_pool() # 从连接池获取连接 conn = pool.connection() try: with conn.cursor() as cursor: # 执行数据库操作 cursor.execute("SELECT * FROM your_table") result = cursor.fetchall() return {"statusCode": 200, "data": result} finally: # 归还连接到池(不要关闭,由连接池管理) conn.close()
关键注意事项
- 连接健康检查:Aurora可能会回收闲置连接,建议在获取连接后执行简单查询(比如
SELECT 1)验证连接有效性,无效则重新获取 - 适配Aurora Serverless特性:
- v1版本:注意最大连接数不要超过数据库配置上限,避免触发自动扩容或连接拒绝
- v2版本:连接数限制更宽松,但仍需监控连接使用情况
- 避免连接泄漏:必须确保在finally块中归还连接到池,即使代码抛出异常
- 处理冷启动:首次执行时会初始化连接池,这部分耗时无法避免,但后续请求会复用
四、其他优化建议
- 使用Lambda层管理依赖:把
pymysql和DBUtils打包成Lambda层,避免每次部署都重复打包 - 监控连接指标:通过CloudWatch监控Aurora的
DatabaseConnections指标,以及Lambda的执行时长、错误率,及时调整连接池参数 - 考虑Aurora Serverless v2:相比v1,v2的连接数限制更灵活,扩容速度更快,能更好适配Lambda的突发并发
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

