errno:2 errmsg:mysqli_ping(): MySQL server has gone away errno:8 errmsg:mysqli_ping(): send of 5 bytes failed with errno=32 Broken pipe
錯誤級別代號php
值 | 常量 | 說明 |
2 | E_WARNING | 運行時警告 (非致命錯誤)。僅給出提示信息,可是腳本不會終止運行。 |
8 | E_NOTICE | 運行時通知。表示腳本遇到可能會表現爲錯誤的狀況,可是在能夠正常運行的腳本里面也可能會有相似的通知。 |
mysqli_ping()
方法是專門爲 libmysql 這種舊式的數據庫驅動而設計的,它跟如今新式的 mysqlnd 驅動已再也不兼容,因此纔會報錯。 html
從 PHP 5.3.0 開始,就引入了 mysqlnd 驅動,而且在 5.4.0 版本開始做爲默認的 MySQL 數據庫驅動。
因此,如今最新的 PHP 版本也是使用 mysqlnd 做爲默認驅動。mysql
mysqli_ping()
方法的做用是檢測當前 mysql 鏈接是否存活,若不存活則自動重連。不過官方有下面一段話sql
Note: The php.ini setting mysqli.reconnect is ignored by the mysqlnd driver, so automatic reconnection is never attempted.shell
這說明了對於 mysqlnd 驅動來講,mysqli_ping()
已經不能再實現自動重連了。數據庫
那咱們還可以用該方法來判斷當前的 MySQL 鏈接是否存活嗎?若是能,那在咱們實現單例模式時是有幫助的。
由於我只須要鏈接一次數據庫,就能夠自始至終都使用同一個數據庫鏈接來操做數據庫。函數
<?php class DB { private static $link; public static function getLink() { if(empty(self::$link) || mysqli_ping(self::$link) === false) { self::$link = mysqli_connect("host", "username", "password", "dbname"); } return self::$link; } }
看起來上面的程序並無問題,可是爲何就會出現上面兩個報錯呢?並且是因爲調用 mysqli_ping()
而引發的錯誤。.net
errno:2 errmsg:mysqli_ping(): MySQL server has gone away errno:8 errmsg:mysqli_ping(): send of 5 bytes failed with errno=32 Broken pipe
其實不管怎麼說,這個方法也不該該報錯纔對的,返回 true
或者 false
來告訴咱們鏈接是否存活便可,這裏直接報錯不太好。設計
根據 Bug #52561 和 Bug #53287 這兩個反饋來看,官方也沒有給出答案,只是說 mysqli_ping()
已不適用於 mysqlnd,若是必定要用該函數那隻能配合 libmysql 驅動來用。code
緣由結論
實際上,若是 MySQL 鏈接還存活的狀況下,使用 mysqli_ping()
去檢測是不會報錯的,一切正常。只有當 MySQL 主動斷開了與 PHP 的鏈接後,再用該方法去檢測時纔會出現報錯信息。
這種狀況通常會出如今兩次間隔時間較長的時間內,期間 MySQL 根據配置參數 wait_timeout
的閥值而斷開了長時間沒有再發送查詢請求的鏈接。若此時再調用 mysqli_ping(self::$link)
就會出現 MySQL server has gone away
這樣的報錯信息。
此外,對於第二個錯誤即 send of 5 bytes failed with errno=32 Broken pipe
雖然沒有找到確切的緣由,可是能夠推測也是因爲 MySQL 鏈接斷開而形成的。由於這兩個錯誤出現得頗有規律,並且都是在差很少的時間間隔內出現。
爲了減小這種報錯信息的出現,咱們能夠在 php 程序中實現自動重連,即在 MySQL 斷開鏈接前,就自動實現從新鏈接或者避免再使用 mysqli_ping()
去檢測。MySQL 會在何時斷開鏈接,能夠查看 my.ini
配置中的 wait_timeout
參數。
mysql> show global variables like '%timeout'; +-----------------------------+----------+ | Variable_name | Value | |-----------------------------+----------| | connect_timeout | 10 | | delayed_insert_timeout | 300 | | innodb_flush_log_at_timeout | 1 | | innodb_lock_wait_timeout | 50 | | innodb_rollback_on_timeout | OFF | | interactive_timeout | 28800 | | lock_wait_timeout | 31536000 | | net_read_timeout | 30 | | net_write_timeout | 60 | | slave_net_timeout | 3600 | | thread_pool_idle_timeout | 60 | | wait_timeout | 1800 | +-----------------------------+----------+
注意最後一項 wait_timeout
的值是 1800 秒,表示 MySQL 會把 30 分鐘以上沒有任何查詢請求的鏈接給斷開。
根據上面的閥值,咱們在程序中實現自動重連。
<?php class DB { private static $link; public static function getLink() { if(empty(self::$link) || mysqli_ping(self::$link) === false) { self::$link = mysqli_connect("host", "username", "password", "dbname"); } return self::$link; } public static function keepConnectionAlive(&$start) { $passed = time() - $start; if($passed > 1800) { $start = time(); self::$link = null; } } }
在 PHP 程序中使用(通常會在耗時的 woker 中使用)
$start = time(); while(true) { $params = Queues::get(); DB::keepConnectionAlive($start); $link = DB::getLink(); //...處理業務邏輯 }