**MySQL连接池**
在传统的网站开发中,比如LNMP模式,由Nginx的master进程接收请求然后分给多个worker进程,每个worker进程 再链接php-fpm的master进程,php-fpm再根据当前情况去调用其worker进程然后处理PHP,如果需要MySQL,在与MySQL建立连接,这个时候,如果有1000个请求打过来,就需要与MySQL建立1000个连接。如果请求达到万级或者百万级,这时数据库的压力就会非常大了。连接池技术就可以派上用场了,可以大大降低数据库连接数,还可以降低IO消耗。
**为什么可以降低IO消耗?**
MySQL短连接每次请求操作数据库都需要建立与MySQL服务器建立TCP连接,这是需要时间开销的。TCP连接需要3次网络通信。这样就增加了一定的延时和额外的IO消耗。请求结束后会关闭MySQL连接,还会发生3/4次网络通信。
而连接池采用的是MySQL的长连接模式,会一直保持与MySQL的连接,重用连接进行MySQL的操作,从而节省了建立连接和断开连接的消耗。
**用swoole实现一个简单的MySQL连接池**
~~~
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2019/5/31
* Time: 10:13
*/
$serv = new swoole_server('0.0.0.0', 9506);
$serv->set(array(
'worker_num' => 50, //worker进程数量
'daemonize' => 0,
'task_worker_num' => 10, //task进程数量 即为维持的MySQL连接的数量
));
function my_onReceive($serv, $fd, $from_id, $data)
{
echo "收到数据".$data.PHP_EOL;
//taskwait就是投递一条任务,这里直接传递SQL语句了
//然后阻塞等待SQL完成,并返回结果
$result = $serv->taskwait($data);
echo "任务结束".PHP_EOL;
if ($result !== false) {
list($status, $db_res) = explode(':', $result, 2);
if ($status == 'OK') {
//数据库操作成功了,执行业务逻辑代码,这里就自动释放掉MySQL连接的占用
//将处理结果发送给客户端
$serv->send($fd, var_export(unserialize($db_res), true) . "\n");
} else {
$serv->send($fd, $db_res);
}
return;
} else {
$serv->send($fd, "Error. Task timeout\n");//如果返回的是false,则说明taskwait等待超时,可以设置相应的等待超时时间
}
}
function my_onTask($serv, $task_id, $from_id, $sql)
{
echo "开始做任务 task id:".$task_id.PHP_EOL;
static $link = null;
HELL:
if ($link == null) {
$link = @mysqli_connect("120.78.77.147", "root", "hanshi2019@", "1901");
if (!$link) {
$link = null;
$serv->finish("ER:" . mysqli_error($link));
return;
}
}
$result = $link->query($sql);
if (!$result) { //如果查询失败了
if(in_array(mysqli_errno($link), [2013, 2006])){//错误码为2013,或者2006,则重连数据库,重新执行sql
$link = null;
goto HELL;
}else{
$serv->finish("ER:" . mysqli_error($link));
return;
}
}
if(preg_match("/^select/i", $sql)){//如果是select操作,就返回关联数组
$data = $result->fetch_assoc();
}else{//否则直接返回结果
$data = $result;
}
$serv->finish("OK:" . serialize($data));//调用finish方法,用于在task进程中通知worker进程,投递的任务已完成
//return "OK:".serialize($data);
}
function my_onFinish($serv, $task_id, $data)
{
echo "任务完成";//taskwait 没有触发这个函数。。
echo "AsyncTask Finish:Connect.PID=" . posix_getpid() . PHP_EOL;
}
$serv->on('receive', 'my_onReceive');
$serv->on('task', 'my_onTask');
$serv->on('Finish', 'my_onFinish');
$serv->start();//启动server
~~~
**接下来,写了个客户端代码来做测试**
~~~
$client = new swoole_client(SWOOLE_SOCK_TCP);//创建swoole tcp客户端
$client->connect('127.0.0.1', 9506, 10) or die("连接失败");//连接server
while(true){
// echo "请输出要执行的sql: ";
// $sql = trim(fgets(STDIN));
$time = time();
$sql = "insert into test_c values('youyu',30,".$time.");";
if($sql=='exit'){
break;
}
$client->send($sql);//发送要执行的sql
$data = $client->recv();//阻塞接受返回的结果
var_dump($data);//打印
sleep(2);
}
$client->close();//关闭连接
~~~