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;
实验代码
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."
";
// $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 "
";
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系统下,能够支持大部分主流的数据库系统和大部分的
SQL Relay 是适合于Unix/Linux下的一个持久数据库连接池,代理服务器和负载平衡系统。
SQL Relay的特点:
快速的执行数据库驱动的Web应用
增强的可测性数据库驱动的Web应用
分配数据库的访问连接
关闭数据库的访问连接
从不支持的平台访问数据库
从一个数据库到另一种数据库移植应用
SQL Relay支持的数据库系统:
Oracle
MySQL
mSQL
PostgreSQL
Sybase
MS SQL Server
IBM DB2
Interbase
Sybase
SQLite
ODBC
MS Access
SQL Relay 客户端API支持一些高级的数据库操作,例如绑定变量、多记录获取、客户端结果的缓存和支持事务等。
SQL Relay 的客户端API支持的编程语言有:
C
C++
Perl
Python
PHP
Ruby
Java
TCL
Zope
SQL Relay 给下面的数据库抽象层提供驱动支持:
Perl DBD
Python DB
Ruby DBD
PHP Pear DB
SQL Relay 的支持:
命令行客户端
一个GUI的配置工具
丰富的文档