CPUアフィニティの理解とnice/reniceによるプロセス優先度の設定

Linuxの`taskset`、`nice`、`renice`を使用して、重要な作業を枯渇させることなくCPUアフィニティとプロセス優先度を調整する方法。

CPUアフィニティの理解とnice/reniceによるプロセス優先度の設定

Linuxホストがビジー状態のとき、「スケジューラに任せる」だけでは不十分な場合があります。CPUアフィニティはプロセスが実行できる場所を制御し、nicereniceはCPU時間をめぐる競合の強さに影響を与えます。

このガイドでは、tasksetnicereniceの実用的な例と、本番ワークロードを変更する前に注意すべきトレードオフを紹介します。

CPUアフィニティ:プロセスを特定のコアにバインドする

CPUアフィニティは、オペレーティングシステムがプロセスやスレッドを特定のCPUまたはCPUセットに結びつけるメカニズムです。プロセスがCPUコアにバインドされると、そのコアでのみ実行されます。これにはいくつかのパフォーマンス上の影響があります:

  • キャッシュ無効化の削減: 最新のCPUには、頻繁にアクセスされるデータを格納するマルチレベルキャッシュ(L1、L2、L3)があります。プロセスが異なるCPUコア間を移動すると、前のコアのキャッシュ内のデータが無効になり、新しいコア用に新しいデータをフェッチする必要があります。プロセスを単一のコアにバインドすることで、データがそのコアのキャッシュに留まり、アクセス時間が短縮されます。
  • コンテキストスイッチの最小化: スケジューラがコア上で別のプロセスを実行することを決定すると、現在のプロセスの状態が保存され(コンテキストスイッチ)、新しいプロセスの状態がロードされます。プロセスが頻繁にコア間を移動する場合、これらのコンテキストスイッチに関連するオーバーヘッドが蓄積される可能性があります。CPUアフィニティは、プロセスを同じコアに維持することでこのオーバーヘッドを削減できます。
  • NUMAアーキテクチャ: Non-Uniform Memory Access(NUMA)システムでは、CPUコアとメモリコントローラへの近接性によってメモリアクセス時間が異なります。プロセスを特定のコアにバインドすることで、ローカルメモリにアクセスし、レイテンシを低減できます。

CPUアフィニティの設定方法

LinuxカーネルはしばしばCPUアフィニティを自動的に管理しますが、管理者は手動で影響を与えることができます。そのための主要なツールはtasksetです。

tasksetの使用

tasksetコマンドを使用すると、実行中のプロセスのCPUアフィニティマスクを取得または設定したり、指定されたアフィニティで新しいコマンドを起動したりできます。

構文:

  • 実行中のプロセスのCPUアフィニティを表示するには:

    taskset -p <PID>
    
  • 実行中のプロセスのCPUアフィニティを設定するには:

    taskset -p <mask> <PID>
    

    <mask>は、許可されたCPUのビットマスクを表す16進数です。例えば、0x1(バイナリ0001)はCPU 0、0x2(バイナリ0010)はCPU 1、0x3(バイナリ0011)はCPU 0と1を意味します。

  • 特定のCPUアフィニティで新しいコマンドを起動するには:

    taskset -c <cpu_list> <command>
    

    <cpu_list>は、CPU IDまたは範囲のカンマ区切りリストです(例:00-31,3)。

例:

計算タスクmy_programを実行し、CPUコア3にバインドするとします:

taskset -c 3 ./my_program

my_programがPID 12345で既に実行中で、アフィニティマスクで制限したい場合:

taskset -p 1 12345

このコマンドは16進マスクを使用するため、1はCPU 0を意味します。プロセスをCPU 1に移動するには、CPU番号とともに-cを使用します:

taskset -cp 1 12345

ヒント: nprocを使用するか、/proc/cpuinfoを調べることで、利用可能なCPUの数を確認できます。

警告: CPUアフィニティを誤って設定すると、パフォーマンスが低下する可能性があります。アフィニティ設定の有無でアプリケーションをベンチマークし、利点を確認することをお勧めします。

nicereniceによるプロセス優先度管理

CPUアフィニティがプロセスの実行場所を決定するのに対し、プロセス優先度は他のプロセスと比較してどれだけのCPU時間を得るかを決定します。Linuxはスケジューリング優先度を制御するために「ナイス値」の概念を使用します。ナイス値の範囲は-20(最高優先度、最も多くのCPU時間)から+19(最低優先度、最も少ないCPU時間)です。プロセスのデフォルトのナイス値は0です。

ナイス値が高いほど、プロセスは他のプロセスに対して「優しく」なり、より多くのCPU時間を譲ります。逆に、ナイス値が低いほど、プロセスは「優しくなく」なり、より多くのCPU時間を取得しようとします。

niceコマンド

niceコマンドは、変更されたナイスレベルでプログラムを実行するために使用されます。通常、新しいプロセスを起動する際に使用されます。

構文:

nice -n <niceness_level> <command>
  • -n <niceness_level>:ナイス値を指定します(指定しない場合のデフォルトは10)。

例:

my_background_taskを低優先度(高いナイス値15)で実行するには:

nice -n 15 my_background_task

my_critical_appを高優先度(低いナイス値-10)で実行するには:

nice -n -10 my_critical_app

重要な注意: 負のナイス値(優先度を上げる)を割り当てることができるのはrootユーザーのみです。通常のユーザーは、自分のプロセスのナイス値のみを増やす(優先度を下げる)ことができます。

reniceコマンド

reniceコマンドは、既に実行中の1つ以上のプロセスのナイスレベルを変更するために使用されます。

構文:

renice -n <niceness_level> -p <PID>
  • -n <niceness_level>:新しいナイス値。
  • -p <PID>:変更するプロセスのプロセスID。

例:

プロセス12345の優先度を下げる(ナイス値を上げる)には:

renice -n 10 -p 12345

プロセス54321の優先度を上げる(ナイス値を下げる)には(root権限が必要):

sudo renice -n -5 -p 54321

reniceは、ユーザー(-u)またはプロセスグループ(-g)でプロセスをターゲットにすることもできます。

例:

ユーザーwww-dataが所有するすべてのプロセスをナイス値5に設定するには:

sudo renice -n 5 -u www-data

ヒント: topまたはhtopを使用して、実行中のプロセスのナイス値(NI列)を表示し、優先度調整の候補を特定します。

警告: プロセスに非常に高い優先度(低いナイス値)を与えると、他のプロセスを枯渇させ、システムが応答しなくなる可能性があります。特に本番システムでは注意して使用してください。

実用的なシナリオとベストプラクティス

CPUアフィニティのシナリオ:

  • データベースサーバー: データベースプロセスを特定のコアにバインドすると、データがCPUキャッシュに留まるため、クエリパフォーマンスが向上します。
  • 高頻度取引アプリケーション: これらはしばしば最小限のレイテンシと予測可能なパフォーマンスを必要とし、CPUバインディングが重要です。
  • 仮想化ホスト: 特定のコアを仮想マシンまたはホスト自体に専用に割り当て、分離性とパフォーマンスを向上させます。

プロセス優先度のシナリオ:

  • バッチジョブ/バックグラウンドタスク: これらは高いナイス値(nice -n 15)で実行することで、インタラクティブなユーザータスクや重要なサービスに干渉しないようにします。
  • インタラクティブアプリケーション: バックグラウンドタスクがすべてのCPUリソースを消費しないようにすることで、デスクトップアプリケーションやシェルの応答性を確保します。
  • 緊急リソース割り当て: まれに、重要なシステムプロセスが苦戦している場合、reniceを使用して一時的に優先度を上げることができます(rootとして)。

ベストプラクティス:

  1. まずベンチマーク: CPUアフィニティや優先度の変更を適用する前後で、常にパフォーマンスを測定します。利点は常に保証されるわけではなく、アプリケーションに依存する場合があります。
  2. ハードウェアを理解する: CPUアフィニティを設定する際は、CPUトポロジ(コア、ソケット、NUMAノード)を把握します。
  3. top/htopを使用する: CPU使用率、ナイス値、プロセス状態を監視して、パフォーマンスの問題を特定し、変更をテストします。
  4. 優先度を上げるにはroot権限: ナイス値を下げる(優先度を上げる)ことができるのはrootのみであることを覚えておいてください。この権限は慎重に使用してください。
  5. 控えめに開始する: 優先度調整では、極端な値(-20や+19)に進む前に、適度なナイス値(例:5、10)から始めてください。
  6. NUMA認識を考慮する: NUMAシステムでは、numactlなどのツールがCPUとメモリのバインディングに対してより高度な制御を提供します。

まとめ

配置が重要な場合(NUMAに敏感なサービスや分離されたバッチジョブなど)はCPUアフィニティを使用します。問題がスケジューリング優先度の場合はnicereniceを使用します。小さな変更から始め、読みやすいCPUリストにはtaskset -cを優先し、チューニングルールを恒久的にする前にベンチマークを行ってください。