その夜、午前2時頃、PagerDutyのアラートがけたたましく鳴り響き、私は跳ね起きました。今回はデプロイエラーやサービス全体の停止ではなく、重要なマイクロサービスのパフォーマンスが突然著しく低下したのです。
監視(Monitoring)グラフは乱れ、APIへのリクエストはタイムアウトが頻発しているにもかかわらず、サーバーのCPUとRAMの負荷は正常でした。顧客からの苦情が始まり、私は冷や汗をかきながら、管理しているUbuntu 22.04 4GB RAMサーバーに一体何が起こっているのかと自問自答しました。
実際の課題:原因不明のサーバーパフォーマンス低下
この状況は続き、ユーザーエクスペリエンスに深刻な影響を与えました。すべての兆候がアプリケーションが実行中であることを示しているにもかかわらず、まるでオペレーティングシステム層にボトルネックがあり、その処理能力が圧迫されているかのようでした。htop、topなどの監視ツールはCPU、RAMのリソースについては正常な結果を示しましたが、ネットワーク関連の指標に問題が見られました。特に、接続失敗数とレイテンシが急増していることに気づき、これは本当に警戒すべきことでした。
原因分析:カーネルパラメータが最適化されていない
数分間、ログやnetstatのようなコマンドと格闘した後、大量のTIME_WAITおよびCLOSE_WAIT状態の接続が積み重なっていることを発見しました。これは、Linuxカーネルがネットワーク接続のライフサイクル管理に苦慮していることを示しており、特にサーバーが短期間に多数の接続要求と切断要求を継続的に処理する必要がある場合に顕著でした。接続数がデフォルトの制限を超えているか、カーネルのソケットメモリ処理が非効率的である可能性があります。
問題はアプリケーションコードではなく、オペレーティングシステム層、具体的にはLinuxカーネルパラメータにありました。デフォルトでは、UbuntuのようなLinuxディストリビューションは、パーソナルデスクトップから小規模サーバーまで、さまざまなハードウェアと用途で安定して動作するように構成されています。
しかし、これらは特定のケースに合わせて最適化されていません。特に、すべてのミリ秒が貴重であり、同時に数千の接続を処理する能力が極めて重要な高負荷サーバーでは、デフォルト設定がボトルネックになる可能性があります。
カーネルパラメータは、カーネルのメモリー空間に格納される構成値であり、システム実行中に変更できます。これらは、カーネルが仮想メモリを管理する方法、ネットワークスタックを処理する方法、ファイルシステムの動作まで、すべてを制御します。これらのパラメータは、仮想ファイルシステム/proc/sys/を通じてアクセスされます。例えば、net.ipv4.tcp_tw_reuseの値を表示したい場合、実際には/proc/sys/net/ipv4/tcp_tw_reuseファイルを読み取っていることになります。
解決策
1. sysctl -wコマンドによる一時的な変更
まず、システムを機能させ、PagerDutyの負荷を軽減するための迅速な解決策が必要でした。sysctlツールが救世主となりました。いくつかのネットワーク関連パラメータを調整して、改善が見られるかどうかを試すことにしました。カーネルパラメータの現在の値を確認するには、次のコマンドを使用しました。
sysctl net.ipv4.tcp_tw_reuse
パラメータを一時的に変更するには、-wフラグを使用しました。
sudo sysctl -w net.ipv4.tcp_tw_reuse=1
私はnet.core.somaxconn(最大待機接続要求数)を増やし、net.ipv4.tcp_tw_reuseを有効にすることで、TIME_WAIT状態のソケットを再利用できるようにしました。すぐに、接続がより速く解放され始め、タイムアウトエラーが徐々に減少し、サーバーが安堵の息を吐き始めました。負荷が減り、顧客も徐々に安心しました。この解決策は、午前2時の緊張した瞬間を乗り切るのに役立ちました。
2. 設定ファイルによる永続的な変更
しかし、sysctl -wによる変更は、サーバーが再起動するまでしか有効ではありません。サーバーが再起動すると、すべてデフォルトに戻ります。これらの設定を永続的に有効にし、サーバー起動ごとに再設定する必要がないようにするには、/etc/sysctl.confファイルを編集するか、独自の構成ファイルを/etc/sysctl.d/ディレクトリに追加する必要があります。
最良の方法:`/etc/sysctl.d/`によるsysctl設定の管理
私は通常、/etc/sysctl.d/ディレクトリに独自のファイルを作成することを好みます。この方法は、個々のパラメータグループを簡単に管理し、必要に応じてロールバックできるため、システムの元のsysctl.confファイルに影響を与えることなく便利です。ファイル名はロード順序を決定するために2桁の数字で始めるべきであり(例: 99-custom-performance.conf)、数字が大きいほど優先度が高くなります。
例えば、/etc/sysctl.d/99-custom-performance.confというファイルを作成します。
sudo nano /etc/sysctl.d/99-custom-performance.conf
そして、以下の行を追加します。
# TIME_WAIT状態のソケットを素早く再利用できるようにする。
# これにより、TIME_WAIT状態にスタックしたポートがシステムによって迅速に解放され、
# 新しい接続が多い場合にポートが枯渇するのを防ぐ。
net.ipv4.tcp_tw_reuse = 1
# 最大接続キューを増やす(デフォルトは通常128)。
# 新しい接続を素早く多数受け入れる必要があるサーバーにとって非常に重要。
# 値が低すぎると、新しい接続が拒否される可能性がある。
net.core.somaxconn = 65535
# システムが開くことができる最大ファイルディスクリプタ数を増やす。
# 各ソケットはファイルディスクリプタであるため、この制限を増やすことで「Too many open files」エラーを回避できる。
fs.file-max = 1000000
# TCPソケットのデフォルトおよび最大受信/送信バッファを増やす。
# これにより、特に高速接続でのネットワークデータ転送パフォーマンスが向上する。
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_max = 4194304
# アウトバウンド接続が使用できるポート範囲。
# サーバーがアウトバウンド接続のためにより多くの利用可能なポートを持てるようポート範囲を拡大する。
# 多数のアウトバウンド接続を持つアプリケーションでのポート競合を避ける。
net.ipv4.ip_local_port_range = 1024 65535
# vm.swappinessを調整し、スワップよりもRAMキャッシュを優先する。
# 値を低くすると、システムがディスク(スワップ)にデータを書き込む量を減らし、パフォーマンスを向上させる。
# 値が0の場合、カーネルはスワップを完全に回避する(物理RAMが尽きるまで)。十分なRAMを持つサーバーの場合、10が良い選択肢。
vm.swappiness = 10
# SYNフラッド攻撃から保護するためにSYNクッキーを有効にする。
# システムが攻撃を受けている場合、SYNクッキーはリソースを過度に消費することなく接続処理を継続するのに役立つ。
net.ipv4.tcp_syncookies = 1
# FIN-WAIT-2ソケットの待機時間を短縮する。
# 接続終了後にネットワークリソースを素早く解放するのに役立つ。
net.ipv4.tcp_fin_timeout = 30
# キープアライブパケットを送信するまでの非アクティブな時間(秒)。
# 死んだ接続をより早く検出し、閉じるのに役立つ。
net.ipv4.tcp_keepalive_time = 600
# カーネルエラー(oops)が発生したときにシステムをパニックさせる。カーネルの問題を早期に診断するのに役立つ。
# 本番環境では、カーネルエラーを迅速に特定し修正するために重要。
kernel.panic_on_oops = 1
# 使用していない場合はIPv6を無効にする。
# ネットワークスタックを簡素化し、不要なセキュリティリスクを軽減するのに役立つ。
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
ファイルを保存した後、サーバーを再起動せずに変更を適用するには、次のコマンドを使用します。
sudo sysctl --system
このコマンドは、/etc/sysctl.d/ディレクトリ内のすべての構成ファイルと/etc/sysctl.confファイル(存在する場合)を読み取り、新しいパラメータを実行中のカーネルに適用します。sysctl -a | grep <parameter>コマンドを使用して、適用された値を確認できます。
個人的な経験と利点
さまざまな環境での複数回のテストと調整の後、/etc/sysctl.d/に個別の構成ファイルを作成することが最も効果的な管理方法であると私は認識しました。これにより、各パラメータグループを簡単に制御できるだけでなく、問題が発生した場合に迅速にロールバックすることもできます。
私が管理している4GB RAMのUbuntu 22.04本番サーバーでは、これによりピーク時のリクエスト処理時間が数百ミリ秒から数十ミリ秒に大幅に短縮されました。タイムアウトの問題はほとんど発生しなくなり、システムははるかにスムーズに動作し、深夜の電話を心配することなく、より安らかな睡眠をとることができるようになりました。
カーネルパラメータの最適化は、ネットワークパフォーマンスにとどまりません。システムがメモリ、I/O、さらにはセキュリティを管理する方法にも影響します。これらのパラメータを理解し、調整することは、プロフェッショナルなLinuxシステム管理の重要な部分です。
変更後のパフォーマンスの確認と監視
変更を適用した後、私は常にnetstat、ss、sar、iostatなどのツールを使用してシステムパフォーマンスを監視しています。これにより、変更が期待通りの効果をもたらしたか、または副作用を引き起こしたかを確認できます。客観的に評価するためのデータを持つことが重要です。
# 現在のすべてのsysctlパラメータを表示する
sysctl -a
# TCP/IP関連のパラメータをフィルタリングする
sysctl -a | grep "net.ipv4.tcp"
# TIME_WAIT状態の接続数をカウントする
sudo netstat -an | grep -i "time_wait" | wc -l
# ソケットに関する要約情報を表示する
sudo ss -s
# CPU、I/O、ネットワークに関する情報を表示する(1秒間隔で5回サンプリング)
sar -u 1 5 # CPU使用率
sar -n DEV 1 5 # ネットワークインターフェース統計
iostat -xz 1 5 # CPUおよびディスクI/O統計
最適化前の重要な注意事項
- 設定のバックアップ:大規模な変更を行う前に、常に
/etc/sysctl.confファイルと/etc/sysctl.d/内のファイルをバックアップしてください。適切なバックアップがあれば、問題が発生した場合に以前の状態に簡単に復元できます。 - ステージング環境でのテスト:カーネルパラメータの変更は、システムに広範な影響を与える可能性があります。本番環境と同様の構成を持つステージング環境または開発環境で徹底的にテストすることを強くお勧めします。これにより、本番システムに直接適用する際の不要なリスクを回避できます。
- 徐々に変更する:その影響を完全に理解せずに、一度に多数のパラメータを変更しないでください。少しずつ変更し、システムパフォーマンスを綿密に監視し、各変更の影響を評価してください。
- ドキュメントを読む:調整したい各パラメータについて深く理解するために、常にLinuxカーネルの公式ドキュメントまたは信頼できる情報源を参照してください。それらに関する深い知識は、より最適な決定を下すのに役立ちます。
sysctlによるカーネルパラメータの調整は、Linuxサーバーのパフォーマンスを最適化し、セキュリティを強化するための強力なテクニックです。
深夜のトラブルシューティングの経験から、カーネルの動作を深く理解し、それを調整する方法を知ることは、最も緊急な状況でシステムを救うことができると私は認識しました。これは、Linux本番システムを管理するITエンジニアにとって不可欠なスキルであり、問題を解決するだけでなく、強力で安定したシステムを構築し、ビジネスにより高い価値をもたらすのに役立ちます。
