php cli swoole mysql_[了解实践]Swoole、PHP与MySQL:连接池,swoole扩展实现真正的PHP数据库连接池。...

背景:swoole的出现,包括PHP出现前,在新浪企业邮箱就有基于Sun Solaris 系统上面用c++写Mysql的长连接,那时候的长连接是基于RPC实现,对mysql那一端形成一个远程过程的调用,通过XDR数据结构进行解析mysql传来的数据项(RPC也为sun最新提出并后来在linux上默认支持),也就是说像用户登录验证这一块用Mysql的长连接来实现,提高其效率运行相当稳定,后面这个系统迁移到了FreeBSD后,出现了mysql长连接的服务经常出现假死,也就是说进程还在,但是已经连接不上mysql了,重新启动这个RPC服务又好了,原因未知,当时我对c++不了解(现在也不太了解,只听说要看是否形成coredump啥的),当年我还写过一个判断死了就杀死,重启动,判断的程序也老半天回不来,于是我又改成了一个多进程,如果超时没有回来,就干掉那个进程,重启Rpc服务,再后来,这套C++的cgi被替换成了php,再后来基于FreeBSD的系统迁移到了Linux,也就是现在一直在linux上,linux也就强大了起来,回想起来,当年一个登录服务如此极致,现在都变成了直接查询mysql了,这个长连接技术有还有用吗?我只能说对有上千台上万台的服务器可能有用,能节省一定的机器成本罢。但是,追求技术永无止境,需要有这样的一些东西来繁荣我们这个PHP的市场,长连接这个话题不再是Java做成了连接池,像c++也能做成连接池,像腾讯广平就有c++团队还有写cgi实现长连接Mysql服务,据说前二年吧更多关注了H5,像实时技术,比如Tail技术在web上的实现,有转向nodejs的趋势,而此时的PHP拿不出这样的技术,是很危险的,有了swoole起到填补作用,我更多的是觉得官方应该重视这个技术,而不是形成一个扩展,像H5的来到,像websocket的进入,这些东西对于Node来讲,从前端向后端的统一,而PHp呢?没有谁来解决,那么从用户角度来讲,开发者用户的流失或迁移,对PHP本身也是一个损失,但我还是说PHP是最好的语言没有之一,期望其能伴随潮流,与时俱进。

PHP的数据库连接池一直以来都是一个难题,很多从PHP语言转向Java的项目,大多数原因都是因为Java有更好的连接池实现。PHP的MySQL扩展提供了长连接的API,但在PHP机器数量较多,规模较大的情况下,mysql_pconnect非但不能节约MySQL资源,反而会加剧数据库的负荷。

假设有100台PHP的应用服务器,每个机器需要启动100个apache或fpm工作进程,那每个进程都会产生一个长连接到MySQL。这一共会产生1万个My SQL连接。大家都知道MySQL是每个连接会占用1个线程。那MYSQL就需要创建1万个线程,这样大量的系统资源被浪费在线程间上下文切换上。而你的业务代码中并不是所有地方都在做数据库操作,所以这个就是浪费的。

连接池就不同了,100个worker进程,公用10个数据库连接即可,当操作完数据库后,立即释放资源给其他worker进程。这样就算有100台PHP的服务器,那也只会创建1000个MySQL的连接,完全可以接受的。

以前确实没有好的办法来解决此问题的,现在有了swoole扩展,利用swoole提供的task功能可以很方便做出一个连接池来。

代码如下:

$serv = new swoole_server("127.0.0.1", 9508);

$serv->set(array(

'worker_num' => 100,

'task_worker_num' => 10, //MySQL连接的数量

));

function my_onReceive($serv, $fd, $from_id, $data)

{

//taskwait就是投递一条任务,这里直接传递SQL语句了

//然后阻塞等待SQL完成

$result = $serv->taskwait("show tables");

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");

}

}

function my_onTask($serv, $task_id, $from_id, $sql)

{

static $link = null;

if ($link == null) {

$link = mysqli_connect("127.0.0.1", "root", "root", "test");

if (!$link) {

$link = null;

$serv->finish("ER:" . mysqli_error($link));

return;

}

}

$result = $link->query($sql);

if (!$result) {

$serv->finish("ER:" . mysqli_error($link));

return;

}

$data = $result->fetch_all(MYSQLI_ASSOC);

$serv->finish("OK:" . serialize($data));

}

function my_onFinish($serv, $data)

{

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();

看完上面的,看完了,觉得真的很厉害。毕竟,现在来说可能是还没有真正在PHP使用数据库连接池的大应用。今天终于准备实验实验。

在开始之前,还是说一下测试环境吧:OS CentOS 6.4 x86;php 5.3.17;MySQL 5.5.28;Swoole 1.6.8。

首先,我们当然要把代码写好。下面是服务端代码,很多是参考了上面文章里面的,当然也有自己的内容。

$serv = swoole_server_create('127.0.0.1', 3305, SWOOLE_PROCESS, SWOOLE_SOCK_TCP);//端口3305

swoole_server_set($serv, array(

'worker_num' => 2,      //worker线程的数量

'task_worker_num' => 1, //MySQL连接的数量

));//作为小型测试,参数调得比较小

//这里有一个守护进程化的参数,由于是实验,没有加入

function my_onReceive($serv, $fd, $from_id, $data){

//执行查询

$result = $serv->taskwait($data);

if ($result !== false) {

swoole_server_send($serv, $fd, $result);

return;

} else {

swoole_server_send($serv, $fd, "Error. Task timeout\n");

}

}

function my_onTask($serv, $task_id, $from_id, $sql){

static $link = NULL;

if ($link == NULL) {

$link = mysqli_connect('localhost', 'user', 'pw', 'db');

//localhost=>UNIX Socket , IP地址=>TCP/IP

}

$result = $link->query($sql);

if ($result === false) {

swoole_server_finish($serv, 'b:0;');//语句运行失败,这是serialize后的false,下同理

return;

}

if ($result === true){

swoole_server_finish($serv, 'b:1;');//写入操作成功

return;

}

$data = $result->fetch_all(MYSQLI_ASSOC);

swoole_server_finish($serv, serialize($data));

}

function my_onFinish($serv, $data){

//这次实验就没有写东西了

//但是必须有这个函数定义

//其实可以写日志什么的吧

}

swoole_server_handler($serv, 'onReceive', 'my_onReceive');

swoole_server_handler($serv, 'onTask', 'my_onTask');

swoole_server_handler($serv, 'onFinish', 'my_onFinish');

//上面是设置回调函数

swoole_server_start($serv);

swoole_event_wait();//实验环境是PHP5.3,所以需要这个函数进行事件轮询;5.4+就不需要了

如果把上面的连接池代码和Rango的相比较,会发现我的对于错误的部分处理很少。其实这个时候用CLI运行这个连接池,然后使用Telnet已经就可以直接测试效果了。但是不管怎么说这个东西还是要应用在PHP上面的,我简单地写一下PHP方面的代码。

$link=new swoole_client(SWOOLE_SOCK_TCP,SWOOLE_SOCK_SYNC);//TCP方式、同步

$link->connect('127.0.0.1',3305);//连接

$link->send('SELECT * FROM `table`');//执行查询

$res=unserialize($link->recv());

if(!res){

echo 'Failed!';

}

else{

print_r($res);

}

$link->close();

//上面的是最简单的测试,下面可以简单地改写成函数

function dbcp_query($sql){

$link=new swoole_client(SWOOLE_SOCK_TCP,SWOOLE_SOCK_SYNC);//TCP方式、同步

$link->connect('127.0.0.1',3305);//连接

$link->send($sql);//执行查询

return unserialize($link->recv());

//swoole_client类析构时会自动关闭连接

}

现在可以运行了,本次实验是成功的。但是如果使用dbcp_query()这个函数,每次调用都要发起一次TCP连接,执行的语句多了,肯定出问题。这个时候我们就可以把它封装成一个类了,单纯实现这个会比较的简单,但是打出来要点时间,这里就不写了。

最后:今天做的是数据库连接池的实现。从上面的代码我们可以看见,程序与连接池之间的数据交换是使用php序列进行的。这里会有两次的serialize、unserialize,绝对也是一个开销。Rango的文章里面有说到“MySQL是每个连接会占用1个线程……大量的系统资源被浪费在线程间上下文切换上……不是所有地方都在做数据库操作,所以这个就是浪费的。”再看看他那篇文章的假设:“假设有100台PHP的应用服务器,每个机器需要启动100个apache或fpm工作进程。”这肯定不是一个小项目,确实就适合用连接池了。写的东西是用来练手或者解闷儿的?常规方法已经可以了。不要忘了一点:程序与连接池的交互我们应该还是用Swoole实现的,Swoole可是一个TCP/UDP扩展。而Swoole只能运行在Linux平台上面,但是Linux平台上的MySQL是可以用UNIX Socket通讯的。

P.S.:找个时间给epdb改写一个支持数据库连接池的版本。

来自:http://rango.swoole.com/archives/265

http://bokjan.com/prog/php-db-conn-pool-with-swoole.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/296374.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

会按摩的充气颈枕,只占行李箱一个角,却能让你的脖子爽到爆

▲ 点击查看出差、旅游、探亲,舟车劳顿的路上,想要休息实在太难。临近国庆,有多少人准备外出旅游、回家或者出差的?然而在舟车劳顿的路上,想要休息一下,不要太难。睡到一半撞到车窗痛醒,不小心歪…

转:编写高效的Android代码

毫无疑问,基于Android平台的设备一定是嵌入式设备。现代的手持设备不仅仅是一部电话那么简单,它还是一个小型的手持电脑,但是,即使是最快的最高端的手持设备也远远比不上一个中等性能的桌面机。 这就是为什么在编写Android程序时要…

給定周中的特定天

转:給定周中的特定天 另一個常見的需求是,僅在每月中的特定星期數運行。例如,可能希望在每個月的第一個星期一或星期五運行一個報告。為了完成此任務,可以使用與上面類似的過程。對於給定周中的任何天,它一定屬於以下日期範圍之一…

Envoy实现.NET架构的网关(一)静态配置与文件动态配置

什么是Gateway在微服务体系结构中,如果每个微服务通常都会公开一组精细终结点,这种情况可能会有以下问题如果没有 API 网关模式,客户端应用将与内部微服务相耦合。在客户端应用中,单个页面/屏幕可能需要多次调用多个服务。 如果没…

corosync和pacemaker实现httpd和mysql双集群

一、环境介绍:三台均为双网卡:openstack-control.example.com openstack-control eth0:172.16.171.100eth1:10.1.1.100 openstack-nova.example.com openstack-novaeth0:172.16.171.110eth1:10.1.1.110openstack-neutron.example.com openstack-neutrone…

25岁男生要有多少存款才能让女友满意?

1 男女观念差异这么大的吗?▼2 演绎人生从落魄到适应再到悠哉的三个阶段▼3 牌子大,了不起咯~▼4 这鬼才文案用在这里屈才了▼5 狗子:你就说,我演的哪里不像?▼6 7个月一点没变我觉得已经蛮厉害得了▼7 不小心跟…

查看mysql数据库历史_查看mysql数据库历史

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":4,"count":4}]},"card":[{"des":"阿里云数据库专家保驾护航,为用户…

IT学习--学习不一定要用在现实工作中

很多人在学习知识的时候总是说这个学了没用,这个学了用不上,所以很多人就干脆不学。今天就站在我个人观点上对这个问题进行讨论 以考CCIE为例,有些工作经验的考生会对自己的工作有个的认识,知道自己哪些知识是工作上用得上的&…

心得9--jsp设计模版

1.常用的面向对象设计模式有4种: Factory模式、Singleton模式、Facade模式和MVC架构模式。 SUN公司推出JSP技术后,同时也推荐了两种web应用程序的开发模式,一种是JSPJavaBean模式,一种是ServletJSPJavaBean(MVC)模式。 JSP设计模…

C# 泛型的使用

01—泛型概述泛型是用于处理算法、数据结构的一种编程方法。泛型的目标是采用广泛适用和可交互性的形式来表示算法和数据结构,以使它们能够直接用于软件构造。泛型类、结构、接口、委托和方法可以根据它们存储和操作的数据的类型来进行参数化。泛型能在编译时提供强…

80040e14 mysql_【ASP】提示错误80040e14

是的,提示Cls_vbsPage.asp 行164 有问题,整个代码如下:Class Cls_vbsPagePrivate oConn 连接对象Private iPagesize 每页记录数Private sPageName 地址栏页数参数名Private sDbType数据库类型,AC为access,MSSQL为SQL SERVER2000…

在数学世界,都有这些美妙的数学公式是你不认识的......

全世界只有3.14 % 的人关注了爆炸吧知识什么是数学?华罗庚说:宇宙之大,粒子之微,火箭之速,化工之巧,地球之变,生物之谜,日用之繁,无处不用数学......回首往昔&#xff0c…

Android MediaScanner:(一)MediaScanner总体架构

Android MediaScanner:(一)MediaScanner总体架构 分类: Android android.multimedia2012-05-19 18:29 5050人阅读 评论(5) 收藏 举报androidservice数据库工作interfaceinsert田海立csdn 2012-05-19 本文是笔者的分析归纳&#xf…

协变和逆变

http://msdn.microsoft.com/zh-cn/library/vstudio/dd997386.aspx转载于:https://www.cnblogs.com/mingyongcheng/archive/2012/11/15/2771568.html

报表系统FineReport通过权限控制数据访问方案

2019独角兽企业重金招聘Python工程师标准>>> 问题:实际应用环境中,不同角色的人可能对数据具有不同的访问权限,通过直接在SQL语句中筛选出需要的数据制作模板可以解决该需求,但对于角色较多的情况,就需要制…

SkyWalking配上告警更优秀

前言对于监控系统来说,不可能让人一直盯着监控看板,而更多的是以自动提醒的方式,比如邮件、短信或微信推送等,当达到或超出预设的告警指标时,就自动发送消息提醒,下面就来说说如何配置SkyWalking的告警。正…

python sqllite远程_Python实现Sqlite将字段当做索引进行查询的方法

本文实例讲述了Python实现Sqlite将字段当做索引进行查询的方法。分享给大家供大家参考,具体如下:默认从sqlite中获取到的数据是数字索引的, 在开发阶段经常有修改数据库所以显得不太方便, 其实在python源码里就有解决方案, 直接读sqlite3的源码, 摸索了一…

神抓拍!2020搞笑野生动物摄影大赛,哈哈哈哈哈笑到头掉

全世界只有3.14 % 的人关注了爆炸吧知识图片来自CWPAs 2020小动物们到底能有多好玩让我们来看看今年的搞笑野生动物摄影大赛吧保准叫你从头笑到尾(以下是入围作品)“飚自行车的”猴看起来像个酷猴▲摄影:Yevhen Samuchenko真情实感演绎“我太…

【转载】ESFramewor使用技巧(2)-- 在插件中使用NHibernate

ESFramewor使用技巧(2)-- 在插件中使用NHibernate 我们来讨论一下这种情景,你采用基于ESFramework的4层架构进行应用开发,你分析用户的需求,并将其分类整理为几大块,考虑每一块使用…

如何在ashx页面获取Session值(未将对象引用设置到对象的实例) (转)

如何在ashx页面获取Session值(未将对象引用设置到对象的实例) 分类: .Net学习笔记 Session 2011-11-30 10:25 902人阅读 评论(1) 收藏 举报在一般事务处理页面,可以轻松的得到 Request,Response对象,从而进行相应的操作,如下&am…