CLOSE_WAITが増え続ける原因とアプリ側の修正ポイント【Linux実務解説】

  • URLをコピーしました!

Linuxサーバーで CLOSE_WAIT が増え続けて減らない 状態は、 ネットワーク障害に見えて、実際にはほぼ100%アプリケーションの問題です。

本記事では、CLOSE_WAITが発生する正確な仕組みと、 OSでは解決できない理由、そしてアプリ側で必ず修正すべきポイントを 実務目線で解説します。

目次

CLOSE_WAITとは何か

TCP通信では、相手側が先に接続を終了すると、 こちら側は FIN を受信した状態 になります。

その状態が CLOSE_WAIT です。

つまり CLOSE_WAIT とは、

  • 相手は「もう切った」
  • 自分は「まだ close() していない」

というアプリ待ち状態を意味します。

CLOSE_WAITが増え続ける時に起きる症状

  • 再起動しないと直らない
  • コネクション数が増え続ける
  • FD(ファイルディスクリプタ)枯渇
  • 新規通信が張れなくなる
  • アプリは生きているが通信不能

まず確認すべき現状把握

① CLOSE_WAIT数の確認

ss -tan state close-wait | wc -l

② どのプロセスか特定

ss -tanp state close-wait

③ プロセス別集計

ss -tanp state close-wait | awk '{print $NF}' | sort | uniq -c | sort -nr

ここで特定の Java / Python / Webサーバープロセスが 集中していれば、原因は確定です。

OSやsysctlでは直らない理由

よくある誤解として、

  • tcp_fin_timeout を短くする
  • tcp_tw_reuse を設定する

がありますが、これらは TIME_WAIT に対する設定です。

CLOSE_WAITはカーネルでは解消できません。

理由は単純で、

「アプリが close() を呼ばない限り、カーネルは何もできない」 からです。

CLOSE_WAITが発生する典型原因

① ソケット close() 忘れ

  • 例外発生時にcloseしない
  • returnパスが複雑
  • finally がない

② 接続プールの破棄漏れ

  • DBコネクションを返していない
  • HTTPクライアントのclose忘れ

③ タイムアウト未設定

  • read timeout 無し
  • socket timeout 無し

言語別・実務で多いミス例

Java

  • HttpClient / OkHttp の close忘れ
  • try-with-resources 未使用
  • DBコネクション未返却

Python

  • requests の session.close() 忘れ
  • with 文未使用

Node.js

  • keepAlive 無制御
  • errorイベント未処理

アプリ側で必ず行う修正ポイント

① finally / with / try-with-resources の徹底

「例外が起きても必ずcloseされる構造」にします。

② タイムアウトの明示設定

  • connect timeout
  • read timeout
  • request timeout

無限待ちは CLOSE_WAIT の温床です。

③ 接続プールを正しく使う

  • 最大接続数制限
  • アイドル破棄
  • 異常系での破棄

応急処置としてできること(限定的)

根本解決ではありませんが、被害抑止として以下は有効です。

  • プロセス再起動
  • コネクション上限設定
  • FD上限の引き上げ

※ ただし再発します

再発防止のための設計チェック

  • close() 呼び忘れが起きない構造か
  • 異常系・例外系の考慮
  • 通信失敗時のリトライ設計
  • NW断時の挙動

まとめ

CLOSE_WAIT は ネットワークの問題ではありません

それは「アプリが通信を終わらせていない」という、 明確なサインです。

OS設定を疑う前に、コードと設計を疑う。 それが最短での解決ルートです。

目次