本文說明設定模式和最佳做法,協助您在 Compute Engine 執行個體上,使用兩個主機區域網路介面 (NIC) 進行儲存和管理。
總覽
部分加速器最佳化機器系列 (包括 A5X、A4X Max、A4X、A4 和 A3 Ultra) 具有兩個主機 LAN 網路介面,用於儲存和管理,可連結至一般虛擬私有雲 (VPC) 網路。這些機器也有 MRDMA 網路介面,必須連結至基於融合乙太網路的遠端直接記憶體存取 (RoCE) 虛擬私有雲網路。
本文著重於在一般虛擬私有雲網路 (而非 RDMA 網路介面) 設定主機區域網路介面 (gVNIC 或 IDPF)。主機 LAN 介面是 Titanium 基礎架構處理單元 (IPU),可連線至獨立的 CPU 插槽和非統一記憶體存取 (NUMA) 節點。在運算執行個體中,這些 IPU 會顯示為 Google 虛擬 NIC (gVNIC) 或基礎架構資料路徑函式 (IDPF) 網路介面。這些介面提供網路頻寬,用於儲存和管理活動,例如檢查點、載入訓練資料和載入模型。訪客作業系統 (OS) 可查看機器的 NUMA 拓撲,包括網路介面的拓撲。
無論您為多個主機 NIC 選擇哪種模式,請使用下列設定:
- 網路設定:
設定每個 gVNIC 或 IDPF 介面,使用獨立的虛擬私有雲網路。請完成下列虛擬私有雲設定:
- 為每個虛擬私有雲網路設定較大的最大傳輸單位 (MTU),例如
8896(支援的最大 MTU)。 - 如果接收端捨棄傳入的資料封包,導致工作負載的輸入效能降低,請使用
ethtool公用程式檢查是否有捨棄的封包。如要最佳化頁面快取的資料分配,讓每個傳入的第 2 層框架都能容納在兩個 4 KB 緩衝區中,請調整 TCP 最大區段大小 (MSS)、介面 MTU 或虛擬私有雲 MTU。
- 為每個虛擬私有雲網路設定較大的最大傳輸單位 (MTU),例如
- 應用程式設定:
- 使用 CPU 核心、記憶體配置和來自相同 NUMA 節點的網路介面,對應用程式進行 NUMA 對齊。如果您為特定 NUMA 節點或網路介面執行應用程式的專屬執行個體,請使用
numactl等工具,將應用程式的 CPU 和記憶體資源繫結至該 NUMA 節點。
- 使用 CPU 核心、記憶體配置和來自相同 NUMA 節點的網路介面,對應用程式進行 NUMA 對齊。如果您為特定 NUMA 節點或網路介面執行應用程式的專屬執行個體,請使用
- 作業系統設定:
- 啟用 TCP 區隔卸載 (TSO) 和大型接收卸載 (LRO)。
- 針對每個 gVNIC 或 IDPF 介面,設定對稱多處理 (SMP) 親和性,將中斷要求 (IRQ) 轉送至與介面相同的 NUMA 節點,並將中斷分散至各個 CPU 核心。如果您使用 Google 提供的 Linux 映像檔,Compute Engine 訪客代理程式會在啟動時執行
google_set_multiqueue指令碼,自動套用這項設定。如果使用自訂映像檔,請安裝客體環境。如果指令碼未自動執行,請執行sudo /usr/bin/google_set_multiqueue指令。 - 評估接收流程導向 (RFS)、接收封包導向 (RPS) 和傳輸封包導向 (XPS) 設定,判斷是否對工作負載有益。
- 如果是 A4X Max 和 A4X 執行個體,NVIDIA 建議停用自動 NUMA 排程。
- 請勿在這些機器上使用 Linux 核心繫結與 gVNIC 或 IDPF 介面,因為系統不支援核心繫結。
使用多個主機 NIC 的模式
下表概述在Cloud de Confiance by S3NS上使用多個主機 NIC 的一般模式:
| 模式 | 支援的程序版面配置 | 部署路徑:Compute Engine | 部署路徑:Google Kubernetes Engine | 部署路徑:Slurm | 附註 |
|---|---|---|---|---|---|
| 變更應用程式以使用特定介面 | 每個介面的處理 shard | 是 | 是 | 是 | 需要變更應用程式的程式碼。 |
| 變更應用程式以使用這兩種介面 | 雙介面程序 | 是 | 是 | 是 | 需要變更應用程式的程式碼。 |
| 為特定應用程式使用專屬網路命名空間 | 每個介面的處理 shard | 是 | 是 (僅限特殊權限容器) | 否 | 無 |
| 將整個容器的流量對應至單一介面 | 所有容器流量都對應至一個介面 | 是 | 是 | 否 | 無 |
| 使用虛擬私有雲對等互連,讓系統在介面之間平衡工作階段負載 | 雙介面程序 | 是 | 是 | 是 | 難以或無法進行 NUMA 調整。需要 Linux 核心 6.16 以上版本。 |
| 將流量分散至多個網路 |
|
是 | 是 | 是 | 如果您執行雙介面程序,可能需要變更程式碼,以配合 NUMA。 |
| 使用來源網路位址轉譯 (SNAT) 選擇來源介面 |
|
是 | 是 (設定需要管理員權限) | 是 (設定需要管理員權限) | 設定可能相當困難。 |
附註
將應用程式變更為使用特定介面
必要操作:
- 需要變更應用程式的程式碼。
- 需要下列一或多個方法的權限:
bind():只有在使用特殊權限來源通訊埠時,才需要特殊權限。SO_BINDTODEVICE:需要CAP_NET_RAW權限。
- 可能需要修改核心路由表,才能建立路由並防止非對稱路由。
高階總覽
如要設定應用程式使用特定網路介面,請完成下列步驟:
- 使用下列任一選項,將網路介面的繫結新增至應用程式的原始碼:
- 使用
bind()系統呼叫,將通訊端繫結至特定來源 IP 位址。 - 使用
SO_BINDTODEVICE通訊端選項,將通訊端繫結至特定網路介面。
- 使用
- 視需要修改核心路由表,確保從來源網路介面到目的地地址有路由。如要避免非對稱轉送,請按照「設定其他網路介面的轉送」一文所述,設定政策轉送。
- 選用:使用
numactl指令,在與所選網路介面共用相同 NUMA 節點的記憶體和 CPU 上執行應用程式。
完成上述步驟後,應用程式就會使用指定的網路介面。
變更應用程式以使用兩個介面
必要操作:
- 需要變更應用程式的程式碼。
- 需要下列一或多個方法的權限:
bind():只有在使用特殊權限來源通訊埠時,才需要特殊權限。SO_BINDTODEVICE:需要CAP_NET_RAW權限。
- 可能需要修改核心路由表,才能建立路由並防止非對稱路由。
高階總覽
如要將應用程式設為使用這兩個網路介面,請完成下列步驟:
- 使用下列任一選項,在應用程式的原始碼中為每個網路介面新增繫結:
- 使用
bind()系統呼叫,將每個通訊端繫結至對應網路介面的來源 IP 位址。 - 使用
SO_BINDTODEVICE通訊端選項,將每個通訊端繫結至特定網路介面。
- 使用
- 如果應用程式做為用戶端,請為每個來源網路介面建立個別的用戶端通訊端。
- 視需要修改核心路由表,確保每個來源網路介面都有通往目的地位置的路徑。如要避免非對稱轉送,請按照「設定其他網路介面的轉送」一文所述,設定政策轉送。
- 將網路活動分區為執行緒,並在與對應 gVNIC 或 IDPF 介面相同的 NUMA 節點上執行,例如呼叫
pthread_setaffinity_np。由於應用程式會使用多個 NUMA 節點的資源,請避免使用numactl,或確保numactl指令包含應用程式使用的所有網路介面 NUMA 節點。
為特定應用程式使用專屬網路命名空間
必要操作:
- 需要
CAP_SYS_ADMIN功能。 - 與 GKE Autopilot 不相容。
- 如果您使用的是 GKE,則必須使用具特殊權限的容器。
本節說明可用來為次要網路介面建立網路命名空間的模式。最適合工作負載的模式取決於您的情境。如果多個應用程式需要從不同的網路命名空間共用次要介面,最適合使用虛擬交換器或 IPvlan 的方法。
將次要介面移至專屬網路命名空間
採用這個模式時,您會建立網路命名空間,將次要 gVNIC 或 IDPF 介面移至新的命名空間,然後從該命名空間執行應用程式。與虛擬交換器相比,這種模式更容易設定和調整,但新網路命名空間以外的應用程式無法存取次要網路介面。
如要將 eth1 介面移至名為 app-net 的網路命名空間,並在該命名空間中執行指令,請執行下列指令:
ip netns add app-net ip link set eth1 netns app-net ip netns exec app-net ip addr add ETH1_IP/PREFIX dev eth1 ip netns exec app-net ip link set dev eth1 up ip netns exec app-net ip route add default via GATEWAY_IP dev eth1 ip netns exec app-net COMMAND
更改下列內容:
ETH1_IP:eth1介面的內部 IP 位址。PREFIX:eth1介面的子網路前置碼長度。GATEWAY_IP:eth1子網路的預設閘道 IP 位址。COMMAND:在app-net網路命名空間中執行的指令。
執行這些指令時,COMMAND 會在 app-net 網路命名空間內執行,並使用 eth1 介面。
在新網路命名空間中執行的應用程式,會使用次要 gVNIC 或 IDPF 介面。您也可以使用 numactl 指令,透過與所選網路介面位於相同 NUMA 節點的記憶體和 CPU 執行應用程式。
使用虛擬交換器和網路命名空間做為次要介面
使用這個模式時,您需要設定虛擬交換器,以便從網路命名空間存取次要 gVNIC 或 IDPF 介面:
- 開啟與運算執行個體的 SSH 連線。詳情請參閱「連線至 Linux VM」。
- 使用
ip link add指令建立虛擬乙太網路 (veth) 裝置配對,例如ip link add veth0 type veth peer name veth1。 使用
ip link set指令調整每部裝置的 MTU,使其與次要介面的 MTU 相符:ip link set dev veth0 mtu MTU ip link set dev veth1 mtu MTU
將
MTU替換為次要介面的 MTU,例如8896。啟用 IPv4 封包轉送:
sysctl -w net.ipv4.ip_forward=1
將
veth配對的一端移至新的網路命名空間,另一端則留在根命名空間。將
veth裝置的流量對應至次要介面。如要設定這項對應,請為運算執行個體的次要介面建立別名 IP 範圍,並將這個範圍內的 IP 位址指派給命名空間中的子介面。從新的網路命名空間執行應用程式。您可以使用
numactl指令,透過與所選網路介面位於相同 NUMA 節點的記憶體和 CPU 執行應用程式。
或者,視客體 OS 和工作負載設定而定,您可以將 IPvlan 介面連結至次要 gVNIC 或 IDPF 介面,而不建立 veth 裝置。
將整個容器的流量對應至單一介面
必要操作:
- 應用程式必須在容器內執行,且該容器使用網路命名空間進行容器網路,例如 GKE、Docker 或 Podman。無法使用主機網路。
GKE、Docker 和 Podman 等容器執行階段會為每個容器使用專屬的網路命名空間,藉此隔離流量。您可以直接或使用容器執行階段的工具修改這個網路命名空間,將流量對應至不同的網路介面。
GKE 需要主要介面,才能進行內部 Kubernetes 通訊。不過,您可以變更 Pod 中的預設路徑,改用次要介面,如以下 GKE Pod 資訊清單所示:
metadata:
# ...
annotations:
networking.gke.io/default-interface: 'eth1'
networking.gke.io/interfaces: |
[
{"interfaceName":"eth0","network":"default"},
{"interfaceName":"eth1","network":"secondary-network"}
]
這種方法無法保證預設網路介面與指派的 CPU 或記憶體之間的 NUMA 對齊。
使用虛擬私有雲對接,讓系統在介面之間平衡工作階段負載
必要操作:
- 您必須在主要和次要主機 NIC 的虛擬私有雲網路之間,建立虛擬私有雲網路對接。
- 將流量傳送至單一目的地 IP 位址和通訊埠時,您必須使用 Linux 核心版本 6.16 以上版本,才能在來源介面之間平衡 TCP 工作階段的負載。
- 工作負載必須能容忍跨通訊端記憶體傳輸,且不會錯過成效目標。
高階總覽
如果您無法在應用程式內或跨應用程式執行個體輕鬆 shard 網路連線,且工作負載在 A4 或 A3 Ultra 運算執行個體上執行,且對跨 NUMA 或跨通訊端傳輸不敏感,則可將這兩個介面視為可替換。
如要設定這項行為,請啟用 fib_multipath_hash_policy sysctl 參數,並新增多路徑路由:
PRIMARY_GW=192.168.1.1 # Gateway of nic0
SECONDARY_GW=192.168.2.1 # Gateway of nic1
PRIMARY_IP=192.168.1.15 # Internal IP address for nic0
SECONDARY_IP=192.168.2.27 # Internal IP address for nic1
# Enable L4 5-tuple equal-cost multipath (ECMP) hashing
sysctl -w net.ipv4.fib_multipath_hash_policy=1
ip route add DESTINATION_NETWORK/SUBNET_MASK \
nexthop via ${PRIMARY_GW} \
nexthop via ${SECONDARY_GW}
更改下列內容:
DESTINATION_NETWORK:目的地內部 IP 位址範圍。SUBNET_MASK:目的地網路的子網路前置碼長度。
在網路之間分配流量
必要操作:
- 運算執行個體上的
nic0和nic1必須連線至不同的虛擬私有雲網路和子網路,且目的地 IP 位址必須在兩個虛擬私有雲網路之間進行 shard。
高階總覽
根據預設,Linux 核心會為 nic0 子網路和 nic1 子網路建立路由,依據目的地 IP 位址,透過對應的網路介面轉送流量。
舉例來說,假設 nic0 使用虛擬私有雲網路 net1 和子網路 subnet-a,而 nic1 使用虛擬私有雲網路 net2 和子網路 subnet-b。根據預設,傳送至 subnet-a 中對等互連 IP 位址的流量會使用 nic0,而傳送至 subnet-b 中對等互連 IP 位址的流量則會使用 nic1。如果一組對等互連單一 NIC 運算執行個體連線至 net1,而第二組連線至 net2,通常會套用這項設定。
使用 SNAT 選擇來源介面
必要操作:
- 需要
CAP_NET_ADMIN功能才能設定初始iptables規則,但不需要執行應用程式。 - 與其他非一般
iptables規則或轉送設定搭配使用時,必須謹慎評估。
高階總覽
如果您無法使用網路命名空間或修改應用程式,則可使用 SNAT 選取來源介面。使用 iptables 等工具,您可以根據傳送應用程式的屬性 (例如 cgroup、使用者或 CPU),重寫流量的來源 IP 位址,以符合特定介面的 IP 位址。
下列範例使用 CPU 規則,因此來自特定 CPU 執行緒的任何流量,都會透過連結至該 CPU NUMA 節點的 gVNIC 或 IDPF 介面輸出:
# --- Begin Configuration ---
OUTPUT_INTERFACE_0="enp0s19" # CHANGEME: NIC0
OUTPUT_INTERFACE_1="enp192s20" # CHANGEME: NIC1
CPUS_0=($(seq 0 55; seq 112 167)) # CHANGEME: CPU IDs for NIC0
GATEWAY_0="10.0.0.1" # CHANGEME: Gateway for NIC0
SNAT_IP_0="10.0.0.2" # CHANGEME: SNAT IP for NIC0
CONNMARK_0="0x1"
RT_TABLE_0="100"
CPUS_1=($(seq 56 111; seq 168 223)) # CHANGEME: CPU IDs for NIC1
GATEWAY_1="10.0.1.1" # CHANGEME: Gateway for NIC1
SNAT_IP_1="10.0.1.2" # CHANGEME: SNAT IP for NIC1
CONNMARK_1="0x2"
RT_TABLE_1="101"
# --- End Configuration ---
# Specify which interface to use for packets in each routing table.
ip route add default via "$GATEWAY_0" dev "$OUTPUT_INTERFACE_0" table "$RT_TABLE_0"
ip route add default via "$GATEWAY_1" dev "$OUTPUT_INTERFACE_1" table "$RT_TABLE_1"
# Route replies to connections from peers through the matching egress interface.
# Add these rules before the fwmark rules so that fwmark takes precedence.
ip rule add from "$SNAT_IP_0" table "$RT_TABLE_0"
ip rule add from "$SNAT_IP_1" table "$RT_TABLE_1"
# Select the routing table based on the packet mark set in OUTPUT.
ip rule add fwmark "$CONNMARK_0" table "$RT_TABLE_0"
ip rule add fwmark "$CONNMARK_1" table "$RT_TABLE_1"
# Relax reverse path filtering so that the kernel doesn't drop legitimate
# replies to the SNAT IP addresses.
sysctl -w net.ipv4.conf."$OUTPUT_INTERFACE_0".rp_filter=2
sysctl -w net.ipv4.conf."$OUTPUT_INTERFACE_1".rp_filter=2
# Mark packets and connections with a per-NIC mark based on the source CPU.
# The fwmark rules then select the corresponding routing table for this traffic.
for cpu_id in "${CPUS_0[@]}"; do
iptables -t mangle -A OUTPUT -m state --state NEW -m cpu --cpu "$cpu_id" -j CONNMARK --set-mark "$CONNMARK_0"
iptables -t mangle -A OUTPUT -m state --state NEW -m cpu --cpu "$cpu_id" -j MARK --set-mark "$CONNMARK_0"
done
for cpu_id in "${CPUS_1[@]}"; do
iptables -t mangle -A OUTPUT -m state --state NEW -m cpu --cpu "$cpu_id" -j CONNMARK --set-mark "$CONNMARK_1"
iptables -t mangle -A OUTPUT -m state --state NEW -m cpu --cpu "$cpu_id" -j MARK --set-mark "$CONNMARK_1"
done
# Restore the connection mark for established connections so that packets use
# the same NIC regardless of other routing rules.
iptables -t mangle -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark
# Rewrite the source address after the packet is routed to the target interface
# so that replies return to the same NIC and pass VPC network validation.
iptables -t nat -A POSTROUTING -m mark --mark "$CONNMARK_0" -j SNAT --to-source "$SNAT_IP_0"
iptables -t nat -A POSTROUTING -m mark --mark "$CONNMARK_1" -j SNAT --to-source "$SNAT_IP_1"