【问题标题】:Mysqli persistent connect doesn't workmysqli持久连接不起作用
【发布时间】:2012-07-24 08:52:23
【问题描述】:

我正在使用 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 个不同的连接。

这是真的吗?

谢谢大家。

【问题讨论】:

  • 为什么要使用持久连接?您可能造成的弊大于利
  • 谢谢马丁,但我需要使用它!
  • 使用 $link = mysqli_init(); $links[] = mysqli_real_connect($link, 'p:192.168.1.6', 'USER', 'PWD', 'DB', 3306);似乎工作

标签: php mysqli persistent-connection


【解决方案1】:

你在错误的地方寻找好处;使用持久连接不会像在您的测试中那样帮助执行单个 php 脚本 - 它有助于处理一系列请求。

当您要求 mysqli 建立持久连接时,它会查找与您的连接详细信息(用户名/密码/等)匹配的已建立连接池没有被使用。 您的循环要求使用十五个连接,您将获得十五个连接。每个连接都专用于您的线程。

当你的线程关闭时,你应该在 netstat 中列出 15 个连接,就像你做的那样。

如果您再次运行该脚本,您应该会看到列出的连接没有任何变化(即没有建立新的连接)。这就是优势所在 - 在以后的脚本执行中,您可以节省建立连接的开销。

更好的测试是在第一个请求上创建一百个持久连接的执行时间,然后重新运行应该更快的相同请求,因为它不需要创建一百个新连接。

【讨论】:

    【解决方案2】:

    mysqli 持久连接将在调用 mysqli_close 后将链接保留在池中。或运行 RSHUTDOWN。所以你可以使用这段代码来完成它。

    for ($i = 0; $i < 15; $i++) {
        $links[$i] =  mysqli_connect('p:192.168.1.40', 'USER', 'PWD', 'DB', 3306);
        var_dump(mysqli_thread_id($links[$i]));    //make sure they are the same.
        mysqli_close($links[$i])
    }
    sleep(15);
    

    结果会是这样的:

    root@cnxct:/home/cfc4n# netstat -antp |grep 3306|grep -v "php-fpm"
    tcp        0      0 192.168.61.150:55148    192.168.71.88:3306      ESTABLISHED 5100/php5   
    root@cnxct:/home/cfc4n# /usr/bin/php5 4.php 
    int(224218)
    int(224218)
    int(224218)
    int(224218)
    int(224218)
    int(224218)
    int(224218)
    int(224218)
    int(224218)
    int(224218)
    int(224218)
    int(224218)
    int(224218)
    int(224218)
    int(224218)
    

    您可以通过some differences between mysql and mysqli of persistent connection in chinese阅读更多信息

    【讨论】:

      【解决方案3】:

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

      例如,如果您使用 FastCGI 并将其配置为有 15 个进程,并且每个进程中有 50 个子进程,那么您在任何给定时间最多可以有 15 个持久连接(每个进程 1 个),并且 50 个子进程中的每一个每个进程将使用来自其父进程的 1 个持久链接。

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

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

      希望对您有所帮助。

      【讨论】:

      • 感谢 draw010,但您所说的与 PHP.net 所说的不同 (php.net/manual/en/features.persistent-connections.php)。然后,用 mysql 代替 mysqli 就可以了。
      • 这里说:They cause the child process to simply connect only once for its entire lifespan, instead of every time it processes a page that requires connecting to the SQL server. This means that for every child that opened a persistent connection will have its own open persistent connection to the server. For example, if you had 20 different child processes that ran a script that made a persistent connection to your SQL server, you'd have 20 different connections to the SQL server, one from each child.
      • 但它也说:这意味着当同一个客户端向服务器发出第二次请求时,它可能由与第一次不同的子进程提供服务。当打开一个持久连接时,每个后续请求 SQL 服务的页面都可以重用与 SQL 服务器建立的相同连接。
      • 也许下一个合适的问题是,您的服务器使用什么 SAPI 以及如何配置 SAPI 以实现流程控制?运行netstat -anp|grep 3306,这样您就可以看到每个连接所属的PID,然后您可以确定每个父进程是什么,以及它们是否是为处理请求而运行的单独服务器进程。
      • 您所说的关于 apache 以及如何在其子项中管理 db 连接是完全正确的,但我使用的是 CLI 而不是 HTTP。 Mysql 使用第一个脚本(仅 1 个连接)和 mysqli 不(15 个不同的连接)可以很好地处理持久连接。我尝试更新 php,现在似乎 mysqli 可以工作,可能是我的 php 5.4 安装版本的错误。谢谢!
      猜你喜欢
      • 2011-03-29
      • 1970-01-01
      • 2015-07-28
      • 2011-04-21
      • 1970-01-01
      • 2018-09-15
      • 1970-01-01
      • 2012-06-06
      • 1970-01-01
      相关资源
      最近更新 更多