鍍金池/ 問答/PHP  數(shù)據(jù)庫  HTML/ swoole websocket服務(wù)進(jìn)行mysql斷線重連不生效的問題

swoole websocket服務(wù)進(jìn)行mysql斷線重連不生效的問題

代碼結(jié)構(gòu)大致是這樣的:

<?php

class server
{
    private $server;
    private $conn = null;

    public function __construct()
    {
        if (!$this->initDb()) exit("終止啟動(dòng)\n"); //連接數(shù)據(jù)庫
        $this->server = new swoole_websocket_server('111.111.111.111', 1234); //實(shí)例化server
        //消息
        $this->server->on('message', function (swoole_websocket_server $server, $frame) {
            //這里使用數(shù)據(jù)庫連接$conn
        });
        //work進(jìn)程開啟
        $this->server->on('workerStart', function (swoole_websocket_server $server, $worker_id) {
            if ($worker_id == 0) {
                // 每10秒檢測一次數(shù)據(jù)庫連接
                $server->tick(10 * 1000, function ($timer_id) {
                    if (!$this->conn->ping()) {
                        echo "數(shù)據(jù)庫已斷開!正在嘗試重新連接...\n";
                        $this->initDb(); //連接數(shù)據(jù)庫
                    }
                });
            }
        });
        $this->server->start();
    }

    // 連接數(shù)據(jù)庫
    private function initDb() {
        $conn = new mysqli('127.0.0.1', 'root','root','test', 3306);
        if ($conn->connect_errno) {
            printf("數(shù)據(jù)庫連接失敗: %s\n", $conn->connect_error);
            return false;
        } else {
            $conn->set_charset("utf8");
            echo "連接數(shù)據(jù)庫成功!\n";
            $this->conn = $conn;
            return true;
        }
    }
}
new server();

每十秒檢測mysql連接狀態(tài),如果斷開連接則重新走initDb,this->$conn重新賦值。 然后我手動(dòng)重啟數(shù)據(jù)庫,程序檢測到數(shù)據(jù)庫斷開之后進(jìn)行重連,并且連接成功。

但是當(dāng)接收到消息事件使用$conn時(shí),卻還是提示mysql server has gone away,明明已經(jīng)重新連接了啊。

我猜想,是不是因?yàn)閟woole server在注冊(cè)事件時(shí)就綁定了所使用到的變量,所以conn雖然重新賦值了,但是并沒有生效到swoole server里?

回答
編輯回答
空白格

你可以參看這個(gè)鏈接Class:

https://github.com/matyhtf/framework/blob/master/libs/Swoole/Database/MySQL.php

他的做法是每次執(zhí)行完mysql_query后即使檢測返回值,如果mysql_query返回失敗,則再執(zhí)行一次mysql_connect,這樣可以確保下一次的請(qǐng)求正常。

2018年5月23日 13:52
編輯回答
悶油瓶

問題已經(jīng)解決,欣喜萬分!原因是這樣的:

  1. swoole server是多進(jìn)程模式,所以當(dāng)接收到事件會(huì)分配到空閑的工作進(jìn)程去執(zhí)行。
  2. 由于進(jìn)程之間內(nèi)存是不共享的,而我的代碼只是在工作進(jìn)程0去檢測斷線重連的,所以重新賦值的mysql連接$conn只作用于工作進(jìn)程0,其他進(jìn)程所使用到的mysql連接依然是斷開的。
  3. 我的解決方案是:不特定工作進(jìn)程0進(jìn)行數(shù)據(jù)庫檢測重連,而是所有的工作進(jìn)程都會(huì)進(jìn)行這項(xiàng)操作。
  4. 其實(shí),最佳的解決方案還是 @madthumb 所說的,在每次進(jìn)行query時(shí)就進(jìn)行檢測斷線重連,這樣的話,重連時(shí),重新賦值的$conn就是當(dāng)前進(jìn)程內(nèi)存的變量,會(huì)生效于當(dāng)前進(jìn)程。一開始我把 @madthumb 的回答的側(cè)重點(diǎn)放在了swoole文檔所描述的問題上(官方建議query時(shí)檢測,而不是定時(shí)器ping):
“定時(shí)執(zhí)行mysql_ping不能解決問題,如剛剛執(zhí)行過mysql_ping檢測之后,連接就關(guān)閉了。”
相關(guān)鏈接:https://wiki.swoole.com/wiki/...

沒有發(fā)現(xiàn)問題產(chǎn)生的本質(zhì),沒有進(jìn)行嘗試,其實(shí)那樣做是非??尚械?。

2017年6月22日 06:29