ファイルディスクリプタは、LinuxがオープンされたI/Oリソースへの有限の参照として使用するため、セルフホストのホームサーバーを制限することがあります。サービスはCPU、RAM、ネットワーク帯域幅に余裕があっても、ディスクリプタの予算が尽きると接続を受け入れたり、メディアファイルを開いたり、ログを書き込んだり、パイプを作成したり、他のリソースを監視したりできなくなります。
制限はプロセス、systemdサービス、コンテナランタイム、ユーザー、またはカーネル全体のいくつかの層に存在する可能性があります。目に見える症状はしばしば「ファイルが多すぎます」ですが、枯渇したリソースは実際にはソケット、パイプ、イベントハンドル、またはリークであって、通常のファイルとは限りません。
ホームサーバーでファイルディスクリプタは何を表すのか?
ファイルディスクリプタは、オープンされたカーネルリソースを指す小さなプロセスローカルの整数です。ファイル、ソケット、パイプはすべてディスクリプタを消費し、同じ読み書き、ポーリング、クローズのパターンが異なるリソースタイプで機能します。
リバースプロキシはリスニングソケットと受け入れたクライアント接続にディスクリプタを使用します。データベースはデータファイル、ログ、ソケット、パイプに使用します。メディアサーバーはライブラリファイル、メタデータ、サブプロセス通信、アクティブストリームにディスクリプタを保持できます。
ディスクリプタ番号はプロセスの参照に過ぎません。カーネルは基になるオープンファイルやソケットオブジェクト、その状態、オフセット、バッファ、所有権をすべての参照が閉じられるまで追跡します。
サービスが実際に到達可能なディスクリプタ制限はどれか?
Linuxは複数の上限を適用するため、複数のディスクリプタ制限が独立して失敗することがあります。現在のソフトリミットは通常の割り当てを制御し、ハードリミットはそのソフトリミットがどこまで上げられるかを制約します。
systemdユニットは、対話型シェルとは異なる制限を継承または上書きすることがあります。コンテナはホストとは異なるランタイムのデフォルトを継承できますが、カーネルは依然としてホスト全体のオープンファイル容量を強制します。
これが、あるシェルでの `ulimit -n` が影響を受けるサービスを説明しない理由です。関連する値は実行中のプロセスとそのサービスやコンテナのコンテキストに属し、単に管理者のログインセッションに属するわけではありません。
なぜネットワーク接続は同じ有限のプールを消費するのか?
受け入れたすべてのTCP接続とほとんどのアウトバウンドソケットはディスクリプタを必要とします。接続の再利用は繰り返しのソケット作成を減らし、セットアップ作業と同時に遷移中の接続数の両方を減らします。
リバースプロキシ、データベースプール、WebSocketサービス、ダウンローダー、監視エージェント、メディアアプリはすべて、異なるプロセスを通じて同じプロセスまたはホストレベルのディスクリプタ予算を消費することがあります。
閉じられた接続もネットワークスタックの他の場所にしばらく残ることがありますが、ソケットが閉じられたときにアプリケーションのディスクリプタは解放されるべきです。開いているソケットディスクリプタの持続的な増加は、通常のTCPクリーンアップだけでなく、長期間続く負荷やリークを示しています。
新しいディスクリプタが割り当てられないと何が失敗するのか?
プロセスが自身の制限に達すると、ディスクリプタの枯渇により新しいI/Oリソースがブロックされます。システム全体の制限は、最も多くのハンドルを消費したプロセスだけでなく、複数の無関係なサービスに影響を与えることがあります。
サーバーは新しいクライアントの受け入れを停止しても、既存のセッションは継続することがあります。ログ記録が失敗したり、設定のリロードが壊れたり、DNSルックアップがソケットを開けなかったり、アプリケーションが誤ったデータベースやストレージのエラーを報告することがあります。
診断ツール、SSHセッション、サービスマネージャー、再起動フックもディスクリプタを必要とするため、障害は連鎖的に広がる可能性があります。1つの負荷を制限するためのリソース制限は、ホストがすでに枯渇している場合に回復を困難にすることがあります。
なぜディスクリプタリークは正当なピークと異なるのか?
正当なピークは同時ユーザー数や開いている作業に応じて増加し、その作業が完了すると減少します。ディスクリプタリークはリソースを解放せずに増加します。これはアプリケーションが参照を失うか保持し続け、閉じないためです。
制限を引き上げることは、アプリケーション、メモリ、ソケット、および下流システムがより大きな負荷に対応するように設計されている場合にのみ、正当な高同時実行サービスに役立ちます。リークの場合、それは単に同じ障害が再発するまでの時間を延ばすだけです。
合計だけでなく、タイプや経過時間ごとにディスクリプタの数を監視しましょう。数千の予想されるクライアントソケットは、着実に増加する削除されたログファイル、パイプ、イベントオブジェクト、または利用できない依存関係への接続とは異なる意味を持ちます。
なぜ制限を引き上げることが本当の問題を隠すのか?
コンテナやデーモンは複数の設定レイヤーから制限を受けることがあり、コンテナの制限はホストの制限と異なる場合があります。一つのレイヤーだけを変更しても実効制限は変わらないことがあります。
はるかに大きな上限は、暴走するサービスが制御される前により多くのカーネルメモリやソケットを消費することも許します。正しい値は、予想される同時実行数、開いているファイル、ウォッチャー、パイプ、安全な余裕、障害時の挙動に基づくべきです。
まず現在の制限、現在の使用量、成長率、ディスクリプタの種類を測定します。リークや無制限の接続動作を修正し、観測された正当なピークが正当な余裕を持って制限に近づいた場合に実効サービス制限を引き上げます。
| ディスクリプタ圧力 | 典型的なパターン | 正しい対応 |
|---|---|---|
| 正当な同時実行 | トラフィックに伴いカウントが増加し、その後減少する | 容量テストを行い、実効サービス制限を引き上げる |
| ディスクリプタリーク | カウントが着実に増加し戻らない | 未クローズのリソースを見つけてライフサイクル処理を修正する |
| コンテナまたはsystemdの不一致 | シェルの制限は高いがサービスが早期に失敗する | 実行中のプロセスとサービス/ランタイムの制限を調査する |
| システム全体の枯渇 | 複数の無関係なサービスがリソースを開けない | 主要な消費者を特定し、回復アクセスを確保する |
よくある質問
すべての開いているファイルは正確に1つのディスクリプタを使用しますか?
通常、1つのプロセス参照は1つのディスクリプタを使用しますが、複製されたディスクリプタ、継承されたディスクリプタ、複数のプロセスが同じ基底のオープンオブジェクトを参照することがあります。
ホームサーバーは低いCPU使用率でファイルディスクリプタの制限に達することがありますか?
はい。ディスクリプタの容量はCPU使用率とは独立しています。待機中のサービスは、ほとんど計算を行わずに多くのソケットやファイルを保持できます。
ulimitを増やせば「Too many open files」エラーはすべて解決しますか?
いいえ。サービスは異なるsystemdやコンテナの制限を使用している場合があり、ホストがシステム全体の上限に達しているか、アプリケーションがディスクリプタをリークしている可能性があります。
inotifyウォッチは開いているファイルディスクリプタと同じですか?
inotifyインスタンスはディスクリプタを使用し、多数のウォッチを含むことができます。ウォッチの制限とディスクリプタの制限は関連するカーネルリソースですが、同一ではありません。
最終的な結論
ファイルディスクリプタは、ファイル、ソケット、パイプ、多くのイベント駆動型リソースの背後にある有限のプロセス参照であるため、セルフホストサーバーの制限となります。枯渇すると、主要なハードウェア指標が正常に見えても新しい作業がブロックされることがあります。安定した容量を確保するには、実際のプロセスおよびサービスの制限を測定し、正当な同時実行とリークを区別し、リソースのライフサイクルを理解した上で上限を引き上げる必要があります。
テック&AIハブ
もっと読む

Home Assistantにおけるランタイム状態と永続状態:再起動後も維持すべきものは?
Home Assistantはすべてのライブ値を永続化するわけではありません。設定、レジストリ、選択された復元状態、履歴、デプロイデータは、再起動時にそれぞれ異なる役割を果たします。

Home Assistantはローカルセッションとリモートセッションをどのように認証しますか?
ローカルおよびリモートのHome Assistantセッションでは、同じサーバー側のIDモデルを使用します。リモートアクセスによって変わるのは経路とTLSの境界であり、トークンフローの中核ではありません。

Recorderデータが増えると、なぜHome Assistantの履歴クエリは遅くなるのですか?
レコーダーの成長に伴い、要求された範囲に含まれる行数が増えたり、キャッシュミスが増加したり、ストレージやインデックス処理が遅くなったりすると、履歴クエリのコストが上昇する可能性があります。

