求助:Laravel在AWS ALB+Apache2环境下数据库连接无法正常关闭
问题场景
部署架构:AWS EC2(Ubuntu 24.04)+ Apache2 + AWS ALB,后端为Laravel 10.48.28(PHP 8.2),数据库采用AWS RDS MySQL 8.0.39。核心问题为睡眠状态MySQL连接持续堆积,最终触发Too many connections错误导致服务中断。已完成基础排查:
- Laravel数据库配置
PDO::ATTR_PERSISTENT设为false - MySQL
wait_timeout/interactive_timeout配置合理 - Apache2
KeepAlive设为Off - ALB闲置超时设置正常
针对性排查与解决方案
1. 强制Laravel请求结束时回收数据库连接
部分场景下PHP请求生命周期的收尾钩子未正常触发,导致连接未释放。可在app/Providers/AppServiceProvider.php中手动注册请求终止事件:
use Illuminate\Support\Facades\DB; public function boot() { // 注册请求结束回调,强制断开所有数据库连接 $this->app->terminating(function () { DB::disconnect(); }); }
修改后执行php artisan optimize:clear生效。
2. 调整Apache MPM模式与进程配置
若当前使用prefork MPM(每个请求对应独立进程),易出现连接泄漏。建议切换为event MPM(线程化模式,资源复用更高效):
# 禁用prefork模块 sudo a2dismod mpm_prefork # 启用event模块 sudo a2enmod mpm_event # 重启Apache服务 sudo systemctl restart apache2
同时修改/etc/apache2/mods-available/mpm_event.conf的进程参数,避免进程长期存活导致连接泄漏:
<IfModule mpm_event_module> StartServers 2 MinSpareThreads 25 MaxSpareThreads 75 ThreadLimit 64 ThreadsPerChild 25 MaxRequestWorkers 150 # 进程处理1000个请求后自动重启,释放资源 MaxConnectionsPerChild 1000 </IfModule>
修改后重启Apache生效。
3. 排查MySQL连接来源与进程状态
通过MySQL命令查看睡眠连接的详细信息,定位是否为特定进程持续持有连接:
SHOW PROCESSLIST;
重点关注Host(EC2实例IP)、Time(睡眠时长)、Id(进程ID),若发现同一进程ID长期处于睡眠状态,说明该进程内存在连接泄漏,需对应排查Apache/PHP进程的生命周期配置。
4. 调整PHP-FPM进程复用策略(若使用PHP-FPM)
若应用采用Apache + PHP-FPM架构,需限制FPM进程的请求处理次数,避免进程长期运行导致连接泄漏:
在PHP-FPM的池配置文件(如/etc/php/8.2/fpm/pool.d/www.conf)中修改:
# 每个进程处理500个请求后自动重启 pm.max_requests = 500
修改后重启PHP-FPM服务:
sudo systemctl restart php8.2-fpm
5. 检查Laravel队列/异步任务的连接释放
若应用使用Laravel队列,长期运行的Worker进程可能未正确释放连接。可通过两种方式处理:
- 在任务类的
handle方法末尾手动断开连接:
public function handle() { // 任务业务逻辑 DB::disconnect(); }
- 启动队列Worker时设置超时参数,限制任务运行时长:
php artisan queue:work --timeout=60
6. 优化ALB健康检查路径
确保ALB的健康检查路径不会触发数据库连接(如使用静态页面/health,仅返回HTTP 200状态码),避免频繁的健康检查请求创建大量短期连接。
临时缓解方案
若需快速恢复服务,可临时调整RDS MySQL参数组中的max_connections值(如从默认151上调至300),但需注意RDS实例的内存容量,避免触发内存不足问题。此方案仅为临时措施,需配合上述排查找到根本原因。
内容的提问来源于stack exchange,提问作者Ravi Kyada

