HN 日本語サマリー

← 一覧へ戻る
インフラ・DevOps

NUMA: コア、メモリ、そしてそれらの間の距離

NUMA: Cores, memory, and the distance between them (edera.dev)

109 pointsby sys_call24 コメント

要約

この記事は、NUMA(Non-Uniform Memory Access)アーキテクチャについて解説しています。UMA(Uniform Memory Access)との違いから、マルチソケットサーバーの登場、さらには単一ソケット内のNUMAノード化(AMD EPYCのCCDやIntel XeonのSNC)に至るまでの進化を歴史的背景とともに説明します。NUMA環境下でのメモリアクセスのコストと、それがワークロードのパフォーマンスに与える影響について深く掘り下げています。

全文翻訳

NUMA - パート1: コア、メモリ、そしてそれらの間の距離 2026年6月23日 - Steven Noonan 同じホスト上に、同一に構成され、同じワークロードを実行している2つの仮想マシン。そのうちの1つは、一貫してもう1つよりも20%遅い。ワークロードには何も問題はなく、ホストにも何も問題はなく、他のテナントからの競合もない。遅い方のメモリが、たまたま実行中のCPUから見てインターコネクトの「間違った側」にあり、オペレーターが修正できるゲスト内の設定ノブは存在しない。 これが本シリーズで扱う物語です。Ederaは、Xenベースの仮想化をNUMAアウェアにするための変更スタックを出荷しました。これは、ゲスト内部、準仮想I/Oドライバ経由、dom0、そしてハイパーバイザーのホストハードウェアの視点まで、エンドツーエンドに及んでいます。これらのうち一部は、我々が知る限り、世界初の実装です。なぜそれが重要なのかを説明するために、まずNUMAが実際に何であるかから始めなければなりません。 NUMAの起源: UMAからマルチソケットサーバーへ NUMAはNon-Uniform Memory Accessの略です。その定義する特性は名前にあります。NUMAマシン上のメモリアクセスコストは均一ではありません。アクセスを実行しているCPUが重要であり、データが存在する物理メモリバンクが重要であり、コストはこれら2つの関係に依存します。 NUMAの歴史的な対義語はUMA、Uniform Memory Accessであり、そこではすべてのCPUが同じメモリコントローラーを介して同じコストですべてのメモリバイトにアクセスします。UMAはシングルソケットのコモディティサーバーや多くの組み込みシステムの時代でした。概念的にはシンプルであり、ある限界までスケールアップします。その限界とは、おおよそ「1つのシリコンチップに、1つのメモリチャンネルセットで搭載できるコアの数」です。 その限界を超えてプッシュする必要がある場合はどうなるでしょうか? UMAは停止するまでスケールし、「停止」にはいくつかの絡み合った理由があります。電気配線長が長くなります。信号が端から端まで伝播するのに時間がかかり、現代のメモリバスが動作するデータレートでは、長い配線は信号の整合性を保つためにバスの速度を落とすことを強制します。これはレイテンシの上にレイテンシを積み重ねます。(これはL1 / L2 / L3キャッシュ階層の背後にあるのと同じ物理学です。L1が小さいのは、キャッシュを小さくしてコアに物理的に近づけることが、それを高速に保つための一部です。)単一のメモリコントローラーは、任意の数のコアをフル帯域幅で供給することはできません。パッケージのピン数は、1つのソケットに配線できるメモリチャネルの数に厳しい上限を設けています。多くのCPUが同時にメモリを読み取ろうとする際のバス競合は無視できなくなります。業界の答えは、各ソケット(またはダイ)に独自のメモリコントローラーを与え、メモリが単一の対称的なプールであるというふりをやめることでした。マシンはNUMAになります。各ノードは独自のCPUと独自のメモリのスライスを持っています。CPUは依然としてどのノードからも読み取ることができますが、リモートノードへの読み取りはインターコネクトを横断する必要があり、インターコネクトは絶対的には高速ですが、ローカルDRAMアクセスと比較すると低速です。 UMA CPU 0 CPU 1 CPU 2 CPU 3 メモリコントローラー メモリ 単一のプール、すべてのCPUで共有 すべてのアクセスは同じコスト NUMA ノード0 CPU 0 CPU 1 メモリコントローラー メモリ ノード1 CPU 2 CPU 3 メモリコントローラー メモリ インターコネクト ローカルアクセスは安価。リモートアクセスはインターコネクトを横断する。 インターコネクトを隣接する2つの町を結ぶ橋だと考えると役立ちます。空いている道路では、横断はローカルの交通量よりわずかに遅いだけです。ラッシュアワーで、誰もが同時に同じ橋を使おうとすると、コストは現在のキューによって決まります。この区別については、ビジーな本番ワークロードと静かなマイクロベンチマークでNUMAがどのように見えるかについて話すときに戻ってきます。 これがどこから来たのかを理解するための簡単な年表です。商業用NUMAは1990年代に、1つのバスでは供給しきれない数のコアを必要とする少数の買い手をターゲットとした大型システムに登場しました。SGIのOriginシリーズ、Sequent NUMA-Q、CompaqのAlphaServer GSシリーズなど、すべてが独自のノード間ファブリックを持っていました。NUMAはコモディティx86に2003年、AMDのOpteronとともに登場しました。Opteronは各ソケットに独自のメモリコントローラーを与え、HyperTransportを介してソケット間を接続しました。Intelは2008年、NehalemとQuickPath Interconnect(QPI)で追いつきました。それ以前は、真にUMAであったフロントサイドバスチップセットが長期間にわたって使用されていました(すべてのCPUがノースブリッジへの単一バスを共有し、ソケットごとのメモリはまったくありませんでした)。今日のIntel部品はQPIの後継であるUltra Path Interconnect(UPI)を使用し、今日のAMD部品はHyperTransportの後継であるInfinity Fabricを使用しています。各世代は絶対的な帯域幅を大幅に向上させましたが、リモート対ローカルDRAMコストの比率は、おおよそ同じ範囲で頑固に維持されています。 これまでのところ、ソケットが1つのNUMAノードであると考えてしまいたくなるかもしれません。Opteron以降の10年間ほとんど、それは正解でした。当時のソケットごとのコア数では、単一のメモリコントローラーがソケット全体を問題なく供給できたため、オペレーターはNUMAを「トポロジはソケットを反映する」ものとして学びました。このメンタルモデルは機能しました。 それは2010年代後半頃から真実ではなくなりました。AMDのZenベースのEPYCは、ソケットごとのコア数を十分に高く押し上げ、巨大なモノリシックダイの製造上のトレードオフを十分に魅力的にしないものにしたため、パッケージは小さなチップレットの集合体へと移行しました。つまり、1つのソケット内にいくつかのCore Complex Die(CCD)があり、それぞれが独自のL3キャッシュのスライスとメモリコントローラーのスライスを持ち、Infinity Fabricによって結合されています。問題は、Infinity Fabricがソケット間だけでなく、ソケット内部のCCD間でも使用されるようになったことです。これは同じファブリックであり、同じ仕事をより小さなスケールで行っています。そのため、単一のEPYCソケットは、部品とBIOS構成(現在の世代ではNPS1からNPS4までの「Nodes Per Socket」(NPS)ノブ)に応じて、複数のNUMAノードをOSに提示することができます。 Intelの同じアイデアのバージョンは、Sub-NUMA Clustering(SNC)です。デフォルトではオフですが、最近のXeon部品のBIOSで利用可能であり、SNCはオンダイのメモリコントローラーのメッシュをパーティション化し、その結果をソケットごとの複数のNUMAノードとして提示します。 「1ソケット、1ノード」は便利な第一近似でしたが、数年前からコモディティハードウェアでは正確ではなくなりました。2つ以上のソケットを持つx86サーバーは、特殊なニッチを除いて珍しくなりました。現代のシステムにおける興味深いNUMAの複雑さは、単一のデュアルソケットボックスの内部から来ており、4〜8ノードが今や日常的です。 「遅い」とはどのくらいか? 正確な数値はプラットフォーム固有であり、人々は正確な方法論について議論しますが、現代のサーバーではリモートDRAMアクセスがローカルアクセスの約1.5倍から3倍のコストがかかるというのが有用な経験則です。帯域幅も低く、同様の比率になることもあります。これらの数値は、アイドル状態のマシンでマイクロベンチマークを実行して測定するものです。 ノード0 CPU 0 CPU 1 メモリコントローラー ノード0メモリ ノード1 CPU 2 CPU 3 メモリコントローラー ノード1メモリ インターコネクト ローカル リモート 実際のワークロードでは、インターコネクトが共有されているため、ギャップは通常さらに悪化します。多くのコアが一度にノード間のアクセスを実行すると、同じインターコネクト帯域幅を競合するため、リクエストあたりのレイテンシが増加します。これは、多くの「なぜこのサーバーは高負荷時に遅いのか」という謎の背後にあるメカニズムです。マイクロベンチマークではノード間は2倍悪いと示されますが、本番ワークロードでは、誰もが同じパイプを奪い合うため、4倍または5倍悪いと認識されます。 その結果として言及すべきは、NUMA効果は影響を受けるワークロードを遅くするだけでなく、そのパフォーマンスを予測不能にするということです。同じリクエストが、その瞬間にインターコネクト上に何があるかによって、80ナノ秒かかることもあれば、250ナノ秒かかることもあります。平均レイテンシは有用な数値ですが、テールレイテンシこそNUMAの痛みが最初に現れる場所です。 インターリービング: ピークを犠牲にしてフロアを上げる メモリがどこに存在すべきかを理解するための作業を何もせずにコストカーブを平坦化する、よく知られた方法があります。それはメモリインターリービングです。要求元のタスクがどのノードにあるかに関係なく、すべてのノードにページをラウンドロビンで割り当てます。Linuxではnumactl --interleave=allがこれにあたり、一部のデータベースやJVMは独自のアロケーターで同等のことを行い、いくつかのハイパーバイザーはゲストメモリに対して暗黙的にそれを行います。