1. 程式人生 > >PHP MySQL 持久連線(mysql_pconnect)

PHP MySQL 持久連線(mysql_pconnect)

PHP MySQL 持久連線(mysql_pconnect)

先來一段 PHP 連線 MySQL 的經典程式碼:

1

2

3

4

5

6

7

8

<?php

$con = mysql_connect("localhost", "root", "123456");

if (!$con) {

    die("Could not connect: " . mysql_error());

}

// some code

mysql_close($con);

?>

這沒什麼問題,一直這樣用。後來看文件發現有個函式 mysql_pconnect(開啟一個到 MySQL 伺服器的持久連線)。官方文件是這樣介紹的:

首先,當連線的時候本函式將先嚐試尋找一個在同一個主機上用同樣的使用者名稱和密碼已經開啟的(持久)連線,如果找到,則返回此連線標識而不開啟新連線。

其次,當指令碼執行完畢後到 SQL 伺服器的連線不會被關閉,此連線將保持開啟以備以後使用(mysql_close() 不會關閉由 mysql_pconnect() 建立的連線)。

我們都知道建立 MySQL 連線比較消耗資源,要是能複用連線那不是牛逼了。但是 PHP 不是指令碼語言嗎?執行完了啥都沒了,怎麼維持持久連線呢?

實踐是檢驗真理的唯一標準,還是試一試吧:

1

2

3

4

5

6

7

8

9

<?php

// pconnect.php

$con = mysql_pconnect("localhost", "root", "123456");

// connect.php

// $con = mysql_connect("localhost","root","123456");

if (!$con) {

  die('Could not connect: ' . mysql_error());

}

sleep(10);

通過 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 連線池可參考:http://wiki.swoole.com/wiki/page/350.html

就目前來看,WEB 開發這塊,折騰連線池等東西,還不如把(一部分)資料遷移到 Redis 等記憶體/No-SQL 資料庫收益來的大。

上文關於持久連線的一些結論並不僅僅適用於 MySQL,同樣適用於 Redis 等其它資料庫。

在下對於這一塊理解的也不是很深,若有任何紕漏,還請不吝賜教。

參考資料:

《PHP MySQL 連線資料庫》 http://www.w3school.com.cn/php/php_mysql_connect.asp

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

《資料庫持久連線 》 http://php.net/manual/zh/features.persistent-connections.php

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