【转】swoole mysql连接池之断线重连

作者: 白云飞 分类: mysql,swoole,网络知识 发布时间: 2018-12-05 22:50 阅读:

怎么理解健壮?

当程序任何一个环节出现故障或异常,都能有稳定的预期或输出

为什么说之前连接池不够健壮呢?

你可以尝试以下几个操作, 然后访问 http://127.0.0.1:9501/list:

  1. 长时间不操作,

  2. 重启下mysql

  3. 修改下数据库或者表名

得出的结果都是 false,  这里就完全不在我们预期之内,那开始我们的优化之路吧

第一步:false变异常

当返回false时,我们可以通过$mysql的相关属性来获取相关的错误信息

$result = $mysql->query("select * from test");
if(false == $result) {
    var_dump($result);
}

可以得到如下信息:

//  ["sock"]=> int(8)
//  ["connected"]=> bool(false)
//  ["connect_error"]=> string(24) "connection close by peer"
//  ["connect_errno"]=> int(111)
//  ["affected_rows"]=> int(0)
//  ["insert_id"]=> int(0)
//  ["error"]=> string(26) "MySQL server has gone away"
//  ["errno"]=> int(2006)
//  ["errCode"]=> int(5001)

进一步改造:

$result = $mysql->query("select * from test");
if(false == $result) {
    throw new RuntimeException($mysql->error, $mysql->errno);
}

这样我们就可以捕获异常,进行相关的逻辑处理

但这样每次都在业务层去做判断不是很好的实现方式,可以抽出一个中间层,然后简单改造一下mysql_pool,代码如下:

<?php
use Swoole\Coroutine\MySQL;

class mydb
{
    /**
     * @var MySQL
     */
    private $mysql;
    private $config;

    /**
     * @param $config
     * @return mixed
     * @desc 连接mysql
     */
    public function connect($config)
    {
        $mysql = new MySQL();
        $res = $mysql->connect($config);
        if ($res == false) {
            //连接失败,抛弃常
            throw new RuntimeException($mysql->connect_error, $mysql->errno);
        } else {
            //mysql连接存入channel
            $this->mysql = $mysql;
            $this->config = $config;
        }
        return $res;
    }

    /**
     * @param $name
     * @param $arguments
     * @return mixed
     * @desc 利用__call,实现操作mysql,并能做断线重连等相关检测
     */
    public function __call($name, $arguments)
    {
        $result = call_user_func_array([$this->mysql, $name], $arguments);
        if (false === $result) {
            if (!empty($this->mysql->errno)) {  //有错误码,则抛出弃常
                throw new RuntimeException($this->mysql->error, $this->mysql->errno);
            }
        }

        return $result;
    }

}

保存为mydb.php, 这里我们利用到__call方法,然后可以在操作mysql进行前后置的判断,统一做一些处理
在mysql_pool.php文件里引入:

require_once "mydb.php";

然后把

$mysql = new MySQL();

改成

$mysql = new mydb();

 

第二步:断线重连

上面我们看到了一个经典的错误:MySQL server has gone away,他是如何产生的呢?

  1. 长时间未操作,mysql会主动关闭空闲的连接,防止占着茅坑不拉屎的行为, 时间由 wait_timeout 配置决定,可通过 show variables like “%timeout%” 查看配置的时间是多少?
  2. mysql重启后,所以的旧连接自然就失效了

所以当出现了这些情况,我们还拿着旧的连接去操作,当然就报错了,但碰到这个错误,我们直接抛异常也不太合理,因为我们可以通过断线重连的机制,重新建立一个新的连接,实现也非常简单,看代码:

/**
 * @param $name
 * @param $arguments
 * @return mixed
 * @desc 利用__call,实现操作mysql,并能做断线重连等相关检测
 */
public function __call($name, $arguments)
{
    $result = call_user_func_array([$this->mysql, $name], $arguments);
    if (false === $result) {
        if (!$this->mysql->connected) { //断线重连
           
            $this->connect($this->config);
            return call_user_func_array([$this->mysql, $name], $arguments);
        }

        if (!empty($this->mysql->errno)) {  //有错误码,则抛出弃常
            throw new RuntimeException($this->mysql->error, $this->mysql->errno);
        }
    }

    return $result;
}

 

如果我们发现是连接失效,我们再尝试新建连接即可,其他的错误,按异常处理

至此,我们一个健壮的mysql连接池就有了,是不是很简单呢。

抛个问题?

为什么mysql要主动关闭长久不活跃的连接?像redis就没有这样的机制

预告:
下一篇我们将继续扩展连接池,使之可以支持主从模式

查看原文,可以详细了解swoole的mysql有哪些属性

 

原文链接:https://mp.weixin.qq.com/s/txKoxedoJjnLnPDq7VBMhg

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!