PHP MySQL 持久连接(mysql_pconnect)

先来一段 PHP 连接 MySQL 的经典代码:

这没什么问题,一直这样用。后来看文档发现有个函数 mysql_pconnect(打开一个到 MySQL 服务器的持久连接)。官方文档是这样介绍的:

首先,当连接的时候本函数将先尝试寻找一个在同一个主机上用同样的用户名和密码已经打开的(持久)连接,如果找到,则返回此连接标识而不打开新连接。

其次,当脚本执行完毕后到 SQL 服务器的连接不会被关闭,此连接将保持打开以备以后使用(mysql_close() 不会关闭由 mysql_pconnect() 建立的连接)。

我们都知道建立 MySQL 连接比较消耗资源,要是能复用连接那不是牛逼了。但是 PHP 不是脚本语言吗?运行完了啥都没了,怎么维持持久连接呢?

实践是检验真理的唯一标准,还是试一试吧:

通过 URL 访问 pconnect.php,页面加载完成后,等待 10s ,新开浏览器再次访问。在 MySQL 命令行运行「show full processlist;」查看建立的连接:

2015-10-15_001413

感觉并没有复用呀,再次访问还是重新建立了连接(从 Time 字段的值可以看出),那么试试访问 connect.php :

2015-10-14_230252

很明显脚本执行完成连接就断了,这也是 mysql_connect 的特征,符合常理。但是怎么没有出现 mysql_pconnect 的特征呢?这种时候没办法,只能仔细再看文档,发现这么一句话:

注意,此种连接仅能用于模块版本的 PHP。

原来如此,我用的是 Nginx+PHP-FPM 模式,而非 Apache+php_module 模式。 Nginx+PHP-FPM 模式运行过程大概为:Nginx 根据配置(location ~ \.php$)发现这请求我处理不了,然后把请求转给 PHP-FPM(PHP FastCGI管理器) 处理(fastcgi_pass unix:/var/run/php5-fpm.sock;)。PHP-FPM 的 master 进程带着一帮小弟正等着处理上游来的请求呢,每来一个请求就会派一个小弟去处理。处理完了将结果返回给 Nginx,最后自己也死了,所以这个小弟生前建立的连接也就没了(准确来说是 MySQL 并不这鬼崽子挂了,还一直保持着这个连接,但别的小弟并不知道这事)。

2015-10-14_232942

在本地 WampServer 环境,同样方式访问 pconnect.php,结果如下:

2015-10-14_235232

明显可以看出连接得到了复用。在空闲的情况下,新的请求不会再新建连接。那为什么 Apache+php_module 模式能支持持久连接呢?其实这不是 PHP 能持久连接而是 Apache 维持了这个连接,相当于 Apache 的连接线程池充当了 MySQL 的连接池。

那么同时大量访问呢?会是什么情况。

2015-10-15_002241

可以发现连接得到了复用,效率得到了提升。那这能说明 pconnect 是万金油吗?并不见得,官方文档中就有一段提醒:

注意,如果持久连接的子进程数目超过了设定的数据库连接数限制,系统将会产生一些问题。如果数据库的同时连接数限制为 16,而在繁忙会话的情况下,有 17 个线程试图连接,那么有一个线程将无法连接。如果这个时候,在脚本中出现了使得连接无法关闭的错误(例如无限循环),则该数据库的 16 个连接将迅速地受到影响。

由上面的试验也能看到,不管是哪种 PHP 运行模式,都会使 MySQL 产生很多闲置的连接进程,这会占用很多的内存,若配置不当(mysql.max_connections <<< Apache.MaxClients),在小内存的机器上 MySQL 很容易就会崩掉。更有甚者,当你的产品非常多时,每个产品配置了不同的 MySQL 账号密码,持久连接复用的整体效率会直线下降,大量的连接占着茅坑不拉屎,非常容易就会产生 “Too many connections MySQL error” 错误,进一步则 MySQL 崩掉。

综上所诉,建议还是使用 mysql_connect(MySQL 扩展已经不推荐使用了,PHP 7 甚至在默认扩展中移除了此扩展,推荐使用 MySQLi 和 PDO)。当然也不用恐惧 pconnect,了解两者的区别与联系,做好配置和压测,在线上环境大内存机器上还是很有用的。不过现在在 HTTP 服务器这一块,Nginx 可以说已经完全取代了 Apache。感受一下 PHP CodeIgniter 框架 2.X 和 3.x 数据库默认配置的改变,就能更加容易体会到这一点:

2015-10-15_011633

关于 PHP MySQL 连接池可参考:https://wiki.swoole.com/#/coroutine/conn_pool

就目前来看,WEB 开发这块,折腾连接池等东西,还不如把(一部分)数据迁移到 Redis 等内存/No-SQL 数据库收益来的大。

上文关于持久连接的一些结论并不仅仅适用于 MySQL,同样适用于 Redis 等其它数据库。

在下对于这一块理解的也不是很深,若有任何纰漏,还请不吝赐教。

参考资料:

《PHP MySQL 连接数据库》 https://www.w3school.com.cn/php/php_mysql_connect.asp

《PHP: mysql_pconnect - Manual》 https://www.php.net/manual/zh/function.mysql-pconnect.php

《数据库持久连接 》 https://www.php.net/manual/zh/features.persistent-connections.php

《概念了解:CGI,FastCGI,PHP-CGI与PHP-FPM》 http://www.nowamagic.net/librarys/veda/detail/1319

 

CC BY-NC-SA 4.0

扫码分享

      复制标题+网址成功,请去要分享的地方粘贴

本 Blog 不支持评论,如有疑问或建议请联系我,以完善内容,期望帮助到更多的同学