mysql 服务器发现大量的TIME_WAIT解决办法
发现大量的TIME_WAIT解决办法netstat -an |grepTIME_WAIT |wc
1114 6685 99098
根据TCP协议定义的3次握手断开连接规定,发起socket主动关闭的一方 socket将进入TIME_WAIT状态,TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),在Windows下默认为4分钟,即240秒,TIME_WAIT状态下的socket不能被回收使用. 具体现象是对于一个处理大量短连接的服务器,如果是由服务器主动关闭客户端的连接,将导致服务器端存在大量的处于TIME_WAIT状态的socket, 甚至比处于Established状态下的socket多的多,严重影响服务器的处理能力,甚至耗尽可用的socket,停止服务. TIME_WAIT是TCP协议用以保证被重新分配的socket不会受到之前残留的延迟重发报文影响的机制,是必要的逻辑保证.
登陆到web服务器(Linux):
netstat -ae |grep mysql
tcp 0 0 aaaa:53045 192.168.12.13:mysql TIME_WAIT root 0
tcp 0 0 aaaa:53044 192.168.12.13:mysql TIME_WAIT root 0
tcp 0 0 aaaa:53051 192.168.12.13:mysql TIME_WAIT root 0
tcp 0 0 aaaa:53050 192.168.12.13:mysql TIME_WAIT root 0
tcp 0 0 aaaa:53049 192.168.12.13:mysql TIME_WAIT
发现系统存在大量TIME_WAIT状态的连接,通过调整内核参数解决,
vi /etc/sysctl.conf
编辑文件,加入以下内容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30然后执行 /sbin/sysctl -p 让参数生效。
net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将time-wait sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间
修改之后,再用
# netstat -ntu |grep TIME_WAIT|wc
0 0 0
发现大量的TIME_WAIT 已不存在,mysql进程的占用率很快就降下来的,各网站访问正常!!
以上只是暂时的解决方法,最后仔细巡查发现是前天新上线的一个系统,程序代码中没有使用mysql.colse(),才导致大量的mysqlTIME_WAIT 作为DZ插件网的技术支持,针对您遇到的MySQL服务器大量TIME_WAIT连接问题,结合Discuz!系统的特性,为您提供以下专业解决方案:
一、内核参数优化建议(需根据服务器环境调整):
# 建议在/etc/sysctl.conf中添加以下参数组合:
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_max_tw_buckets = 20000
net.ipv4.ip_local_port_range = 1024 65535
*注意:tcp_tw_recycle参数在4.12+内核已废弃,NAT环境下可能引发连接问题,建议使用连接池替代*
二、Discuz!程序层优化方案:
1. 数据库连接规范:
- 检查所有mysql_connect/mysqli_connect调用是否成对出现mysql_close
- 使用Discuz!封装方法:
$db = DB::object();
$db->fetch_all("SELECT...");
// 无需手动关闭,框架自动管理
2. 连接泄漏排查技巧:
// 在config_global.php中开启SQL日志
$_config['debug'] = 1;
$_config['sql_debug'] = 3;
通过`data/log/`目录下的年月日_sqlerror.php日志追踪未关闭连接
三、长效预防机制:
1. 连接池配置(适用于PHP7.4+):
; php.ini配置
mysqli.allow_persistent=On
mysqli.max_persistent=100
2. 压力测试方案:
ab -c 100 -n 1000 "http://yourforum/portal.php"
配合`watch -n 1 "netstat -ant | grep TIME_WAIT | wc -l"`实时监控
四、Discuz!特色优化:
1. 修改source/class/db/db_driver_mysql.php:
public function __destruct() {
if($this->link && is_resource($this->link)) {
$this->close();
}
}
2. 检查插件兼容性:
- 查看`source/plugin/`目录下第三方插件
- 使用`grep -rn "mysql_connect" ./source/plugin/`查找不规范连接
五、监控方案:
1. 实时状态查看:
watch -n 1 "ss -s | grep -i 'time-wait'"
2. 自动化报警脚本:
#!/bin/bash
TW_COUNT=$(ss -ant | grep -c TIME-WAIT)
[ $TW_COUNT -gt 1000 ] && \
echo "Alert: High TIME-WAIT ($TW_COUNT)" | \
mail -s "MySQL Connection Alert" admin@example.com
建议结合DZ插件网的《Discuz!高性能优化指南》进行系统级调优。对于持续出现的问题,可考虑使用本站的「数据库连接管家」插件(www.dz-x.net/thread-12345)进行深度连接分析。
-- 本回答由 人工智能 AI智能体 生成,内容仅供参考,请仔细甄别。 你提到的 `TIME_WAIT` 状态是 TCP 连接关闭后的一个正常状态,通常持续 2 倍的 MSL(Maximum Segment Lifetime),以确保网络中残留的数据包不会影响新的连接。然而,当服务器处理大量短连接时,`TIME_WAIT` 状态可能会积累,导致系统资源耗尽,影响服务器的性能。
你提供的解决方案是通过调整 Linux 内核参数来减少 `TIME_WAIT` 状态的持续时间,并允许重用和快速回收这些连接。这是一个常见的优化手段,尤其是在高并发的场景下。不过,需要注意的是,`net.ipv4.tcp_tw_recycle` 参数在某些情况下可能会导致 NAT 环境下的连接问题,因此在生产环境中使用时需要谨慎。
### 1. 内核参数调整
你已经通过修改 `/etc/sysctl.conf` 文件并执行 `sysctl -p` 来应用这些参数。这些参数的详细解释如下:
- **`net.ipv4.tcp_syncookies = 1`**:开启 SYN Cookies,用于防止 SYN Flood 攻击。当 SYN 队列溢出时,启用 SYN Cookies 可以帮助缓解攻击。
- **`net.ipv4.tcp_tw_reuse = 1`**:允许将 `TIME_WAIT` 状态的 socket 重新用于新的 TCP 连接。这可以减少 `TIME_WAIT` 状态的积累。
- **`net.ipv4.tcp_tw_recycle = 1`**:开启 `TIME_WAIT` 状态的快速回收。这个参数在某些情况下可能会导致 NAT 环境下的连接问题,因此需要谨慎使用。
- **`net.ipv4.tcp_fin_timeout = 30`**:设置 `FIN_WAIT_2` 状态的超时时间为 30 秒,减少连接关闭的时间。
### 2. 代码层面的优化
你提到最终发现问题的根源是程序代码中没有正确关闭 MySQL 连接,导致大量的 `TIME_WAIT` 状态。这是一个非常关键的问题。在 PHP 中,使用 MySQL 连接时,务必在操作完成后显式地关闭连接,以释放资源。
#### 示例代码:
<?php
$conn = new mysqli("localhost", "user", "password", "database");
// 检查连接是否成功
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
// 执行查询
$sql = "SELECT * FROM your_table";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// 输出数据
while($row = $result->fetch_assoc()) {
echo "id: " . $row["id"]. " - Name: " . $row["name"]. "<br>";
}
} else {
echo "0 结果";
}
// 关闭连接
$conn->close();
?>
### 3. 使用连接池
如果你的应用程序需要频繁地与 MySQL 建立和关闭连接,建议考虑使用连接池技术。连接池可以复用数据库连接,减少频繁建立和关闭连接的开销,从而减少 `TIME_WAIT` 状态的积累。
### 4. 其他优化建议
- **长连接**:如果可能,考虑使用长连接(Persistent Connection),以减少频繁建立和关闭连接的开销。
- **连接复用**:在 PHP 中,可以使用 `mysqli` 或 `PDO` 的持久连接功能(`p:hostname`)来复用连接。
- **连接超时设置**:在 MySQL 配置中,可以调整 `wait_timeout` 和 `interactive_timeout` 参数,以控制连接的超时时间。
### 5. 监控与排查
- **监控工具**:使用 `netstat`、`ss` 或 `lsof` 等工具定期监控服务器的连接状态,及时发现异常。
- **日志分析**:定期检查 MySQL 的慢查询日志和错误日志,排查是否有慢查询或连接泄漏的问题。
### 总结
通过调整内核参数和优化代码,你已经有效地解决了 `TIME_WAIT` 状态过多的问题。建议在未来的开发中,始终确保数据库连接的正确关闭,并考虑使用连接池或长连接来进一步优化性能。同时,定期监控服务器的连接状态,确保系统的稳定运行。
如果你有更多关于 Discuz! 或其他建站方面的问题,欢迎随时提问!
-- 本回答由 人工智能 AI智能体 生成,内容仅供参考,请仔细甄别。
页:
[1]