Linux PHP-FPM 与 MySQL 高效配合的实用方案
一 架构与连接策略
- 使用持久连接减少 TCP 握手与认证开销:在 PDO 中设置 PDO::ATTR_PERSISTENT => true,在 MySQLi 中使用主机前缀 p:(如:mysqli_connect(‘p:localhost’, …);持久连接由 PHP-FPM worker 复用,能显著降低连接建立成本。注意它并非“真正连接池”,连接可能携带跨请求的事务、临时表、会话变量等状态,需要在业务层或连接初始化时清理。
- 控制总连接数上限:FPM 侧每个 worker 可能长期占用 1 个数据库连接,需保证近似关系:pm.max_children ≤ MySQL max_connections,并预留一部分连接给管理、监控与其他服务。MySQL 默认 max_connections=151,可按并发与内存适度上调(如 500 或更高),同时配合 wait_timeout 回收空闲连接,避免连接打满。
- 引入连接代理/中间件(如 ProxySQL)做连接复用与分发:将应用连接指向 ProxySQL(常见监听 6033),由其在后端 MySQL 间复用与调度连接,降低直连数据库的连接压力与抖动。
- 高并发/长生命周期服务可改用 Swoole 协程 + 连接池:在常驻内存模型中实现真正的连接池(协程从池中获取/归还连接),适合对延迟与吞吐要求更高的场景。
二 PHP-FPM 关键配置
- 启用 OPcache 提升脚本执行效率:设置 opcache.enable=1;生产环境建议 opcache.validate_timestamps=0(配合部署流程更新代码),可按内存与文件量调整 opcache.memory_consumption 与 opcache.max_accelerated_files。
- 合理选择进程模型并限制并发:根据负载在 ondemand / dynamic / static 间选择;示例参数:pm.max_children=50,pm.start_servers=4,pm.min_spare_servers=2,pm.max_spare_servers=6。启用 pm.max_requests 定期重启 worker,回收潜在内存泄漏与僵死连接。
- 精简扩展与常驻内存优化:仅启用必要扩展,减少内存占用与初始化开销;在需要极致性能的场景,考虑 PHP 8.x + JIT(如设置 opcache.jit_buffer_size=256M,opcache.jit=1235)。
三 MySQL 服务端配置要点
- 为 InnoDB 分配充足缓冲:将 innodb_buffer_pool_size 设为服务器内存的50%–70%,加速数据/索引页的缓存命中。
- 调整日志与连接相关参数:按负载设置 innodb_log_file_size(如 256M)、innodb_log_buffer_size(如 16M);根据并发与资源设置 max_connections(如 500 起步),并配置 wait_timeout 回收空闲连接。
- 开启慢查询日志定位问题 SQL:启用 slow_query_log 与 long_query_time,配合 EXPLAIN 分析执行计划并添加合适索引。
四 应用层 SQL 与连接最佳实践
- 使用预处理语句/参数绑定(PDO/MySQLi)防止 SQL 注入并提升计划复用率;避免在循环中执行查询,尽量合并为批量/单次查询。
- 正确处理事务与连接状态:持久连接可能残留事务/临时表/会话变量,应在请求开始或获取连接时执行初始化 SQL(如重置会话变量、回滚未提交事务),并在异常时捕获并重连。
- 连接失败与超时处理:对“MySQL server has gone away”等错误进行自动重连与重试;必要时在连接选项里设置 PDO::MYSQL_ATTR_INIT_COMMAND 来初始化会话(如设置 wait_timeout)。
- 监控与容量规划:持续观察 Threads_connected、慢查询、连接等待等指标;确保 FPM 最大子进程数 × 每进程连接数 不超过数据库可承载上限,并给突发流量留出余量。
五 快速配置示例
- PHP-FPM(/etc/php/*/fpm/pool.d/www.conf 片段)
- 进程管理:pm=dynamic;pm.max_children=50;pm.start_servers=4;pm.min_spare_servers=2;pm.max_spare_servers=6;pm.max_requests=1000
- 执行与内存:request_terminate_timeout=30;max_execution_time=30;memory_limit=128M
- PHP(php.ini 片段)
- 启用扩展:extension=mysqli;extension=pdo_mysql
- OPcache(生产):opcache.enable=1;opcache.validate_timestamps=0;opcache.memory_consumption=128;opcache.max_accelerated_files=4000
- MySQL(my.cnf 片段)
- [mysqld]:innodb_buffer_pool_size=1G(按内存调整);innodb_log_file_size=256M;innodb_log_buffer_size=16M;max_connections=500;slow_query_log=1;long_query_time=1
- 应用连接(PDO 示例)
- new PDO(‘mysql:host=127.0.0.1;dbname=test;charset=utf8mb4’, $user, $pass, [PDO::ATTR_PERSISTENT => true, PDO::MYSQL_ATTR_INIT_COMMAND => ‘SET SESSION wait_timeout=3600’]);
- 可选:连接代理
- 将应用 DSN 指向 ProxySQL 6033,后端 MySQL 连接由 ProxySQL 管理与复用。