Laravel(Nginx/EC2)连接AWS RDS MySQL遇too many connections错误求助
解决Laravel + EC2 + RDS的连接数与内存不足问题
先别急着升级实例,咱们一步步拆解你遇到的两个核心错误——too many connections和cannot allocate memory,它们可能是关联的,也可能是独立的问题:
一、先搞定「数据库连接数满」的问题
你的RDS最大连接数是312,但启用PDO持久化后反而出问题,大概率是连接管理没做好,而不是单纯的连接数不够:
先确认实际连接数到底用了多少
别只看配置的最大连接数,直接登录RDS执行:SHOW STATUS LIKE 'Threads_connected';或者去AWS控制台看RDS的CloudWatch指标「Database Connections」,如果当前连接数经常接近312,再往下排查:
检查PHP-FPM的进程数配置
PDO持久化连接是和PHP-FPM进程绑定的——每个PHP-FPM进程会持有一个持久化连接。如果你的PHP-FPMpm.max_children设置得比312大(比如400),那必然会把RDS的连接占满。
打开你的PHP-FPM配置文件(通常是www.conf),调整这些参数:pm.max_children:建议设为RDS最大连接数的70%-80%(比如220-250),留一些连接给RDS的管理进程。- 同时配套调整
pm.start_servers、pm.min_spare_servers、pm.max_spare_servers,避免进程数突增。
排查Laravel代码里的连接泄漏
即使开了持久化,也要确保代码里没有重复创建连接的情况:- 有没有在循环里多次实例化
DB类? - 队列任务有没有在执行完毕后正确释放连接?(可以在任务类的
handle方法末尾加DB::disconnect();试试) - 有没有用第三方包导致连接没有被复用?
- 有没有在循环里多次实例化
二、解决EC2的「内存分配失败」问题
t2.large有8GB内存,正常跑Laravel+Nginx+PHP-FPM完全够用,内存不足大概率是进程数过多或内存泄漏:
先看内存被谁吃了
登录EC2执行htop或者top命令,看哪个进程占内存最多:- 如果是PHP-FPM进程,那就是刚才说的
pm.max_children设得太高,每个PHP-FPM进程大概占20-50MB内存,200个进程就占4-10GB,直接超了t2.large的内存。 - 如果是其他服务(比如Redis、监控工具),考虑关闭不必要的服务,或者给它们分配固定的内存上限。
- 如果是PHP-FPM进程,那就是刚才说的
排查内存泄漏
如果调整PHP-FPM进程数后还是内存不足,可能是代码有内存泄漏:- 检查有没有一次性加载大量数据的情况(比如用
User::all()加载几万条用户数据),换成延迟加载User::lazy()或者分页查询。 - 用PHP的
memory_get_usage()函数在关键代码节点打印内存使用,定位泄漏点。
- 检查有没有一次性加载大量数据的情况(比如用
三、架构层面的长期优化(不用急着升级实例)
如果排查后发现单纯调参数解决不了,再考虑架构优化:
- 加个数据库连接池:比如用ProxySQL作为中间层,统一管理RDS的连接,避免PHP-FPM直接创建大量连接。连接池可以复用空闲连接,大幅降低RDS的连接压力。
- 分流读请求:如果读请求多,给RDS加个只读副本,把Laravel的读操作定向到副本,主库只处理写操作。
- 队列异步处理:把耗时的数据库操作(比如批量导入、发送通知)放到Laravel队列里,避免请求期间长时间占用连接和内存。
最后总结:先排查再决定是否升级
- 先调PHP-FPM进程数,确保不超过RDS最大连接数的80%;
- 查EC2内存使用,干掉内存大户;
- 检查代码里的连接和内存泄漏;
如果做完这些,连接数还是经常满、内存使用率长期超90%,再考虑升级到更大的实例(比如m5.large,比t2.large的性能更稳定)。
内容的提问来源于stack exchange,提问作者Justinus Hermawan
相关产品推荐
相关产品推荐

