怎么理解健壮?
当程序任何一个环节出现故障或异常,都能有稳定的预期或输出
为什么说之前连接池不够健壮呢?
你可以尝试以下几个操作, 然后访问 http://127.0.0.1:9501/list:
长时间不操作,
重启下mysql
修改下数据库或者表名
得出的结果都是 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,代码如下:
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,他是如何产生的呢?
长时间未操作,mysql会主动关闭空闲的连接,防止占着茅坑不拉屎的行为, 时间由 wait_timeout 配置决定,可通过 show variables like “%timeout%”查看配置的时间是多少?
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