swoole mysql连接池之断线重连

Posted PHP饭米粒

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了swoole mysql连接池之断线重连相关的知识,希望对你有一定的参考价值。

上一篇我们实现了,    这篇我们将探讨如何让这个连接池更健壮。


怎么理解健壮?

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


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

你可以尝试以下几个操作, 然后访问 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有哪些属性


--------------伟大的分割线----------------

PHP饭米粒(phpfamily) 由一群靠谱的人建立,愿为PHPer带来一些值得细细品味的精神食粮!

饭米粒只发原创或授权发表的文章,不转载网上的文章

所发的文章,均可找到原作者进行沟通。

也希望各位多多打赏(算作稿费给文章作者),更希望大家多多投搞。

投稿请联系:

shenzhe163@gmail.com



以上是关于swoole mysql连接池之断线重连的主要内容,如果未能解决你的问题,请参考以下文章

swoole4.0 mysql连接池之读写分离

用python编写与mysql数据库连接并实现断线重连的问题

nodejs+mysql 断线重连

java WebSocket客户端断线重连 | 实用代码框架

基础巩固——长连接 短连接心跳机制与断线重连

nodejs中mysql断线重连