閒來無事研究一下 php 的 mysql 持久連線問題。在 mysql 擴充套件的年代,應該用的是mysql_pconnect
,可是那時候我還沒有開始接觸 php, 所以我們直接上 pdo。
首先說一下本次測試用的環境。
738 x 5391468 x 1072
關鍵還要看一下 php 的配置。
738 x 555846 x 636
注意其中的最重要的引數pm.max_children=1
, 這決定了只能有乙個 fpm 的 worker 程序來處理所有請求。這樣把問題簡化更容易發現特徵。
我們知道, php 的 fpm 有乙個 master 程序和若干個 worker 程序, 而 worker 程序並不是像最早的 fastcgi 一樣每次處理完乙個請求之後就銷毀, 下次再來請求需要重新啟動。也就是說乙個 worker 程序是可以處理多個請求的。這給「持久連線」提供了理論基礎。 那麼到底它能不能支援持久連線呢?如果支援持久連線, 它的特徵又是什麼呢?下面直接上**。
738 x 5391468 x 1072
反覆執行curl
(我給 fpm.org 配置了 hosts), 就可以看到不斷變化的 lastinsertid 了。 但這不是重點, 要看兩個現象。
用 root 賬戶登入 mysql, 執行show processlist;
可以看到類似如下的輸出:
738 x 4151920 x 1080
可以看到, 有兩個客戶端和伺服器保持了連線。是誰呢?第乙個是 ubuntu(其實是 debian)維護的 mysql 包自帶的預設管理員使用者, 其實表示的就是當前的這個 mysql cli 連線。另外乙個當然就是剛才呼叫curl
通過 php 的 pdo 建立的了。
738 x 5391468 x 1072
現在再來看 general_log,
738 x 4151920 x 1080
可以看到多次請求伺服器端都是同乙個執行緒 id(14). 參考這裡
那麼怎麼驗證它是由當前這個 fpm 的 worker 維持的呢?很簡單, 重啟一下 fpm 再看它有沒有變化就知道了。
sudo systemctl restart php-fpm.service
738 x 1191264 x 204
可以看到乙個新的 worker 已經在工作了。 現在重新訪問剛才的位址
先再去執行一下show processlist;
738 x 4151920 x 1080
可以看到 14 已經不在了。因為維持 14 這個連線的 fpm worker 已經掛了,當然對應的伺服器的執行緒也已經銷毀了。但 15 出現了。那麼這幾次請求用的是不是 15 呢?
當然是。
738 x 4151920 x 1080
所以結論很明顯了,在 fpm 模式下是可以使用 mysql 持久化連線的。
所以理論上也可以實現 mysql 連線池。有時間可以研究一下。想了想是沒有辦法實現連線池的, 因為乙個 worker 只能維持乙個長連線,無法和別的 worker 共享, 只能通過配置pm.max_children
來讓 fpm 維持的長連線沒有那麼多不要超過 mysql 的最大連線數.
不過這是乙個危險操作, 因為你也看到了, 我在寫這篇文章的過程中在沒有手動重啟 fpm 程序之前這個長連線是一直保持的,而如果這個 fpm 程序是空閒的, 那麼這個連線就是被浪費的。這有可能導致大量無用的連線占用 mysql 的連線數, 而連線數是有上限的,超過之後就無法再建立新的連線, 導致後續的連線失敗。所以必須設定長連線數的上限, 同時保證 worker 空閒一段時間後退出,(使用pm.max_spare_servers
實現)或者再處理若干次請求之後重新啟動(通過pm.max_requests
實現), 以保證 mysql 的正常連線數。
mysql與php的連線 PHP 連線mysql
php 連線mysql mysqlhost localhost mysqluser root mysqlpass mysqldata mydata connect mysql connect mysqlhost,mysqluser,mysqlpass or die 錯誤 mysql error my...
php與MySQL的連線
繁寫 echo this is a test echo asdfasdfadsf mysql server name localhost 資料庫伺服器名稱 mysql username root 連線資料庫使用者名稱 mysql password 連線資料庫密碼 mysql database 資料庫...
PHP與Mysql的連線
繁寫 echo this is a test echo asdfasdfadsf mysql server name localhost 資料庫伺服器名稱 mysql username root 連線資料庫使用者名稱 mysql password 連線資料庫密碼 mysql database 資料庫...