web页面显示 Mysql connect fail, too many connections。

web server用的是lighttpd,查看其状态:http://hostname/pma-server-status并没有太多的连接。

这时,尝试使用普通账号登陆失败:mysql -u mysql -p,依然报too many connections。

在mysql的官方手册上http://dev.mysql.com/doc/refman/5.5/en/too-many-connections.html可以看到,当连接数过多的时候,仅超级用户才能登陆,所以改用root用户连接mysql。

连接上之后,使用show processlist;命令查看当前的连接情况,发现101个sleep状态的查询。这里面存在的问题是:

1、作为一个生产数据库,将max_connection设为100(可以通过show variables like ‘max%’看到)有点太少

2、大量sleep状态的query是否正常?

作为临时解决方案,可以在mysql里kill掉一些sleep的query(mysql>kill  query_id)。也可以暂时更改其max_con数目和允许的连接时间(过小也不行,一次访问未结束就被kill掉了):

mysql> set global max_connections = 500;

mysql> set global wait_timeout = 1000;

为了彻底解决,需要修改mysql的配置文件,将max_connection调大一些,比如500,然后重启mysql。

当然,更重要的是查看代码中是否存在bug。

经查看,造成数据库连接过多的代码,使用了cake框架,并在配置文件中指定persistence为true,从而cake在连接的时候使用了mysql_pconnect。更改配置文件,改persistence为false,使用mysql_connect。第二天早上看到连接数降下来了。

两种connect的区别在php的官方手册如下描述:

mysql_pconnect() acts very much like mysql_connect() with two major differences.

First, when connecting, the function would first try to find a (persistent) link that’s already open with the same host, username and password. If one is found, an identifier for it will be returned instead of opening a new connection.

Second, the connection to the SQL server will not be closed when the execution of the script ends. Instead, the link will remain open for future use (mysql_close() will not close links established by mysql_pconnect()).

也就是说,pconnect形成了一个连接池,每次调用该函数,都会先看连接池中是否有空闲的连接可用。而一次web请求执行完成甚至显式调用mysql_close都不会关闭该连接,而是维持连接状态等待下次使用。wait_timeout会造成该连接关闭。

但是pconnect并不像它看起来这样有用,当连接过多,就会造成阻塞。php官方手册有如下warning:

Using persistent connections can require a bit of tuning of your Apache and MySQL configurations to ensure that you do not exceed the number of connections allowed by MySQL

而从我们服务器的lighttpd配置看到,其允许的最大连接数为500,当前启动的php-cgi个数为111个,这就超过了mysql的最大连接个数,显然是不合理的。

http://cn.php.net/manual/en/features.persistent-connections.php 这里详细说明了persistent database connection的含义。对照它而言,我们使用的是lighttpd的fastcgi模块加载php-cgi脚本,它类似于apache的php module运行方式,会按需启动多个php-cgi进程,这些进程在执行完一个web请求后,并不会立即消失,而是继续pending,等待下次请求。这样就是的persistent connection是有作用的了。

One Comment

  1. flykobe的技术与生活杂谈 » Blog Archive » php的mysql_connect与mysql_pconnect says:

    [...] 那么CLI模式呢?将上面这段代码cp至一个web页面中,通过浏览器访问结束后,show processlist仍然可以看到有连接存在!这就使得多个web请求可以复用同一mysql链接,从而节省了建立连接的过程。但是这样也可能造成问题,就是当允许的web进程(线程)数目超过mysql的max_connections时,会造成web进程连接mysql服务器的阻塞,因为每个web进程都不释放自己的mysql连接,从而可能造成too many connections的mysql错误。可以参考我之前的blog:http://flykobe.com/index.php/2011/01/20/mysql-too-many-connections%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%… [...]

Leave a Reply