Java 服务跑在 CentOS 7.9,上线两天后 ss -ant 里 CLOSE_WAIT 状态稳定在四千多,进程句柄数逼近 ulimit,应用日志里开始出现 connection reset,重启后又慢慢涨起来。
一开始怀疑是「数据库连接被服务端断开后,客户端没有处理读事件」,查了一圈,方向不对。
真正麻烦的地方在于,几个原因的现象几乎一样。代码里拿到连接后没在 finally 里关闭,异常路径直接漏掉。也可能是HTTP 客户端的连接池没有上限,空闲连接一直被对端关掉。
少数情况下是线程池里的任务卡住,持着连接不释放。
先统计各状态的连接数
ss -ant | awk '{print $1}' | sort | uniq -c | sort -rn
接着找到对方地址和占用进程
ss -antp state close-wait | head -20
然后看进程的句柄数和上限
ls /proc/1234/fd | wc -l && grep 'open files' /proc/1234/limits
等前面都确认过,再在代码里补上关闭逻辑后滚动重启
jstack 1234 | grep -A5 SocketInputStream
改完先别撤,确认这几项。CLOSE_WAIT 数量在十分钟内降到两位数,句柄数稳定,接口不再出现 connection reset。
补一句。CLOSE_WAIT 是本地没关,TIME_WAIT 是本地主动关,处理方向完全相反;先看状态再改代码,别一上来就调内核参数。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。
