php没有数据库连接池的概念,一般情况下程序中使用mysql_connect()连接数据库,在php脚本执行完毕之后进程会释放掉连接资源所占的内存。访问每个php网页都会出现一个解析脚本的进程,那么数据库服务端也会出现一个connect连接。当然前提是只有一个数据库设计的系统。在高并发高流量的情况下,基于数据库驱动的应用系统很容易出现瓶颈,这个瓶颈首先就是max_connections,即数据库的同时最大连接数,在MySQL安装的时候默认只有100个。增大这个连接数能马上起到效果。但是并不是能无限量增加,我在window服务器下和linux服务器下分别做了实验。
实验准备:
我分别使用了php的MySQL客户端工具mysql_connect()和pdo做实验。本实验故意不采用长连接方式。关于长连接的作用会在以后讨论。以下是知识准备:
resource mysql_connect ( [string $server [, string $username [, string $password [, bool $new_link [, int $client_flags]]]]] )
mysql_connect()在4.2.0版本后添加 new_link 参数。如果用同样的参数第二次调用 mysql_connect(),将不会建立新连接,而将返回已经打开的连接标识。如果让new_link=true, 会使 mysql_connect() 总是打开新的连接,甚至当 mysql_connect() 曾在前面被用同样的参数调用过。
pdo是PHP5内置的一个轻量级,统一接口访问数据库的抽象类。
my.cnf设置如下
[mysqld] skip-name-resolve port = 3306 socket = /opt/lampp/var/mysql/mysql.sock skip-locking key_buffer = 16M max_allowed_packet = 1M table_cache = 64 sort_buffer_size = 512K net_buffer_length = 8K read_buffer_size = 256K read_rnd_buffer_size = 512K myisam_sort_buffer_size = 8M max_connections = 10000
注意max_connections = 10000;
实验代码
<?php set_time_limit(0); function getmicrotime() { list($usec, $sec) = explode(" ",microtime()); return ((float)$usec + (float)$sec); } $time = getmicrotime(); error_reporting(E_ALL); //pdo $dbsettings = array( 'host' => 'localhost', 'port'=> '3306', 'type' => 'mysql', 'user' => 'root', 'passwd' => '', 'dbname' => 'cdcol', 'charset'=> 'utf8', 'cache_time' => 3600 ); $i = 0; $db = array(); $d1 = ''; $dsn = $dbsettings['type'].":host=".$dbsettings['host'].";port=".$dbsettings['port'].";dbname=".$dbsettings['dbname']; for($i=0;$i<10500;$i++){ /**mysql_connect()的测试***/ // $link = mysql_connect($dbsettings['host'], $dbsettings['user'], $dbsettings['passwd'],true); // // if (!$link) { // $error = mysql_error(); // @fwrite(@fopen(dirname(__FILE__)."/tmp/dberror.txt",'a'),date("Y-m-d H:i:s")." ".$dsn.'|'.$error."/n"); // }else{ // //mysql_select_db($dbsettings['dbname'], $link) or die ('Can/'t use foo : ' . mysql_error()); // //$result = mysql_query("SELECT * FROM cds"); // $db[] = $link; // } /***pdo的测试***/ try{ $d = new pdo($dsn,$dbsettings['user'],$dbsettings['passwd'],array(PDO::ATTR_PERSISTENT => false)); if($d!=$d1){ $db[] = $d; } $d1=$d; //$db -> getOne(); }catch (PDOException $e){ $error = $e->getMessage(); echo $error."<br>"; // $fp =fopen(dirname(__FILE__)."/tmp/dberror.txt",'a'); // fwrite($fp ,date("Y-m-d H:i:s")." ".$dsn.'|'.$error."/n"); // fclose($fp); } } echo count($db); echo "<hr>"; echo getmicrotime() - time(); ?>
实验结果:
在window下执行发现平均能到达平均1860个连接,然后报错
Can't create a new thread (errno 12); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug。执行时间0.685220003128s
在linux下执行能达到8168个连接,然后报错,Can't create UNIX socket (24); 执行时间 0.406996965408 s
由于不是使用长连接,php脚本执行完成之后资源马上被释放掉。php短连接数据库的执行效率还是相当不错的。但是本实验脚本还没有做实际的查询等操作,不能真实的模拟到用户的并发访问环境。但是从单独的创建连接数来看,单个MySQL服务器最多能支持8000个并发连接。如果是几万用户在线的网站,就需要想办法解决数据库的这个瓶颈了。虽然php提供了长连接这个选择,但是长连接的弊端也很明显,详细见这篇文章《PHP使用数据库永久连接方式操作MySQL的是与非》。
至于window下跟linux下数据为什么差别会那么大呢?在MySQL官方文档中有这个说明:
The maximum number of connections MySQL can support depends on the quality of the thread library on a given platform.
跟MySQL运行平台操作系统的线程数量控制有关系。
解决方案:
在数据库方面的解决方案主要是采用Master-Slaver的Cluster数据库集群方案,这个方案解决负载均衡,使连接数分流到 Slaver。另一个在php方面的解决方案是借助第三方软件SQL Relay来创建一个数据库连接池,从而减少单台MySQL服务器的并发连接数量,大大提高了数据库的访问效率。
开源的数据库连接池 SQL Relay 介绍
概述:
SQL Relay是个功能强大并且非常容易使用的持久数据库连接池系统,能够运行在Unix/Linux系统下,能够支持大部分主流的数据库系统和大部分的编程语言,有效的减轻服务器的负载和移植问题,是很多Web应用数据库连接池的一个选择。
SQL Relay 是适合于Unix/Linux下的一个持久数据库连接池,代理服务器和负载平衡系统。
SQL Relay的特点:
SQL Relay支持的数据库系统:
|
|
|
|
SQL Relay 客户端API支持一些高级的数据库操作,例如绑定变量、多记录获取、客户端结果的缓存和支持事务等。
SQL Relay 的客户端API支持的编程语言有:
|
|
|
SQL Relay 给下面的数据库抽象层提供驱动支持:
|
|
|
|
SQL Relay 的支持: