順序比較亂,想到什麼測試什麼,測試環境 PHP7.2 和 MariaDB10.3.11php
PHP-FPM是 master/worker 多進程模型
master負責和web-server通信,把接受到請求分發到一個子進程(worker)處理mysql
worker進程出現異常退出不會影響到master,master會從新啓動一個新的子進程web
2. 打開持久化的數據庫鏈接:
$mysqli = new mysqli('p:host', 'user', 'password', 'dbname');
注意: 文檔中說 持久化鏈接不能顯示關閉,$mysqli->close() 無效,實測結果發現:$mysqli->close() 確實沒法關閉數據庫資源鏈接,sql
可是這句話後面的sql查詢是沒法執行的,可是不影響下一個php請求。數據庫
3. 打開非持久化的數據庫鏈接
$mysqli = new mysqli('host', 'user', 'password', 'dbname');瀏覽器
若是使用持久化方式鏈接數據庫,當子進程完成任務後不會立馬關閉與數據庫的鏈接,當下一個請求任務過來後會繼續使用這個鏈接,
(這裏持久化只是PHP不主動關閉鏈接,但不保證MySQL不主動斷開,MySQL能夠經過配置wait_timeout來主動關閉長時間沒有活動的鏈接)
非持久鏈接方式會在任務處理完後當即關閉數據庫鏈接服務器
持久鏈接帶來了一個直觀的好處,性能提高,但也帶來了不少不可預知的錯誤,好比上一個鏈接開啓了事務可是沒有提交,那後面鏈接上的操做
會出現問題併發
持久化鏈接的數據庫句柄是保存在子進程的,若是有30個子進程都鏈接了數據庫,那麼這30個子進程都會保持和數據庫的鏈接,
因此有個地方須要特別注意,MySQL的最大鏈接數必定要設置爲大於PHP子進程最大數量,不然MySQL會出現 too many connections 錯誤函數
查看MySQL當前鏈接數(每隔一秒刷新一次) mysqladmin -uroot -p123456 -i 1 processlist 查看InnoDB的事務和鎖 SHOW ENGINE INNODB STATUS;
4. 若是PHP子進程正常/意外退出,MySQL鏈接會不會自動釋放?
無論子進程是正常退出(處理完請求)仍是意外退出(直接kill掉),
也無論和數據庫是長鏈接仍是短連接,數據庫都會自動斷開性能
5. 若是瀏覽器發送一個複雜的請求,致使服務器返回超時,會發生什麼?
這個要分兩種狀況:
Nginx超時:服務器返回504,這個時候PHP子進程不受影響繼續執行,和數據庫的鏈接也不會斷開,最終任務會成功執行(前提是PHP不超時)
這種狀況很糟糕,用戶看到的是失敗,後臺卻執行成功了,用戶可能會反覆重試屢次,形成數據錯亂。
PHP超時:服務器返回502,這個時候PHP子進程會被Master殺掉並重啓一個子進程,因此任務是沒有執行成功的,數據庫資源也會自動斷開
6. 若是子進程鏈接數據庫並開啓了事務,可是最後沒有提交,會發生什麼?
分兩種狀況:
數據庫爲非持久鏈接: 這種狀況下數據庫鏈接都關閉了,就別操心事務了
數據庫持久鏈接:這個狀況下官方的說法是要銀熊後面的請求,可是實際測試發現,沒有影響,若是實在擔憂的話,可使用函數 register_shutdown_function
對每一個請求結束前處理一下
register_shutdown_function(function() { echo ("shutdown process"); });
7. 作一個實驗:配置PHP-FPM只啓動一個子進程,瀏覽器連續發送3個請求,PHP處理程序中sleep 25秒
觀察現象:
經過top能夠看到確實始終只有一個 PHP子進程
經過 mysqladmin 查看,始終只有一個鏈接
第一個請求在25秒後返回了數據
第二個請求在第50秒返回了數據
第三個請求返回504(Nginx默認60s超時)
結論: 一個PHP子進程只能同時處理一個請求,多餘的未分配的請求任務堆積在Master主進程中等待空閒子進程
8. 既然PHP子進程某一瞬間只能同時處理一個任務, 從這個理論出發,有人就會有疑問了,是否是服務器開啓100個PHP子進程,那麼這臺服務器的最大併發就是100? 這個地方須要弄清楚併發的概念,併發並非只一瞬間能處理多少請求,而是指在正常人能夠接收的等待時間內(好比2秒) 能夠處理多少個請求,因此併發數量是遠遠超過100的