はじめに
本記事は、計三回に渡ってお送りする、RoCEv2を用いた実機検証シリーズの第二回目の記事となります。
第一回目となる前回は、検証開始へ向けてポイントとなるいくつかの概念(RDMA、All-Reduce等)について、適宜画像を用いて解説してきました。
第二回目となる今回は、Ethernet上にロスレスネットワークを構築する上での前提となる、ネットワーク側(Cisco Nexus)の具体的な機能の話に入っていきます。
概要
RoCEv2の前提:ロスレスネットワーク
通常のTCP/IP通信では、パケットロスが発生した場合でも、OSのTCP/IPスタックによる再送制御によってリカバリされます。
一方、RDMA、特にRoCEでは、アプリケーションのデータ転送がOSカーネルをほとんど介さず、RDMA対応NICがメモリとネットワーク間の転送を主導します。
そのため、信頼性制御や再送処理も主にNIC側の仕組み(RDMAトランスポート)に依存します。
つまり、パケットロスが発生すると、NIC側で失われたデータの再送や順序制御を行う必要があり、その間は後続のデータ処理が待たされたり、送信レートが低下したりします。
結果として、RoCEでは小さなパケットロスであっても、通信全体のレイテンシーやスループットに大きく影響する可能性があります。
そのためRoCEv2では、「そもそもパケットロスを発生させない」という設計思想のもと、ネットワーク側でいくつかの制御を組み合わせてロスレス環境を実現します。
ロスレスを実現するための主な技術
ここからは、Ethernet上でロスレスネットワークを構築するために必要な、ネットワークスイッチ側の技術について書いていきます。
(1) パケットロスの防止(PFC)
まず、バッファが溢れることによるパケットドロップを防ぐために、PFC(Priority Flow Control)を利用します。
PFCは、特定の優先度のトラフィックに対して転送の一時停止を指示する仕組みです。
具体的には、スイッチが輻輳を検知すると、送信元に対してPause Frameと呼ばれる専用のフレームを送信することで、トラフィックの送信を一時的に停止させます。これにより、パケットロスを未然に防ぎます。
RDMAトラフィックに設定された優先度に対してPFCを適用することにより、ロスレスなRDMA通信を実現するためのベースが出来上がります。
(2) 輻輳制御(ECN + DCQCN)
一方で、PFCが発動している間は、そのスイッチからフレームの送信が止まる訳ですから、当然スイッチ内部のバッファには、一つ手前のスイッチから届いたフレームが次第に貯まっていきます。
これが続き、一時停止の影響がその他の機器にも伝播していくと、最終的にはネットワーク全体でトラフィック転送が停止してしまうリスク(Head-of-Line Blockingと呼ばれます)も考えられるため、PFCが発動する手前の段階で、輻輳そのものを緩和する仕組みも必要です。
ここで使われるのがECN(Explicit Congestion Notification) です。
ECNは、スイッチが輻輳を検知した際にパケットをドロップするのではなく、「輻輳が発生している」という情報(CEビット)をパケットにマーキングします。
CE付きパケットを受け取った受信側のサーバは、この情報をもとに送信元のサーバに対して通知(CNP: Congestion Notification Packet)を送信し、RDMAトラフィックの送信レートを低下させます。
RoCEv2では、この一連の制御をDCQCN(Data Center Quantized Congestion Notification)というアルゴリズムで実現し、エンドツーエンドで輻輳をコントロールします。
(※DCQCNの具体的な動作の流れについては後述。)
(3) 輻輳制御の前提:トラフィック識別(DSCP / CoS)
上記の(1),(2)が想定通り動作するためには、RDMAトラフィックをネットワーク内で正しく識別できていることがそもそもの前提となります。
RoCEv2では、IPヘッダのDSCP(Differentiated Services Code Point)や、EthernetのCoS(Class of Service)を利用してトラフィックを分類します。
これにより、スイッチはRDMAトラフィックを特定のキューや優先度にマッピングし、PFCやECNといった制御を適切に処理することが可能になります。
DCQCN 動作の流れ
DCQCNが動作する様子を、図も使いながら時系列で書いてみます。
今回は、Server-1からServer-2に向けてRoCEv2のRDMAトラフィックが送信される例で考えることにします。
(1)
まず、Server-1のRDMA対応NICがRDMAトラフィックを生成し、DSCP 26が付与された状態でLeaf-1へ送信します。このDSCP 26は、ネットワーク上でRoCEv2トラフィックとして識別するためのマーキングです。
Leaf-1で受信されたRDMAトラフィックは、Spineを経由してLeaf-2へ転送されます。Leaf-2では、Server-2向けの出力キューにRDMAトラフィックが蓄積されます。
もしこの出力キューが混雑し、ECNのマーキング閾値に達すると、Leaf-2は該当するパケットを破棄するのではなく、IPヘッダのECNフィールドにCE(Congestion Experienced)をマーキングします。
つまり、Leaf-2は「この経路は混雑し始めている」という情報を、Server-2へ向かうパケット自体に書き込んで転送するという動作になります。
(2)
CEマーキングされたパケットを受信したServer-2側のNICは、その情報をもとに、ネットワーク上で輻輳が発生していることを認識します。そして、そのパケットの送信元であるServer-1に対してCNP(Congestion Notification Packet)を送信します。
CNPは、受信側から送信側へ返される輻輳通知です。Server-1のNICはこのCNPを受信すると、「自分の送信によってネットワークが混雑している」と判断し、RDMAトラフィックの送信レートを下げます。
このように、ECNはスイッチがサーバに対して「混雑を知らせる」ための仕組みであり、CNPは、その通知を受けた受信側NICが、送信側NICへ「送信ペースを落としてほしい」と伝えるための仕組みであると言えます。
PFC 動作の流れ
ECNによってServer-1側の送信レートが調整されても、輻輳状況によっては、Leaf-2の出力キューの状況がすぐには改善されない場合があります。このまま放置しておくと、最終的にはバッファが溢れてLeaf-2がトラフィックをドロップしてしまう可能性がある訳ですが、それを防ぐための最終手段的な役割として使用されるのがPFCとなります。
(1)
先程と同様の通信シナリオにて、Leaf-2側のPriority 3に対応する出力キューがさらに増加していき、PFC発動の閾値に達した場合を想定します。
(2)
すると、Leaf-2は隣接装置であるSpine-1(Spine-2)に対してPause Frameを送信します。
ここで重要なのは、PFCはエンドツーエンドの制御ではなく、隣接装置間のリンク単位で動作するフロー制御であるという点です。
つまりLeaf-2は、Server-1に直接Pauseを送るのではなく、まず自分にRDMAトラフィックを送り込んでいる直前の装置、今回であればSpine-1(Spine-2)に対して、「Priority 3のトラフィックを一時的に送ってこないでほしい」と通知します。
(3)
Spine-1(Spine-2)はLeaf-2からPause Frameを受信すると、Leaf-2向けの該当ポートにおいて、Priority 3のトラフィックの送信を一時停止します。
※このとき停止されるのは、基本的にPriority 3に分類されたRoCEv2/RDMAトラフィックであり、すべての通信が止まるわけではありません。PFCはPriority単位でPauseできるため、他のPriorityの通信は継続できます。
このように、PFCはバッファが溢れる直前に隣接装置を一時停止させる、リンク単位の緊急ブレーキとして動作します。
RoCEv2のロスレスネットワークでは、まずECN/CNPによって送信レートを調整し、それでもキューが急激に増加した場合にPFCでパケットロスを防ぐ、という役割分担で理解すると分かりやすいかと思います。
設定例
本検証においてServer(Ubuntu)およびNexusに対して適用したConfig例(一部抜粋)を記載しておきます。
・Server (Ubuntu)用 Config例
# RDMAトラフィックに対しDSCP/CoS値を設定
mlnx_qos -i <iface> --dscp2prio='set,26,3’
# Cos=3のトラフィックに対しPFCを有効化
mlnx_qos -i <iface> --pfc 0,0,0,1,0,0,0,0
# CNPトラフィック用のDSCP/CoS値を設定
base=/sys/kernel/debug/mlx5/${pci}/cc_params
echo 48 > ${base}/np_cnp_dscp
echo 6 > ${base}/np_cnp_prio
・スイッチ (Nexus) 用Config例
<トラフィックの分類>
# RDMAトラフィック分類用のクラスマップを作成
class-map type qos match-any qos-rdma
match cos 3
match dscp 26
# CNPトラフィック分類用のクラスマップを作成
class-map type qos match-all qos-cnp
match dscp 48
<マーキング>
policy-map type qos rdma-qos-policy
# RDMAトラフィック用QoSグループの設定
class qos-rdma
set qos-group 3
set dscp 26
# CNPトラフィック用QoSグループの設定
class qos-cnp
set qos-group 7
class class-default
set qos-group 0
<キューイング>
policy-map type queuing ecn-queuing-out
# CNPトラフィック (qos-group 7) は最優先で処理
class type queuing c-out-8q-q7
priority level 1
# RDMAトラフィック (qos-group 3) に対してはECNを設定
class type queuing c-out-8q-q3
bandwidth remaining percent 50
random-detect threshold burst-optimized ecn
※その他トラフィックはベストエフォートで処理
class type queuing c-out-8q-q-default
bandwidth remaining percent 30
<バッファ閾値超過時にPAUSE Frameを送信>
# PFCの設定をUplink/downlinkのインターフェースに適用
interface Ethernet1/1
priority-flow-control mode on
interface Ethernet1/2
priority-flow-control mode on
interface Ethernet1/3
priority-flow-control mode on
interface Ethernet1/4
priority-flow-control mode on
・
・
・
ロードバランスの設定
ロードバランス手法の種類
これまで、Ethernet上でパケットロスを防ぐための仕組みとして、QoS(PFC / ECN + DCQCN)について解説してきました。
加えてRoCEv2環境では、トラフィックを複数経路へどのように分散させるかも重要になります。
ここでは代表的なロードバランス手法の仕組みを簡単に整理します。
(1) Flowlet Load DLB (Dynamic Load Balancing)
Flowletは、1つのフローを「時間的に分割された単位(Flowlet)」として扱う方式です。
パケットの送信に一時的な間隔(ギャップ)が発生したタイミングを境に、後続のトラフィックを別経路へ振り分けます。
これにより、1つのフロー内でも複数経路への分散が可能になります。
(2) Per Packet DLB
Per Packetは、パケット単位で経路を決定する方式です。
同一フローに属するパケットであっても、それぞれ独立して経路選択が行われ、異なる経路に送信されます。
つまり、フローという単位ではなく、「パケット単位」でトラフィックが分散されます。
(3) Static Pinning
Static Pinningは、特定の通信をあらかじめ決められた経路に固定する方式です。
例えば、
- 特定の送信元・宛先ペア
- 特定のフロー
に対して、使用する経路を静的に割り当てます。
この方式では、通信開始時に決まった経路がそのまま維持されます。
※ (0) 5-tuple ECMP
ECMP(Equal-Cost Multi-Path)は、そもそも複数の等コスト経路に対してトラフィックを分散する仕組みですが、一般的には(上述の各ロードバランス手法を明示的に設定しない場合)、以下の5つの情報(5-tuple)をもとにハッシュを計算し、使用する経路を決定します。
- 送信元IPアドレス
- 宛先IPアドレス
- 送信元ポート番号
- 宛先ポート番号
- プロトコル
この場合、同一の5-tupleを持つパケットは常に同じ経路を通過します。
まとめ
本記事では、RoCEv2によるロスレスネットワークを構築するために核となるネットワーク技術について解説してきました。
特に、ネットワークスイッチにおけるQoSとロードバランスの観点に重点を置いて解説しましたが、これらの仕組みが動作する際の時系列イメージとしては以下のような感じでしょうか。
RoCEv2実機検証シリーズの最終回となる次の記事では、いよいよ実際の検証パートについて扱っていきます。
本記事で解説してきた各種QoS設定やロードバランス手法の違いが、RoCEv2環境におけるRDMAトラフィックに対してどのような影響を与え得るのかを、実際にトラフィックを流しながら見ていきたいと思います。







