当前位置:Gxlcms > 数据库问题 > 转 Swoole】用swoole简单实现MySQL连接池

转 Swoole】用swoole简单实现MySQL连接池

时间:2021-07-01 10:21:17 帮助过:27人阅读

$serv = new swoole_server(‘0.0.0.0‘, 9509); $serv->set(array( ‘worker_num‘ => 50, //worker进程数量 ‘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("127.0.0.1", "root", "passwd", "database"); 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

 

 

这里就不再说代码了,注释很清楚了,如果对swoole函数有什么疑问,请自行查看官方文档。

接下来,写了个客户端代码来做测试

<?php
$client = new swoole_client(SWOOLE_SOCK_TCP);//创建swoole tcp客户端
$client->connect(‘*.*.*.*‘, 9509, 10) or die("连接失败");//连接server
while(true){
    echo "请输出要执行的sql: ";
    $sql = trim(fgets(STDIN));
    if($sql==‘exit‘){
        break;
    }   
    $client->send($sql);//发送要执行的sql
    $data = $client->recv();//阻塞接受返回的结果
    var_dump($data);//打印
}
$client->close();//关闭连接

 

 

运行,首先启动server

[root@VM_114_93_centos swoole]# php DBserver_task.php

 

然后运行client

[root@VM_114_93_centos swoole]# php DBclient.php 
请输出要执行的sql: select * from s_lvs_vip;
string(103) "array (
  0 => 
  array (
    ‘id‘ => ‘3‘,
    ‘protocol‘ => ‘tcp‘,
    ‘lb_algo‘ => ‘ip_hash‘,
  ),
)
"
请输出要执行的sql: insert into s_lvs_vip set protocol=‘tcp‘,lb_algo=‘ip_hash‘;
string(5) "true
"
请输出要执行的sql: select * from s_lvs_vip;
string(196) "array (
  0 => 
  array (
    ‘id‘ => ‘3‘,
    ‘protocol‘ => ‘tcp‘,
    ‘lb_algo‘ => ‘ip_hash‘,
  ),
  1 => 
  array (
    ‘id‘ => ‘4‘,
    ‘protocol‘ => ‘tcp‘,
    ‘lb_algo‘ => ‘ip_hash‘,
  ),
)
"
请输出要执行的sql: delete from s_lvs_vip where id=3;
string(5) "true
"
请输出要执行的sql: select * from s_lvs_vip;
string(103) "array (
  0 => 
  array (
    ‘id‘ => ‘4‘,
    ‘protocol‘ => ‘tcp‘,
    ‘lb_algo‘ => ‘ip_hash‘,
  ),
)
"
请输出要执行的sql: exit

 

在看server端的输出结果:

[root@VM_114_93_centos swoole]# php DBserver_task.php 
收到数据select * from s_lvs_vip;
开始做任务 task id:0
任务结束
收到数据insert into s_lvs_vip set protocol=‘tcp‘,lb_algo=‘ip_hash‘;
开始做任务 task id:1
任务结束
收到数据select * from s_lvs_vip;
开始做任务 task id:2
任务结束
收到数据delete from s_lvs_vip where id=3;
开始做任务 task id:3
任务结束
收到数据select * from s_lvs_vip;
开始做任务 task id:4
任务结束

 

性能测试

同样执行一条查询

不用连接池的PHP代码

<?php
$conn = @mysqli_connect("***.***.***.***","root","905407339",‘hulk‘);
if($conn){
    //mysqli_select_db($conn,"hulk");
    $res=mysqli_query($conn,‘select * from s_lvs_vip‘);
    $row=mysqli_fetch_assoc($res);
    var_dump($row);
}else{
    echo "ERROR";
}

 

 

用连接池的PHP代码

<?php
$sql = ‘select * from s_lvs_vip‘;
$client = new swoole_client(SWOOLE_SOCK_TCP);
$client->connect(‘***.***.***.***‘, 9509, 10) or die("连接失败");
$client->send($sql);
$data = $client->recv();
var_dump($data);
$client->close();

 

都用2000并发去测试多次,取平均值

ab -n 2000 -c 100 http://***.***.***.***/swoole/mysqli.php
ab -n 2000 -c 100 http://***.***.***.***/swoole/DBclient.php

 

 

类型未使用连接池使用了连接池
总耗时 34.563 seconds 25.407 seconds
总请求量 2000 2000
并发量 100 100
Failed requests 4 0
每秒钟请求量 57.87 [#/sec] (mean) 78.72 [#/sec] (mean)
客户端平均请求等待时间 1728.160 [ms] (mean) 1270.370 [ms] (mean)
服务端平均请求响应时间 17.282 [ms] 12.704 [ms]

通过这些测试数据,可以看出用了连接池以后,效果还是很明显的,有一个质的改变。

注 : 博主用的是腾讯云 1核 1M 1G内存的云主机,测试数据仅供参考。

补充

小知识补充

断线重连

造成这样的原因一般是sql操作的时间过长,或者是传送的数据太大。

在mysql中有一个wait_timeout参数,默认设置为8个小时,当超过8个小时没有数据交互时,mysql服务器会主动关闭掉超时的连接,对应的mysql 错误码是2006,报错为MySQL server has gone away,当查询的结果集超过 max_allowed_packet 也会出现这样的报错

错误:2013 (CR_SERVER_LOST)
消息:查询过程中丢失了与MySQL服务器的连接。

关于以上两个错误码的详细介绍,参照 http://blog.csdn.net/djvc/article/details/31379155。

 

https://blog.csdn.net/qq_28602957/article/details/78305039

转 Swoole】用swoole简单实现MySQL连接池

标签:网络通信   测试数据   set   nbsp   param   文档   腾讯云   water   echo   

人气教程排行