専用サーバーにおけるNUMA対応とCPUピンニング

16分で読めます - 2026年6月16日

hero section cover
目次
  • 専用サーバーにおけるNUMA対応とCPUピンニング
  • マルチソケットサーバーにおけるNUMAの仕組み
  • Linux での NUMA トポロジーの確認
  • CPUピンニングとメモリポリシー
  • ワークロードに応じた戦略の選定
  • 確認すべきBIOSおよびカーネルの設定
共有

NUMAトポロジーの確認方法と、Linuxワークロードを適切なコアおよびメモリに割り当てる方法について解説します。numactl、taskset、systemd、BIOS設定、およびワークロード固有の戦略について扱います。

専用サーバーにおけるNUMA対応とCPUピンニング

マルチソケットサーバーでは、プロセスが実行される場所とメモリが配置される場所は別々の問題であり、これらを同期させないことは、パフォーマンスを無駄にする最も簡単な原因の一つとなります。 NUMAの理解とCPUピンニングは、この問題を解決する2つの手段です。本記事では、NUMAの仕組み、Linuxでの確認方法、およびデータベース、AIトレーニング、レイテンシに敏感なサービス向けにワークロードを適切にピンニングする方法について解説します。

マルチソケットサーバーにおけるNUMAの仕組み

NUMA(Non-Uniform Memory Access)ノードとは、専用のメモリコントローラを介してローカルなRAMブロックにバインドされたCPUコアのグループです。2ソケットサーバーでは通常、2つのノードが存在します。 どのコアも任意のアドレスを読み取ることができますが、ローカルアクセスは約80 nsであるのに対し、IntelのUPIやAMDのInfinity Fabricを介したソケット間ホップは約130~150 nsかかります。ソケット数が多い大規模なシステムでは、最悪の場合、ノード間のアクセス時間が250 nsを超えることもあります。

帯域幅も同様の傾向を示します。2ソケットのSapphire Rapidsシステムでは、コアがローカルメモリにアクセスする場合、約600 GB/sの帯域幅を維持できますが、ソケット間リンクの帯域幅はそのほんの一部であるため、そこを通過するトラフィックはすぐにボトルネックとなります。 コア数の多いプロセッサでは、この現象がより細分化されます。インテルのSub-NUMA Clustering(SNC)やAMDのNodes Per Socket(NPS)は、各ソケットを複数のNUMAドメインに分割するため、「2ソケット」のシステムでも、Linuxに対して4つや8つのノードを容易に提示できます。

NUMAを意識しない場合、Linuxスケジューラは、スレッドのワーキングセットが元のノードに残ったまま、ソケット間でスレッドを平然と移動させてしまいます。その後のアクセスはすべてリモートアクセスとなります。目に見える症状は、CPU使用率が高いにもかかわらず実際のスループットが低いことです。これは、コアがメモリを待つことに時間を費やしているためです。I/Oデバイスはこの状況をさらに悪化させます。 GPUやNICは特定のPCIeルートに接続されており、そのルートは1つのNUMAノードに属しています。もしそれらにデータを供給するプロセスが別のソケット上で実行されている場合、すべてのDMA転送はインターコネクトを横断することになります。

Linux での NUMA トポロジーの確認

以下の4つのツールで、必要な機能のほぼすべてを網羅できます:

  • lscpu ソケットとノードの概要を素早く確認するために。
  • numactl --hardware ノードごとのメモリ合計およびノード間の距離行列を確認する場合。
  • numastat プロセスごとのヒット/ミスカウンターを確認するには。
  • lstopo (hwloc より) キャッシュ階層および PCIe デバイスの局所性を確認します。

まずは numactl --hardwareから始めます。これには各ノード、それに属するコアとメモリ、および距離行列が一覧表示されます。値が10の場合はローカル、20以上はリモートです。マルチソケットマシンで単一のノードしか表示されない場合は、BIOSでNode Interleavingが有効になっており、トポロジーが隠されているため、まずそれを修正してください(以下を参照)。

特定のプロセスについては、 numastat -p <PID> は、そのプロセスのメモリが実際にどこに割り当てられているかを詳細に示します。重要なカウンターは4つあります:

  • numa_hit: 対象ノード上に割り当てられたメモリ。この値は高いほど望ましい。
  • numa_miss: 対象ノードが満杯だったため、割り当てが他の場所に溢れた。
  • numa_foreign: 別のノードがローカルでの割り当てを試みたができなかった場合。メモリ圧迫を示しています。
  • other_node: プロセスが実行されているノード以外のノードに割り当てられたページ。ここでの値が高いのは、不適切なピンニングの典型的な兆候です。

GPUやNICのワークロードについては、 lstopo-no-graphics を実行し、各PCIeデバイスがどのNUMAノードに接続されているかを確認してください。デバイスを駆動するコアが別のノードにある場合、それが最初に修正すべき点です。

CPUピンニングとメモリポリシー

CPU ピンニング(または CPU アフィニティ)は、プロセスを特定のコアにバインドし、スケジューラがそのプロセスを移動できないようにします。しかし、それだけでは不十分です。なぜなら、Linux はデフォルトでファーストタッチ・メモリポリシーを採用しており、ページは最初に書き込みが行われたノードに割り当てられるからです。 スレッドがピン留めされる前に誤ったノードで起動した場合、そのメモリはそこに留まります。配置と割り当ての両方を一緒に制御する必要があります。

一般的なケースに対応するツールは3つあります:

ツール制御対象用途
tasksetCPUコアのみ既存プロセスのクイックな単発バインディング
numactlCPUコアとメモリ厳密な局所性を伴うワークロードの起動
systemdCPUコアとメモリ、永続的再起動後も固定が必要なサービス

numactl 4つのメモリポリシーをサポート:

  • --membind=N: ノードNにのみ割り当て、満杯の場合は失敗する。
  • --preferred=N: ノードNを優先し、必要に応じて他のノードにフォールバックする。
  • --interleave=all: 帯域幅を均等に分散させるため、ノード間でラウンドロビン方式を採用。
  • --localalloc: 実行中のCPUが配置されているノードに割り当てる。

ワークロードを特定のノードに固定する

まず、ターゲットノードに属するコアを特定します:

numactl --hardware

次に、そのノードにコアとメモリの両方をバインドしてアプリケーションを起動します:

numactl --cpunodebind=0 --membind=0 ./your_application

既に実行中のプロセスについては、CPUアフィニティを次のように調整します: taskset:

taskset -cp 0-7 <PID>

再起動後も設定を維持するには、systemdユニットで設定します:

[Service]
CPUAffinity=0-7
NUMAPolicy=bind
NUMAMask=0

再読み込みして再起動します:

sudo systemctl daemon-reload && sudo systemctl restart <service>

手動でピン留めを行う際は、配置設定と競合しないよう、カーネルの自動負荷分散機能を無効にします:

sysctl -w kernel.numa_balancing=0

これを /etc/sysctl.conf に追加して永続化します。その後、 numastat -p <PID> 数分間の実際のワークロードで検証します。もし other_node がゼロ付近に留まる場合、ピンニングが有効になっています。

ワークロードに応じた戦略の選定

適切なポリシーは、ワークロードにとって低遅延の方が有益か、それとも全ノードにわたる総帯域幅の方が有益かによって異なります。

ワークロードポリシー理由
データベース(PostgreSQL、MySQL、SQL Server)--cpunodebind + --membind大規模な共有バッファ、レイテンシに敏感なクエリパス
インメモリキャッシュ(Redis、Memcached)シングルノードバインドすべてがRAMアクセスであり、リモートレイテンシが即座に現れる
AI/MLのトレーニングおよび推論GPUのNUMAノードへのバインドPCIeルート間を跨ぐテンソル転送を回避
分析(SparkElasticsearch--interleave=all大規模なワーキングセットには全ノードにわたる帯域幅が必要
レイテンシに敏感なAPI、トレードオフ厳格なピン + IRQ アフィニティピークスループットよりも予測可能性が重要
ネットワーク負荷が高い(RoCEv2、InfiniBandNICのNUMAノードへのピン割り当て、IRQ専用のコア確保割り込み処理をローカルに保ち、アプリスレッドの邪魔にならないようにする

特にGPUワークロードについては、 lstopo を実行してGPUがどのNUMAノードに配置されているかを確認し、その後 numactl --cpunodebind=N --membind=N を使用して、その同じ N でトレーニングまたは推論プロセスを起動します。デフォルトのスケジューラの配置は往々にして不適切であるため、これはマルチソケット GPU サーバーにおいて最も簡単に成果が得られる手法の一つです。

両方のソケットにまたがる HPC および MPI ワークロードについては、すべてをインターリーブするのではなく、 localalloc を使用して各ランクを単一のノードに固定し、すべてをインターリーブしないようにします。各ランクはローカルメモリを取得し、並列処理はランクレベルで行われます。

実用上の注意点として、単一のノードにランクを固定する場合は、そのノードに2~4GBの余裕を残しておいてください。ノードの使用率がほぼ満杯になるとメモリの回収がトリガーされ、削減しようとしていたレイテンシの損失につながります。

確認すべきBIOSおよびカーネルの設定

ツールの出力精度は、ファームウェアが公開するトポロジーの正確さに依存します。確認すべき設定は以下の通りです:

  • ノードインターリーブ:無効にしてください。有効にすると、BIOSはすべてのメモリを単一のフラットプールとして提示し、OSからNUMAを完全に隠蔽します。 numactl --hardware この場合、マルチソケットマシンでも1ノードとして表示されます。
  • Sub-NUMA Clustering(Intel)または Nodes Per Socket(AMD):より細かい局所性を求める場合は、コア数の多いプロセッサで有効にしてください。 lscpu 再起動後に確認してください。
  • vm.zone_reclaim_mode: ほとんどの運用サーバーでは0に設定します。0以外の値に設定すると、リモートに割り当てるのではなくローカルメモリを積極的に回収するため、有用なページキャッシュが追い出される可能性があります。
  • kernel.numa_balancing: 汎用ワークロードではオンにしておき、手動でピン留めを行う場合はオフにしてください。自動バランサーは、ポリシーと矛盾する方法でページやスレッドを移行してしまいます。

BIOS、カーネルパラメータ、IRQアフィニティを制御できるベアメタル環境でNUMAチューニングを行う場合、ハイパーバイザーの抽象化を回避することなく、上記の設定をすべて適用できます。これが、クラウドVMよりも専用ハードウェアの方がこの種の作業が容易である主な理由です。

フルルートアクセスが可能なマルチソケット専用サーバーについては、FDCの専用サーバーをご覧ください。

ブログ

今週の特集

その他の記事
Linuxサーバーのワークロード最適化のためのチューニング・プロファイル

Linuxサーバーのワークロード最適化のためのチューニング・プロファイル

GPU、データベース、高帯域幅 Linux サーバー用の調整済みプロファイルの選択、適用、カスタマイズ方法について、例と Ansible 導入のヒントを示します。

16分で読めます - 2026年6月9日

Linux OOM Killer Tuning for VPS: 実践ガイド

12分で読めます - 2026年6月8日

その他の記事
background image

ご質問またはカスタムソリューションが必要ですか?

icon

柔軟なオプション

icon

グローバル・リーチ

icon

即時展開

icon

柔軟なオプション

icon

グローバル・リーチ

icon

即時展開