Mysqli持久连接无法工作。

4

我是使用PHP 5.4.4版本,似乎无法使用mysqli的持久连接。具体来说,让我们看一下这个脚本:

<?php

$links = array();

for ($i = 0; $i < 15; $i++) {
    $links[] =  mysqli_connect('p:192.168.1.40', 'USER', 'PWD', 'DB', 3306);
}

sleep(15);

然后,当脚本正在运行时,打开另一个Shell并输入:
netstat -an | grep 192.168.1.40:3306
tcp        0      0 192.168.1.6:52441       192.168.1.40:3306       ESTABLISHED
tcp        0      0 192.168.1.6:52454       192.168.1.40:3306       ESTABLISHED
tcp        0      0 192.168.1.6:52445       192.168.1.40:3306       ESTABLISHED
tcp        0      0 192.168.1.6:52443       192.168.1.40:3306       ESTABLISHED
tcp        0      0 192.168.1.6:52446       192.168.1.40:3306       ESTABLISHED
tcp        0      0 192.168.1.6:52449       192.168.1.40:3306       ESTABLISHED
tcp        0      0 192.168.1.6:52452       192.168.1.40:3306       ESTABLISHED
tcp        0      0 192.168.1.6:52442       192.168.1.40:3306       ESTABLISHED
tcp        0      0 192.168.1.6:52450       192.168.1.40:3306       ESTABLISHED
tcp        0      0 192.168.1.6:52448       192.168.1.40:3306       ESTABLISHED
tcp        0      0 192.168.1.6:52440       192.168.1.40:3306       ESTABLISHED
tcp        0      0 192.168.1.6:52447       192.168.1.40:3306       ESTABLISHED
tcp        0      0 192.168.1.6:52444       192.168.1.40:3306       ESTABLISHED
tcp        0      0 192.168.1.6:52451       192.168.1.40:3306       ESTABLISHED
tcp        0      0 192.168.1.6:52453       192.168.1.40:3306       ESTABLISHED

我认为这是一个错误:PHP应该只打开一个持久连接,而不是15个不同的连接。

这是真的吗?

谢谢大家。


为什么要使用持久连接?很可能你造成的伤害比好处还多。 - Martin
谢谢马丁,但我需要使用它! - MaCi
使用 $link = mysqli_init(); $links[] = mysqli_real_connect($link, 'p:192.168.1.6', 'USER', 'PWD', 'DB', 3306); 看起来是有效的。 - MaCi
2个回答

4
您正在寻找错误的好处;使用持久连接并不能像在您的测试中一样帮助单个php脚本执行 - 它有助于在一系列请求中。
当您请求mysqli建立一个持久连接时,它会查找与您的连接详细信息(用户名/密码等)匹配且未被使用的已建立的连接池。 您的循环请求使用十五个连接,您将获得十五个连接。 每个连接都专用于您的线程。
当您的线程关闭时,您应该在netstat中列出十五个连接,就像您所做的那样。
如果您再次运行脚本,则应该看不到列出的连接有任何更改(即没有新连接)。 这就是优点所在 - 在以后的脚本执行中,您可以节省建立连接的开销。
更好的测试方法是计时在第一次请求时创建100个持久连接的执行时间,然后重新运行相同的请求,因为它不需要建立100个新连接,所以应该更快。

0

如果运行 PHP 的服务器 API 创建多个父进程来运行 PHP,则这是有意义的。

例如,如果您正在使用 FastCGI 并将其配置为具有 15 个进程,并且每个进程中有 50 个子进程,则您可以在任何给定时间拥有多达 15 个持久连接(每个进程 1 个),并且每个各自进程的 50 个子进程都将使用其父进程的 1 个持久链接。

在 Apache 中,我认为 StartServers 指令是相关的,然后对于每个运行的子服务器进程,您有 ThreadsPerChild 线程运行,每个线程都会使用其各自父级的持久链接。

我猜测,如果您正在使用 Apache,则有 15 个子进程正在运行,每个子进程都有自己的线程。这就是为什么您会看到 15 个持久连接的原因。

希望能有所帮助。


谢谢drew010,但是你说的和PHP.net(http://www.php.net/manual/en/features.persistent-connections.php)上说的不一样。然后,使用mysql而不是mysqli,它可以工作。 - MaCi
它在这里说:它们会导致子进程仅在其整个生命周期内连接一次,而不是每次处理需要连接到SQL服务器的页面时都连接。这意味着对于每个打开持久连接的子进程,都将有自己打开的持久连接到服务器。例如,如果您有20个不同的子进程运行一个脚本,该脚本与您的SQL服务器建立了持久连接,则您将拥有20个不同的连接到SQL服务器,每个连接来自一个子进程。 - drew010
但它也指出:这意味着当同一客户端第二次向服务器发出请求时,它可能由与第一次不同的子进程提供服务。在打开持久连接时,每个后续请求 SQL 服务的页面都可以重用相同已建立的连接到 SQL 服务器的连接。 - MaCi
也许下一个合适的问题是,你的服务器正在使用哪个SAPI,并且在进程控制方面该SAPI如何配置?运行 netstat -anp|grep 3306 命令,这样你就可以看到每个连接所属的PID,然后你就可以确定每个父进程是什么以及它们是否是独立的服务器进程,用于处理请求。 - drew010
你说的关于Apache以及它的子进程如何管理数据库连接是完全正确的,但我使用的是CLI而不是HTTP。MySQL在使用第一个脚本(仅1个连接)时可以正常工作,而mysqli则不行(15个不同的连接)。我尝试更新PHP,现在似乎mysqli可以工作了,可能是由于我安装的PHP 5.4版本存在错误。谢谢! - MaCi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接