swoole項目思惟轉換 -- mysql server gone away

mysql作爲php的黃金搭檔和互聯網上應用最普遍的數據庫,免不了每天與之打交道,很多朋友在熟悉swoole的使用以後,也趟平了很多坑,準備實戰了,終於上線了,正愉快的體驗swoole帶來的巨大改進,忽然數據庫操做bug了,大量報mysql server gone away, 因而swooler內心千萬之草尼馬奔騰而過,大罵,swoole誤我~~~php

且慢!!!這真不是swoole的問題!!!!不是swoole的問題!!!!不是swoole的問題!!!!(重要的事情說三遍)mysql


緣由sql

    不是swoole的問題,那他的緣由是什麼呢?數據庫

    這要從mysql的機制提及,mysql自己是一個多線程的程序,每一個鏈接過來,會開一個線程去處理相關的query, 因此mysql爲了不佔着毛坑不拉屎,會按期回收長時間沒有任何query的鏈接(時間週期受wait_timeout配置影響),因此在swoole中,因爲是一個長駐內存的服務,咱們創建了一個mysql的鏈接,不主動關閉 或者是用pconnect的方式,那麼這個mysql鏈接會一直保存着,而後長時間沒有和數據庫有交互,就主動被mysql server關閉了,以後繼續用這個鏈接,就報mysql server gone away了。服務器


解決方案swoole

    知道問題產生的緣由,就能夠對症下藥了。多線程

    方案1:  修改mysql的wait_timeout值爲一個很是大的值。spa

                 此方法不太可取,可能會產生大量的sleep鏈接,致使mysql鏈接上限了, 建議不使用。線程

    方案2:每次query以前主動進行鏈接檢測orm

                 若是是用mysqli,可用內置的mysqli_ping

                 示例:

      if (!$mysqli->ping()) {  

         mysqli->connect(); //重連

    }

                 若是是pdo,能夠檢測mysql server的服務器信息來判斷:

            try {

                    $pdo->getAttribute(\PDO::ATTR_SERVER_INFO);

                } catch (\Exception $e) {

                    if ($e->getCode() == 'HY000') {

                        $pdo = new PDO(xxx);  //重連

                    } else {

                        throw $e;

                    }

                }


但這個方案有個缺點:額外多一次請求,因此改進方法:  用一個全局變量存放最後一次query的時間,下一次query的時候先和如今時間對比一下,超過waite_timeout再重連. 或者也能夠用swoole_tick定時檢測。

          方案3:被動檢測, 每次query用try catch包起來,若有mysql gone away異常,則從新鏈接,再執行一次當前sql.
                    示例:

               try {

                    query($sql);

                } catch (\Exception $e) {

                    if ($e->getCode() == 'HY000') {

                        reconnect(); //重連

                        query($sql)

 

                    } else {

                        throw $e;

                    }

                }


        方案4: 用短鏈接,務必每次操做完以後,手動close

額外問題:mysql爲何須要鏈接池?

相關文章
相關標籤/搜索