日期:2014-05-16  浏览次数:20709 次

对付 MySQL 的死连接,Sleep的进程的来源探究
当前的连接数:
mysql> show status like '%Threads_connected%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_connected | 27    |
+-------------------+-------+
1 row in set (0.00 sec)

最大连接数:
show variables like '%max_connections%';
set GLOBAL max_connections=800;
flush privileges
也可以修改/etc/my.cnf中的max_connections:
max_connections = 1000

关于php应该在何时调用mysql_close()以及pconnect方式和传统方式有何种区别收藏
以前我一直认为,当php的页面执行结束时,会自动释放掉一切。相信很多人都跟我想的一样。但事实证明并不是这样。比如session就不会随着页面执行完毕而释放。
php的垃圾回收机制,其实只针对于php本身。对于mysql,php没权利去自动去释放它的东西。如果你在页面执行完毕前不调用mysql_close(),那么mysql那边是不会关闭这个连接的。如果你是用的是pconnect方式,即使你在页面执行完毕前调用mysql_close(),也无法另mysql关闭这个连接。
也许在负载低的情况下,你感受不到有何不妥。但是,一旦负载很高,就回出现很多的死链接,于是得杀掉它们,现象:
在php中使用pconnect方式建立连接,然后到mysql客户端下执行show processlist;如果你的负载到一定程度的话,你可以看到很多sleep的进程,这些进程就是人们常说的死连接,它们会一直保持sleep,直到my.cnf里面设置的wait_timeout这个参数值的时间到了,mysql才会自己杀死它。在杀死它的时候,mysql还会在error-log里面记录一条Aborted connection xxx to db: 'xxx' user: 'xxx' host: 'xxx'的日志,用google翻译一下,会得到一个相当强悍的解释"胎死腹中的连接"!
那么造成sleep的原因,有三个,下面是mysql手册给出的解释:
1.客户端程序在退出之前没有调用mysql_close().[写程序的疏忽,或者数据库的db类库没有自动关闭每次的连接。。。]
2.客户端sleep的时间在wait_timeout或interactive_timeout规定的秒内没有发出任何请求到服务器. [类似常连,类似于不完整的tcp ip协议构造,服务端一直认为客户端仍然存在(有可能客户端已经断掉了)]
3.客户端程序在结束之前向服务器发送了请求还没得到返回结果就结束掉了. [参看:tcp ip协议的三次握手]




网上有一个哥们写了一个,如下:


<?php
define('MAX_SLEEP_TIME', 120);

$hostname = "localhost";
$username = "root";
$password = "password";

$connect = mysql_connect($hostname, $username, $password);
$result = mysql_query("SHOW PROCESSLIST", $connect);
while ($proc = mysql_fetch_assoc($result)) {
    if ($proc["Command"] == "Sleep" && $proc["Time"] > MAX_SLEEP_TIME) {
        @mysql_query("KILL " . $proc["Id"], $connect);
    }
}
mysql_close($connect);
?>


将它当中的 $password 改成你实际的数据库密码,死连接的时间也可以修改。然后加入计划任务就可以了。比如用 crontab -e 命令加入:

*/2 * * * * php /usr/local/sbin/kill-mysql-sleep-proc.php就可以每隔 2 分钟检查并清除一次数据库中的死连接了。


我结合自己的实际改写如下:


<?php

require_once 'services/UserServices*.class.php';
define('MAX_SLEEP_TIME', 120);//注意调试的时候这儿只能修改120,而不能在重新定义,常量一旦定义好,就不能被重新定义了。PHP预先定义了几个常量,并提供了一种机制在运行时自己定义。常量和变量基本上是一样的,不同的是:常量必须用DEFINE函数定义,常量一旦定义好,就不能被重新定义了。
$scoreServ = new TMService ( );
$sql = "SHOW PROCESSLIST";
$proc = $scoreServ*->query($sql);
foreach($proc as $oneproc)
{
    if ($oneproc["Command"] == "Sleep" && $oneproc["Time"] >= MAX_SLEEP_TIME)
    {
       $query = "KILL " . $oneproc["Id"];
       echo $query."\n";
       @$scoreServ*->query($query);
    }
}

?>

crontab 加入:


*/2 * * * * /usr/local/php/bin/php /usr/local/tads/htdocs/*/src/crontable/killmysqlsleepproc.php


听说可以做mysql的设置也可以的如下:


配置MYSQL里的参数。超时时间设置。
max_connections:
允许的同时客户的数量。负载过大时,你将经常看到 too many connections 错误。已达到最大链接数,所以会出现这种情况。 我们服务器数值是200。
wait_timeout           
服务器在关闭连接之前在一个连接上等待行动的秒数,默认数值是28800,即如果没有事情发生,服务器在 8个小时后关闭连接。防止sleep过而导致出现too many connections


如果你的sleep进程数在同一时间内过多,再加上其他状态的连接,总数超过了max_connection的值,那mysql除了root用户外,就无法再继续处理任何请求无法与任何请求建立连接或者直接down了。所以,这个问题在大负载的情况下还是相当严重的。如果发现你的mysql有很多死连接存在,首先要先检查你的程序是否使用的是pconnect的方式,其次,检查在页面执行完毕前是否及时调用了mysql_close(),


还有一个办法,你可以在my.cnf里面加上wait_timeout和interactive_timeout,把他们的值设的小一些,默认情况下wait_timeout的值是8小时的时间,你可以改成1个小时,或半个小时。这