← 一覧へ戻る

Claude が書いた記事

RDMA ── CPU 処理なしで通信させる (zero copy と kernel bypass)

「そもそも RDMA ってなんやねん? 普通の通信や DMA と何が違う?」から始め、『普通の通信かてデータは最後メモリに入るやろ、なら何が違うんや』で詰まった所までほどく。両方ともデータは最後にメモリへ着く ── 違うのは『途中のコピー』と『CPU が指揮するか』だけ、と立て直した学習ログ。

俺の最初の疑問

そもそも RDMA ってなんやねん? 普通の通信や DMA と何が違うんや?

説明してもらう中で詰まったのはここ ── 普通の通信と並べられても、何が違うのかピンと来んかった。

この記事は、その「RDMA は普通の通信・DMA と何が違うか」を順に潰した記録や。

まず一言でいうと

RDMA (Remote Direct Memory Access) = あるマシンから別のマシンのメモリへ、NIC が直接データを書き込む (読み出す) 仕組み。 データのコピーとプロトコル処理を OS カーネルにやらせず、CPU は転送を指示するだけで運搬には出てこない。

これにより、速くなり、CPU を食わず、スループットが出る。GPU を何千枚も並べる AI 学習クラスタは、CPU を一々経由してたら通信で詰まる。だから RDMA が効く。

NIC オフロードと混同しやすいから差分を提示しておく。

NIC オフロードRDMA
オフロード対象個別の低レベル処理 (TSO・LRO・チェックサム・RSS・割り込み統合…)通信の CPU・カーネル処理ごと (TCP / IP スタック + コピー)
CPU に残る仕事ACK・再送制御・ルーティング等送受信の開始・完了待ちだけ
データのコピー残る0 (zero copy)
TCP / IP スタックそのまま通る (中で加速)丸ごとバイパス
レイテンシ数十〜数百 µs数 µs 以下
スループット〜10 Gbps 級 (CPU が頭打ち)数十〜200 Gbps 級
リンク層 (L2)普通の Ethernet (一般網で可)InfiniBand か Ethernet (RoCE)・閉じた DC 網が前提

何と比べるとわかるか

「いわゆる普通の TCP / IP 通信と何が違うんや」── これが一番のモヤやった。両者をメモリ込みで並べると、違いははっきりする。

普通の通信 (TCP / IP) も RDMA も、ゴールは同じ=アプリのメモリにデータが入る。違うのは「そこに着くまで何回コピーして、誰が指揮するか」だけ。受信側を、メモリ込みで正確に並べるとこうなる。

TCP/IP の受信:
NIC → [カーネルのメモリ] → (CPU がコピー) → [アプリのメモリ]
↑コピー①            ↑CPU が毎回働く   ↑やっと到着


RDMA の受信:
NIC → [アプリのメモリ]
↑ NIC が最初からアプリのメモリへ直書き (途中を経由しない)
TCP / IPRDMA
最後にメモリへ着くか着く着く
途中のコピー回数複数回 (カーネル → アプリ)0 回 = zero copy
CPU が毎回働くか働く (指揮役)働かない = kernel bypass

つまり「メモリに直接書く」の直接は、カーネルのメモリという中継地を経由せず、CPU の手も借りず、いきなり目的地のメモリへ置くという意味。両方メモリに着くが、RDMA は寄り道と人手が不要。これが速くて軽い理由や。

ここで出てくる 2 つの「メモリ」は、物理的には同じ RAM の別区画や。カーネルのメモリ (OS が通信処理に使う中継バッファ) とアプリのメモリ (アプリ専用の最終目的地) は、持ち主が違う。アプリは保護されたカーネルの区画を直接は読めないので、普通の通信はカーネル区画からアプリ区画へのコピーが要る。RDMA はこのコピーを飛ばして、NIC からいきなりアプリのメモリへ置く。

何が問題なのか

普通の通信だと、データが届くたびに CPU が叩き起こされ、カーネルのメモリからアプリのメモリへ詰め替える。1 本 2 本なら誤差やが、AI 学習で GPU 数千枚が一斉に通信 (all-reduce 等) するとどうなるか。

  • CPU がデータ移動に張り付く ── 計算に回したい CPU が、運送業で潰れる。
  • コピーのたびにレイテンシが積む ── 集団通信は「一番遅い 1 本」に全体が引きずられる。
  • 帯域が頭打ち ── CPU の処理速度が天井になる。

「線を太くする・本数を増やす」では埋まらん。CPU を経由する構造そのものが天井やから、その構造を外しに行くのが RDMA や。

図で見る

どちらも最後はアプリのメモリに着く。普通 (TCP / IP) はカーネルのメモリを経由してコピー 2 回、CPU が毎回指揮する。RDMA は NIC がアプリのメモリへ直書き ── コピー 0 回、CPU は経路外。違いはこの 2 点だけ。

片側 RDMA と両側 RDMA

RDMA の操作には 2 つの型がある。NIC がどう書くかの詳細に入る前に、ここを分けておく。

  • 片側 (WRITE / READ) … 送信側が、事前に、宛先側の番地 + rkey を知り、そこへ直接 書く / 読む。宛先側の CPU は起こさんし、書かれた事すら検知しない。普通の通信を裏返した、一番尖った型。
  • 両側 (SEND / RECV) … メッセージを渡す型。送る側は SEND するだけ (相手の番地は知らんでいい)。受け手は先に「受け皿バッファをここに置いとくで」という RECV を積んでおく必要があり、届くと完了通知で軽く起きる。普通の通信に近い。
片側 (WRITE / READ)両側 (SEND / RECV)
相手の番地を知る必要あるなし
送信元 CPU指示書を出してドアベルを鳴らす同左 (同じ)
宛先 CPU何もしないRECV を出して完了通知を送る
性格普通の通信と別物 (リモートメモリアクセス)普通の通信に近い (メッセージパッシング)

「片側」「両側」は通信の向きを表してるんやない。送信元の CPU だけを使うのが片側 RDMA、送信元と宛先の両方の CPU を使うのが両側 RDMA、という意味や。

その片側 WRITE が一番効くのが、AI 学習の all-reduce や。リング状に「隣のランクのバッファへ自分のチャンクを直接書く」の繰り返しで、相手 GPU / CPU を起こさず回せる (完了の合図もフラグを書いて相手がポーリング)。数千ランクで毎回相手 CPU を起こしてたら詰むから、CPU ゼロにできる片側 WRITE が選ばれる。両側 (SEND / RECV) はこのデータ本線では基本使わへん (NCCL は片側 WRITE 主体。MPI ベースだと両側を使う実装もある)。

ここから先は、その片側 WRITE で「NIC がどうやってメモリに書くか」を見ていく。

NIC は脳 (OS) が無いのに、なぜメモリに書けるんや

次の疑問はこれやった ── NIC には OS の判断力が無い。なのにメモリにどうやって書くんや?

答えは拍子抜けするほど単純で、NIC は判断してない

片側 RDMA (WRITE) の全体像は、下の図の 8 ステップや。上半分が準備 (control plane・配管を通すだけ)、下半分が本番 (data plane・アプリデータが流れる)。図を見ながら順に追う。

片側 RDMA (WRITE) の全体。準備 (①②③) で配管を通す (登録と番地 + rkey 交換。データはまだ流れない)、本番 (④〜⑧) でアプリデータ (オレンジ) が A のメモリ → 線 → B のメモリへ。④ は制御の着火だけで、CPU はデータを運ばず、B の CPU は経路外。

準備(①〜③・control plane)

「下地」を作る段。データはまだ 1 バイトも流れない。

  • ① 両アプリ起動 ── 送信側 A も 宛先 B も、RDMA で通信すると決めて書かれた 1 つのプログラムの両端や。
  • ② メモリ登録 ── 各アプリが「このメモリを使う」と登録を呼ぶ。すると CPU (OS) が下の 3 つをやる。鍵は 2 種類出る (A は自分用の lkey、B は相手に渡す rkey)。
    1. ページを固定 (pin) ── そのメモリが OS のスワップで動かされないよう釘で打つ (動いたら NIC が迷子になる)。
    2. 変換表を作る ── 「仮想アドレス → 物理アドレス」の対応表を用意する。ただし表の本体はホスト RAM に置く (NIC のチップには載りきらん)。NIC はよく使う分だけ TLB のようにキャッシュし、無い番地は RAM から引きに行く。CPU の MMU と TLB と同じ仕掛け。
    3. 鍵を発行 ── その領域への許可証を作る。
  • ③ 番地 + rkey を送信側へ渡す ── 送信側 (A) は B のメモリの空きなんか知らん。空きを把握して割り当てるのは自分のメモリを持つ B。だから B が、ふつうの経路 (TCP ソケットや RDMA-CM) で「この番地から N バイト、鍵は rkey、使ってええ」と A に渡す。
rkey (remote key) ── B が自分のメモリを登録したとき発行する、その領域の許可証。B が準備で「ここに書いてええ」と A に手渡し、A の書き込みパケットに番地と一緒に載る。受信側 NIC が登録済みの鍵と照合し、合えば DMA、違えば蹴る。CPU を介さず書かせる代わりの、ハードだけで効く関所。

本番(④〜⑧・data plane)

下地ができたら、アプリデータが流れる。CPU が出てくるのは ④ の一瞬だけ。

  • ④ 指示書 + ドアベル (制御) ── A の CPU が「番地 X から M バイト転送せよ」という指示書 (descriptor) をキューに置いてドアベルを鳴らすだけ。データ本体は入ってない (ポインタだけ)。データ量に関係なく一定の極小コスト (1GB でも 1 枚)。キューはユーザー空間に見えてるのでカーネルを呼ばず直接書ける (kernel bypass)。
ドアベル (doorbell) ── 比喩やなく正式な用語。NIC の特別なレジスタへ 1 回書き込む (MMIO) ことを指す。指示書をキューに置いた後「キューを見ろ」と NIC に知らせる合図で、これが無いと NIC は気づかへん。
  • ⑤ アプリデータを DMA read ── 送信側 NIC が指示書を見て、ペイロードをホスト RAM から DMA で吸い上げる。PCIe デバイスは「バスマスタ」── CPU を介さず自分でバスを駆動して RAM を読める ── やからこれができる。
  • ⑥ パケットが線を渡る ── [番地 + rkey | アプリデータ] が送信 NIC から受信 NIC へ。番地と rkey は宛名 (殻)、その後ろにアプリデータが乗る。
  • ⑦ 照合・変換 ── 受信側 NIC が届いた rkey を照合 → 番地を物理に変換。合えば通す、違えば蹴る。
  • ⑧ アプリのメモリへ DMA write ── 受信側 NIC が B の CPU をオフロードして、アプリのメモリへ直書き。B の CPU は寝たまま (書かれた事すら知らん)。

NIC がやってるのは「鍵の照合」「番地の変換」「DMA」だけ。どれも判断やなく、配線された専用回路 (ステートマシン) が、指示書や登録情報のとおり機械的に動くだけ。スイッチ ASIC が脳なしでパケットを転送するのと同じや。だから脳が無くてもできる。

片側 RDMA と両側 RDMA の違いをもう少し

RDMA の操作には「片側 (One-Sided)」と「両側 (Two-Sided)」の 2 種類があります。違いは、転送のたびに受信側の CPU が関与するかどうかです。

片側 RDMA (One-Sided)

イニシエータ (送信側) だけが操作を開始し、ターゲット (受信側) は受動的です。送信側が受信側のメモリ番地と rkey を指定してデータを送信し、受信側 NIC が受信側メモリに DMA で書き込みます (または読み出します)。受信側の CPU は関与せず、書かれたことも知りません。

両側 RDMA (Two-Sided)

送信側と受信側の両方が操作を出します。送信側が SEND を出し、受信側はあらかじめ RECV (受け皿バッファ) を出しておきます。データが届くと、受信側に完了通知が入ります。普通のメッセージのやり取り (送る / 受け取る) に近く、受信側の CPU も関与します。

比較

項目片側 (WRITE / READ)両側 (SEND / RECV)
受信側 CPU の関与しない (書かれたことを知らない)する (完了通知で気づく)
受信側の事前準備不要RECV (受け皿) を先に出す
送信側が知る情報相手の番地 + rkey不要
モデルリモートメモリアクセスメッセージパッシング
代表 APIrdma_write / rdma_readrdma_send / rdma_recv

どちらを選ぶか

  • 片側:相手の CPU を完全にゼロにできます。AI の all-reduce のように、数千ノードで相手を一切起こしたくない場合に使います。代わりに、番地と rkey の事前交換が必要です。
  • 両側:受信側が完了通知で受信を知れるため、プログラムが書きやすくなります。番地の交換も不要です。ただし、受信側の CPU が毎回わずかに関与します。

出てきた言葉の変換表

出てきた言葉つまり何の話?
RDMARemote Direct Memory Access。相手の CPU・OS カーネルを介さず、相手側の NIC がそのマシンのメモリへ直接読み書きする仕組み
zero copy途中のカーネルメモリを経由せず、目的地のメモリへ直に置くこと。コピー回数 0
kernel bypassOS カーネルの通信処理 (TCP/IP スタック) を通らないこと。CPU が経路外になる
DMAデバイスが CPU を介さず RAM を直接読み書きする標準機能。RDMA の「直書き」の実体
メモリ登録 (Memory Registration)本番前に、使うメモリを pin し・変換表を NIC に渡し・rkey を発行する段取り。判断の前倒し
rkey (remote key)登録した領域への許可証。リモート書き込みで照合される鍵
lkey / rkey登録で出る 2 つの鍵。lkey は自分用 (自マシンの NIC が読む)、rkey は相手に渡す用 (リモート書き込みで照合)
片側 / 両側WRITE / READ (相手 CPU 不在) と SEND / RECV (受け手が受け皿を積み完了通知で起きる)
ドアベル (doorbell)NIC のレジスタへの 1 回の書き込み (MMIO)。「キューを見ろ」と NIC に知らせる合図。比喩でなく正式な用語
深掘りメニュー 次におすすめのトピック

RDMA の核 ── CPU を飛ばして NIC が直書きする仕組みは掴めた。次は「その RDMA を Ethernet で安定して走らせる所」と「GPU でどう効くか」。

  • RoCE の lossless 問題と PFC ── 次はこれが効く。 普通の Ethernet は混んだら落とす。落ちたら困る RDMA を乗せるには、スイッチで「待った」をかけて落とさせない仕組み (PFC) が要る。RoCE 運用のキモで、ここが分かると次の Ultra Ethernet が何を直すのか読める。
  • Ultra Ethernet ── RoCE の弱点を Ethernet 陣営が束で作り直す新規格。 「なぜ今 AI 向けに新しい Ethernet が要るのか」を、RoCE の不満点から逆算して読む段。
  • GPUDirect RDMA と集団通信 (all-reduce) ── RDMA の直書き先を GPU のメモリにすると何が起きるか。AI 学習で片側 WRITE がなぜ効くかの実地。