swoole websocket服务进行mysql断线重连不生效的问题

代码结构大致是这样的:

<?php

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

    public function __construct()
    {
        if (!$this->initDb()) exit("终止启动\n"); //连接数据库
        $this->server = new swoole_websocket_server('111.111.111.111', 1234); //实例化server
        //消息
        $this->server->on('message', function (swoole_websocket_server $server, $frame) {
            //这里使用数据库连接$conn
        });
        //work进程开启
        $this->server->on('workerStart', function (swoole_websocket_server $server, $worker_id) {
            if ($worker_id == 0) {
                // 每10秒检测一次数据库连接
                $server->tick(10 * 1000, function ($timer_id) {
                    if (!$this->conn->ping()) {
                        echo "数据库已断开!正在尝试重新连接...\n";
                        $this->initDb(); //连接数据库
                    }
                });
            }
        });
        $this->server->start();
    }

    // 连接数据库
    private function initDb() {
        $conn = new mysqli('127.0.0.1', 'root','root','test', 3306);
        if ($conn->connect_errno) {
            printf("数据库连接失败: %s\n", $conn->connect_error);
            return false;
        } else {
            $conn->set_charset("utf8");
            echo "连接数据库成功!\n";
            $this->conn = $conn;
            return true;
        }
    }
}
new server();

每十秒检测mysql连接状态,如果断开连接则重新走initDb,this->$conn重新赋值。 然后我手动重启数据库,程序检测到数据库断开之后进行重连,并且连接成功。

但是当接收到消息事件使用$conn时,却还是提示mysql server has gone away,明明已经重新连接了啊。

我猜想,是不是因为swoole server在注册事件时就绑定了所使用到的变量,所以conn虽然重新赋值了,但是并没有生效到swoole server里?

阅读 4.9k
2 个回答

问题已经解决,欣喜万分!原因是这样的:

  1. swoole server是多进程模式,所以当接收到事件会分配到空闲的工作进程去执行。
  2. 由于进程之间内存是不共享的,而我的代码只是在工作进程0去检测断线重连的,所以重新赋值的mysql连接$conn只作用于工作进程0,其他进程所使用到的mysql连接依然是断开的。
  3. 我的解决方案是:不特定工作进程0进行数据库检测重连,而是所有的工作进程都会进行这项操作。
  4. 其实,最佳的解决方案还是 @madthumb 所说的,在每次进行query时就进行检测断线重连,这样的话,重连时,重新赋值的$conn就是当前进程内存的变量,会生效于当前进程。一开始我把 @madthumb 的回答的侧重点放在了swoole文档所描述的问题上(官方建议query时检测,而不是定时器ping):
“定时执行mysql_ping不能解决问题,如刚刚执行过mysql_ping检测之后,连接就关闭了。”
相关链接:https://wiki.swoole.com/wiki/...

没有发现问题产生的本质,没有进行尝试,其实那样做是非常可行的。

你可以参看这个链接Class:

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

他的做法是每次执行完mysql_query后即使检测返回值,如果mysql_query返回失败,则再执行一次mysql_connect,这样可以确保下一次的请求正常。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题