ハードウェアを無駄にするのはやめよう:sysctlによるLinuxカーネルパラメータのチューニング

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

「高性能」ハードウェアが本領を発揮できないとき

以前、16コアと64GBのRAMを誇るサーバーに高トラフィックのAPIをデプロイしたことがありました。スペック上は「モンスターマシン」でした。しかし、同時実行ユーザー数が5,000人という中規模なスパイクが発生した際、アプリケーションは「Connection Refused(接続拒否)」エラーを吐き出し始めました。モニタリングツールを見ると、CPU使用率は15%でアイドル状態に近く、メモリにも十分な空きがありました。サーバーは過負荷だったのではなく、単に自身のオペレーティングシステムによって制限をかけられていたのです。

このような苛立ちは、開発者やシステム管理者にとって珍しいことではありません。生のパワーはあるのに、Linuxカーネルが汎用デスクトップ向けの「安全な」デフォルト設定で動作しているのです。ハードウェアの可能性を解き放つには、sysctlの世界に飛び込む必要があります。

問題点:現代にそぐわないレガシーなデフォルト設定

Linuxカーネルは、Raspberry Piからスーパーコンピュータまで、あらゆるデバイスで動作するように設計されています。そのため、デフォルト設定は保守的です。これらの設定は低スペックのノートPCでは安定性を確保しますが、毎秒数千のリクエストを処理する本番サーバーにとってはボトルネックとなります。

ほとんどのパフォーマンス問題は、次の3つのカテゴリに分類されます。攻撃的なスワップ:

  • ネットワークバックログ: 着信接続のキューが非常に小さい(多くの場合、デフォルトはわずか128)。これにより、NginxやNode.jsが接続を認識する前に、カーネルがパケットをドロップしてしまいます。
  • ソケットの枯渇: システムのエフェメラルポートが不足する。これは、閉じた接続をデフォルトの60秒間「TIME_WAIT」状態に保持し続けることで発生します。
  • 過度なスワップ: RAMに空きがあるにもかかわらず、カーネルがデータをディスクに移動させる。これにより、1ミリ秒のデータベースクエリが、ディスクI/O待機による100ミリ秒の悪夢に変わる可能性があります。

ハードウェア増設 vs カーネルチューニング

サイトが遅くなると、クラウドコンソールの「アップグレード」ボタンをクリックしたくなるのが反射的な反応です。RAMを増やせば余裕は生まれますが、設定ミスのあるネットワークスタックがそれで直ることは稀です。

アプローチ メリット デメリット
垂直スケーリング リソースを即座に増強できる。 月額コストの上昇。ソフトウェアのボトルネックを無視している。
ロードバランシング 冗長性に優れている。 構成の複雑化とレイテンシの増加を招く。
カーネルチューニング (sysctl) コストゼロ。効率を最大化できる。 不安定化を避けるためのテストが必要。

既存のリソースを最適化することが、最も賢明な第一歩です。sysctlを介したチューニングは、アプリケーションとその背後にあるハードウェアの間の摩擦を取り除きます。

sysctlへの体系的なアプローチ

数多くの本番クラスターを管理してきた経験から、闇雲に設定を変更するよりも体系的なアプローチの方が優れていることがわかりました。タイポ(打ち間違い)一つでカーネルパニックを引き起こしたり、サーバーから締め出されたりする可能性があります。これらの変更は、必ず最初にステージング環境でテストしてください。

1. sysctlの基本

sysctlコマンドは、実行時にカーネルパラメータを変更します。これらの設定は/proc/sys/ディレクトリにあります。

システムの現在の全設定を確認するには、以下を実行します:

sysctl -a

特定の値(例:オープンできるファイルの最大数)を確認するには、以下を使用します:

sysctl fs.file-max

永続化せずに変更をテストしたい場合は、-wフラグを使用します。この設定は再起動後に消えるため、安全策として最適です。

2. ネットワークスタックの修正

Webサーバーにとって、ネットワークスタックは最も頻繁なボトルネックです。サーバーが短命な接続を多数処理する場合、「パイプ」を広げ、ソケットをより速く再利用する必要があります。

設定ファイルを開きます:

sudo nano /etc/sysctl.conf

高い並行トラフィックを処理するために、以下のパラメータを追加します:

# 保留中の接続キューを増やす
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 8192

# 送信接続用に使用できるポートの範囲を広げる (デフォルトは多くの場合 32768-60999)
net.ipv4.ip_local_port_range = 1024 65535

# 新しい接続のために TIME_WAIT 状態のソケットを再利用する
net.ipv4.tcp_tw_reuse = 1

# リソースを解放するために接続をより速く切断する (デフォルトは 60秒)
net.ipv4.tcp_fin_timeout = 15

# スループット向上のために TCP ウィンドウサイズを大きくする
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

3. メモリ管理とスワップ設定 (Swappiness)

デフォルトでは、LinuxはRAMの使用率が約40%に達すると、RAMからスワップパーティションへのデータの移動を開始します。これはデータベースにとって致命的です。SSDやHDDからのデータアクセスは、RAMよりも桁違いに遅いためです。

ほとんどの本番サーバーでは、swappinessを10に設定します。これにより、カーネルにRAMを優先させ、ディスクは最後の手段としてのみ使用するように指示します。

vm.swappiness = 10
vm.dirty_ratio = 60
vm.dirty_background_ratio = 2

dirty_ratioの設定は、データをディスクに書き込む前にカーネルがキャッシュする方法を制御します。値を大きくすると書き込みパフォーマンスが向上しますが、停電時のデータ損失のリスクが高まります。

4. ファイルハンドル制限の拡張

Linuxでは、すべてのユーザー接続、ログファイル、ソケットはファイル記述子(ファイルディスクリプタ)です。デフォルトの制限はプロセスあたり1,024であることが多く、忙しいNginxワーカーなら数秒で上限に達してしまいます。

fs.file-max = 2097152

fs.file-maxはグローバルな制限を設定しますが、アプリケーションユーザーごとの制限を上げるために/etc/security/limits.confの更新も必要になる場合があることを覚えておいてください。

5. 変更の適用

/etc/sysctl.confを更新したら、以下のコマンドで即座に変更を適用します:

sudo sysctl -p

値が有効になったことを必ず再確認してください。例えば、sysctl net.core.somaxconnを実行して、新しい制限値65535がアクティブであることを確認します。

安全なワークフロー

巨大な設定ファイルをただコピー&ペーストしないでください。環境の安定性を保つために、次のワークフローに従ってください:

  1. ベースライン: wrkk6を使用してロードテストを実行し、現在のスループットとエラー率を測定します。
  2. 反復: 一度に1つの設定グループ(例:ネットワークのみ)を変更します。
  3. 監視: カーネルの警告やエラーがないか、dmesg/var/log/syslogを監視します。
  4. 検証: ロードテストを再実行します。接続エラーが減少し、レスポンスタイムがより安定するはずです。

カーネルのチューニングは魔法ではありませんが、魔法のように感じられることもあります。同じCPU使用率でサーバーが2倍のトラフィックを処理できるのを見るのは、非常に満足感があります。まずはsomaxconnswappinessから始めてみてください。これら2つの変更だけでも、ほとんどのワークロードで最大の効果が得られます。

Share: