测试PHP-FPM的工作流中的疑惑点

顺序比较乱,想到什么测试什么,测试环境 PHP7.2 和 MariaDB10.3.11

PHP-FPM是 master/worker 多进程模型
master负责和web-server通讯,把接受到请求分发到一个子进程(worker)处理

worker进程出现异常退出不会影响到master,master会重新启动一个新的子进程

2. 打开持久化的数据库连接:
$mysqli = new mysqli('p:host', 'user', 'password', 'dbname');
注意: 文档中说 持久化连接不能显示关闭,$mysqli->close() 无效,实测结果发现:$mysqli->close() 确实无法关闭数据库资源连接,

但是这句话后面的sql查询是无法执行的,但是不影响下一个php请求。


3. 打开非持久化的数据库连接
$mysqli = new mysqli('host', 'user', 'password', 'dbname');

如果使用持久化方式连接数据库,当子进程完成任务后不会立马关闭与数据库的连接,当下一个请求任务过来后会继续使用这个连接,
(这里持久化只是PHP不主动关闭连接,但不保证MySQL不主动断开,MySQL可以通过配置wait_timeout来主动关闭长时间没有活动的连接)
非持久连接方式会在任务处理完后立即关闭数据库连接

持久连接带来了一个直观的好处,性能提升,但也带来了很多不可预知的错误,比如上一个连接开启了事务但是没有提交,那后面连接上的操作
会出现问题

持久化连接的数据库句柄是保存在子进程的,如果有30个子进程都连接了数据库,那么这30个子进程都会保持和数据库的连接,
所以有个地方需要特别注意,MySQL的最大连接数一定要设置为大于PHP子进程最大数量,否则MySQL会出现 too many connections 错误

    

查看MySQL当前连接数(每隔一秒刷新一次)
mysqladmin -uroot -p123456 -i 1 processlist

查看InnoDB的事务和锁
SHOW ENGINE INNODB STATUS;

4. 如果PHP子进程正常/意外退出,MySQL连接会不会自动释放?
不管子进程是正常退出(处理完请求)还是意外退出(直接kill掉),
也不管和数据库是长连接还是短链接,数据库都会自动断开

5. 如果浏览器发送一个复杂的请求,导致服务器返回超时,会发生什么?
这个要分两种情况:
Nginx超时:服务器返回504,这个时候PHP子进程不受影响继续执行,和数据库的连接也不会断开,最终任务会成功执行(前提是PHP不超时)
这种情况很糟糕,用户看到的是失败,后台却执行成功了,用户可能会反复重试多次,造成数据错乱。
PHP超时:服务器返回502,这个时候PHP子进程会被Master杀掉并重启一个子进程,所以任务是没有执行成功的,数据库资源也会自动断开

6. 如果子进程连接数据库并开启了事务,但是最后没有提交,会发生什么?
分两种情况:
数据库为非持久连接: 这种情况下数据库连接都关闭了,就别操心事务了
数据库持久连接:这个情况下官方的说法是要银熊后面的请求,但是实际测试发现,没有影响,如果实在担心的话,可以使用函数 register_shutdown_function

对每个请求结束前处理一下

register_shutdown_function(function() {
  echo ("shutdown process");
});

7. 做一个实验:配置PHP-FPM只启动一个子进程,浏览器连续发送3个请求,PHP处理程序中sleep 25秒
观察现象:
通过top可以看到确实始终只有一个 PHP子进程
通过 mysqladmin 查看,始终只有一个连接
第一个请求在25秒后返回了数据
第二个请求在第50秒返回了数据
第三个请求返回504(Nginx默认60s超时)
结论: 一个PHP子进程只能同时处理一个请求,多余的未分配的请求任务堆积在Master主进程中等待空闲子进程

8. 既然PHP子进程某一瞬间只能同时处理一个任务,
从这个理论出发,有人就会有疑问了,是不是服务器开启100个PHP子进程,那么这台服务器的最大并发就是100?
这个地方需要弄清楚并发的概念,并发并不是只一瞬间能处理多少请求,而是指在正常人可以接收的等待时间内(比如2秒)
可以处理多少个请求,所以并发数量是远远超过100的

猜你喜欢

转载自www.cnblogs.com/codeAB/p/10547357.html