こんにちは!クラウドインフラやKubernetesの裏側で、日々パケットの旅路を見守っているSREの筆者です。
皆さんは、仮想マシン(VM)やコンテナを使っていて、「なんだか最近、アプリの応答速度が急にモタつくな…」「負荷は高くないのに、なぜか処理が遅い瞬間がある」と感じたことはありませんか?
クラウドの世界では、1台の強力な物理サーバーの上に、たくさんの「間借り人(仮想マシン)」が暮らしています。このお隣さん同士がリソースを奪い合うことで起きるパフォーマンスの揺らぎは、インフラエンジニアにとって永遠の頭痛の種です。
今回は、そんなモタつきを根元から断ち切り、まるで専用の特等席を用意するかのように爆速なパフォーマンスを引き出す技術、「CPUピンニング(CPU Pinning)」と「NUMAトポロジー」について、身近な例えを交えながら優しく紐解いていきましょう。
難しい専門用語が出てきても「一歩ずつ理解していきましょう!」、大丈夫です。ゆっくり見ていきましょうね。
—
1. 仮想化の便利さと、「座席ガチャ」のモヤモヤ
まずは、私たちが普段使っているクラウドや仮想化の仕組みを、少し違った角度から見てみましょう。
物理サーバーという巨大なビルの中には、計算をしてくれる頭脳である「CPUコア」がたくさん入っています。仮想化技術を使うと、この1つのビルを区切って、いくつもの小さなお部屋(仮想マシン)を作り、いろいろなユーザーに貸し出すことができますよね。
ここで問題になるのが、「vCPU(仮想CPU)の座席ガチャ」です。
通常、仮想マシンに割り当てられたvCPUが、物理サーバーの「どのCPUコア」で動くのかは、ハイパーバイザー(VMware ESXiやKVMなど)という管理人さんがその時々の気分や空き状況で決めています。
- ある瞬間: 1階の窓際の快適なCPUコアでお仕事
- 次の瞬間: エレベーターを何度も乗り換えるような、遠く離れた別の階のCPUコアにお引越し
これをコンピューターの世界では、CPUが頻繁に切り替わることによる「キャッシュミスの多発」や「コンテキストスイッチのオーバーヘッド」と呼びます。人間で例えるなら、仕事道具を毎秒違う机に引っ越しさせられているようなもので、そりゃあ疲れて仕事も遅くなりますよね。
—
2. 郵便配達で例える「NUMA(ヌーマ)」と物理の壁
この「お引越し問題」をさらに複雑にしているのが、現代のサーバーが持つ「NUMA(Non-Uniform Memory Access:不均一なメモリアクセス)」という構造です。
サーバーの規模が大きくなると、CPUコアやメモリが1つのグループ(NUMAノード)には収まりきらなくなります。
身近な例え:大きなオフィスの文房具置き場
- NUMAノード内(自分のフロア):
自分の席のすぐ後ろに大きな文房具棚(メモリ)がある状態。手を伸ばせばすぐにノートやペン(データ)を取ることができます。
- NUMAノード跨ぎ(別のフロア):
自分の席は3階にあるのに、必要な資料がなぜか遠く離れた5階の倉庫にしかな culturales い状態。わざわざ階段(バス)を上り下りして取りに行かなければならず、すごく時間がかかりますよね。
仮想マシンが動くとき、もしvCPUが3階にいるのに、その子が使うメモリが5階にあったとしたらどうでしょう? データを取りに行くたびに待ち時間(レイテンシの増加)が発生し、アプリのパフォーマンスはガタ落ちしてしまいます。
—
3. 特等席を予約する「CPUピンニング」とは?
そこで登場するのが、今回の主役である「CPUピンニング(CPU Pinning)」です。
ピンニング(Pinning)とは、英語の「ピン留め」のこと。
管理人さんにお願いして、「この仮想マシンのvCPUは、必ず物理サーバーの【第0コアと第2コア】の特等席だけに座らせてください!他の席には移動させません!」と、ガッチリ固定してしまう設定のことです。
これを行うことで、以下のような圧倒的なメリットが生まれます。
1. お引越しがゼロに:
CPUが別のコアへ移動しないため、CPU内部の小さな黒板(L1/L2キャッシュ)に記憶した情報がそのまま使えます。キャッシュヒット率が劇的に跳ね上がり、処理がスピードアップします。
2. NUMAノードの局所化:
CPUコアだけでなく、その近くにあるメモリ(NUMAノード)もセットで固定(メモリバインディング)することで、遠くのフロアへデータを探しに行く無駄な時間を完全に排除できます。
金融系の超高速取引システムや、ミリ秒単位の遅延が許されないリアルタイム配信、負荷の高いデータベースなどでは、このCPUピンニングが「標準装備」として使われています。
—
4. 実践!Libvirt/KVM環境でのCPUピンニング設定
「理屈は分かったけれど、実際の現場ではどうやって設定するの?」という方のために、代表的な仮想化基盤であるKVM(Libvirt)環境を例に、具体的な設定ファイル(XML)の書き方を見てみましょう。
仮想マシンの設定ファイル(virsh edit <vm-name>などで開くXML)に、以下のような追記を行います。
<domain type='kvm'>
<!-- 仮想マシンの基本設定 -->
<name>ultra-fast-db-server</name>
<memory unit='KiB'>8388608</memory> <!-- 8GBのメモリを割り当て -->
<!-- NUMAトポロジーの定義:CPUとメモリの距離を最適化する -->
<cpu mode='host-passthrough'>
<topology sockets='1' cores='4' threads='1'/>
<numa>
<!-- 物理NUMAノード0に属するCPU 0〜3 と、対応するメモリを割り当て -->
<cell id='0' cpus='0-3' memory='8388608' unit='KiB'/>
</num>
</cpu>
<!-- CPUピンニング(VCPUと物理CPUの紐付け)の設定 -->
<cputune>
<!-- 仮想マシンのvCPU 0番を、物理CPUコア 2番に固定 -->
<vcpupin vcpu='0' cpuset='2'/>
<!-- 仮想マシンのvCPU 1番を、物理CPUコア 3番に固定 -->
<vcpupin vcpu='1' cpuset='3'/>
<!-- 仮想マシンのvCPU 2番を、物理CPUコア 4番に固定 -->
<vcpupin vcpu='2' cpuset='4'/>
<!-- 仮想マシンのvCPU 3番を、物理CPUコア 5番に固定 -->
<vcpupin vcpu='3' cpuset='5'/>
</cputune>
</domain>
設定のポイント
<topology>タグで、仮想マシン側にも「うちはこういうCPUの形をしていますよ」と伝えます。<cputune>ブロックの中の<vcpupin>で、仮想の何番(vcpu)を物理の何番(cpuset)に座らせるかを指定しています。- これにより、OSやハイパーバイザーが勝手に座席を変更(マイグレーション)することを防ぎます。
—
5. クラウドやKubernetesの世界でのCPUピンニング
「うちはAWSやGCP、Kubernetesを使っているから、KVMのXMLなんて直接触らないよ」という方もご安心ください。モダンなプラットフォームでも、この概念は形を変えてしっかり息づいています。
- Kubernetes(コンテナの世界):
Podの品質保証クラスをGuaranteedに設定し、CPUマネージャーポリシーをstaticに設定することで、コンテナが特定のCPUコアを専有(ピンニング)できるようになります。これにより、隣のコンテナが暴走しても、自分のパフォーマンスが落ちない強靭な環境が作れます。
- パブリッククラウド(AWS EC2など):
「ベアメタルインスタンス」や、CPUを完全専有する「Dedicated Hosts / Dedicated Instances」を選ぶことで、物理レベルでのリソース競合を排除し、独自のNUMA/CPUチューニングを行う下地が整います。
—
まとめ:インフラの「見えない摩擦」を減らす職人技
今回は、CPUピンニングとNUMAトポロジーについて、郵便配達やオフィスの席替えに例えて解説しました。
- CPUピンニングは、仮想CPUに「自分専用の特等席」をプレゼントしてキャッシュ効率を上げる技術。
- NUMAトポロジーの意識は、CPUとメモリの距離を近づけて、遠くへの無駄な移動をなくす技術。
普段私たちが何気なく使っているクラウドやコンテナの裏側では、こうしたハードウェアの物理特性をいかに綺麗に使い切るかという、インフラエンジニアたちの泥臭い工夫やこだわりが詰まっています。
「なんだかアプリのパフォーマンスが頭打ちだな」と感じたときは、ぜひこの「座席ガチャ」と「お部屋の距離」を思い出してみてください。きっと、目に見えないボトルネックを解決する大きなヒントになるはずです。
それでは、また次回のインフラ探訪でお会いしましょう!
コメント