Pola penggunaan beberapa NIC host (VM GPU)


Beberapa mesin yang dioptimalkan untuk akselerator, termasuk A3 Ultra, A4, dan A4X, memiliki dua antarmuka jaringan host selain antarmuka MRDMA di mesin ini. Di host, ini adalah IPU Titanium yang dicolokkan ke soket CPU terpisah dan node akses memori non-seragam (NUMA). IPU ini tersedia di dalam VM sebagai NIC Virtual Google (gVNIC), dan menyediakan bandwidth jaringan untuk aktivitas penyimpanan seperti pembuatan titik pemeriksaan, memuat data pelatihan, memuat model, dan kebutuhan jaringan umum lainnya. Topologi NUMA komputer, termasuk gVNIC, terlihat oleh sistem operasi (OS) tamu.

Dokumen ini menjelaskan praktik terbaik untuk menggunakan dua gVNIC di mesin ini.

Ringkasan

Secara umum, sebaiknya gunakan konfigurasi berikut, terlepas dari cara Anda berencana menggunakan NIC multi-host:

  • Setelan jaringan: Setiap gVNIC harus memiliki jaringan VPC yang unik. Untuk penyiapan VPC, pertimbangkan hal berikut:
    • Gunakan unit transmisi maksimum (MTU) yang besar untuk setiap jaringan VPC. 8896 adalah MTU maksimum yang didukung dan pilihan yang direkomendasikan. Performa ingress untuk beberapa workload mungkin melambat karena sistem menghilangkan paket data masuk di sisi penerima. Anda dapat menggunakan alat ethtool untuk memeriksa masalah ini. Dalam skenario ini, Anda dapat menyesuaikan MSS TCP, MTU antarmuka, atau MTU VPC untuk memungkinkan alokasi data yang efisien dari cache halaman, yang memungkinkan frame layer 2 masuk agar sesuai dengan dua buffer 4 KB.
  • Setelan aplikasi
    • Menyelaraskan aplikasi dengan NUMA. Gunakan inti CPU, alokasi memori, dan antarmuka jaringan dari node NUMA yang sama. Jika Anda menjalankan instance khusus aplikasi untuk menggunakan node NUMA atau antarmuka jaringan tertentu, Anda dapat menggunakan alat seperti numactl untuk melampirkan resource CPU dan memori aplikasi ke node NUMA tertentu.
  • Setelan sistem operasi
    • Aktifkan pengurangan beban segmentasi TCP (TSO) dan pengurangan beban penerimaan besar (LRO).
    • Untuk setiap antarmuka gVNIC, pastikan afinitas SMP disiapkan sehingga permintaan interupsinya (IRQ) ditangani di node NUMA yang sama dengan antarmuka, dan sebarkan interupsi di seluruh core. Jika Anda menjalankan image OS tamu yang disediakan Google, proses ini akan terjadi secara otomatis menggunakan skrip google_set_multiqueue.
    • Evaluasi setelan seperti RFS, RPS, dan XPS untuk melihat apakah setelan tersebut dapat membantu workload Anda.
    • Untuk A4X, Nvidia merekomendasikan menonaktifkan penjadwalan NUMA otomatis.
    • Penggabungan kernel Linux tidak didukung untuk gVNIC di mesin ini.

Pola penggunaan beberapa NIC host

Bagian ini menguraikan pola umum untuk menggunakan beberapa NIC host di Google Cloud.

Jalur deployment yang didukung
Pola Tata letak proses yang didukung GCE (umum) GKE SLURM Catatan
Mengubah aplikasi untuk menggunakan antarmuka tertentu Shard proses per antarmuka Memerlukan perubahan kode pada aplikasi
Mengubah aplikasi untuk menggunakan kedua antarmuka Proses antarmuka ganda Memerlukan perubahan kode pada aplikasi
Menggunakan namespace jaringan khusus untuk aplikasi tertentu Shard proses per antarmuka ✅ (khusus container dengan hak istimewa)
Memetakan seluruh traffic container ke satu antarmuka Semua traffic penampung dipetakan ke satu antarmuka
Lakukan peering VPC dan biarkan sistem menyeimbangkan beban sesi di seluruh antarmuka Proses antarmuka ganda ✅* ✅* ✅* Sulit atau tidak mungkin untuk menyelaraskan NUMA Memerlukan Linux Kernel 6.16 atau yang lebih baru*
Membagi traffic di seluruh jaringan Proses antarmuka ganda Memproses shard per antarmuka ✅* ✅* ✅* Mungkin memerlukan perubahan kode untuk menyelaraskan NUMA jika menjalankan proses antarmuka ganda.
Menggunakan SNAT untuk memilih antarmuka sumber Proses antarmuka ganda Memproses shard per antarmuka ✅ (penyiapan memerlukan hak istimewa administrator) ✅ (penyiapan memerlukan hak istimewa administrator) Konfigurasinya bisa lebih sulit dilakukan dengan benar

* Opsi ini umumnya tidak direkomendasikan, tetapi mungkin berguna untuk beban kerja terbatas di platform x86 (A3 Ultra dan A4).

Mengubah aplikasi untuk menggunakan antarmuka tertentu

Persyaratan:

  • Metode ini memerlukan perubahan kode pada aplikasi Anda.
  • Memerlukan izin untuk satu atau beberapa metode berikut:
    • bind() hanya memerlukan izin khusus jika menggunakan port sumber dengan hak istimewa.
    • SO_BINDTODEVICE: memerlukan izin CAP_NET_RAW.
  • Metode ini dapat mengharuskan Anda mengubah tabel perutean kernel untuk membuat rute dan mencegah perutean asimetris.

Ringkasan umum

Dengan pola ini, Anda akan menyelesaikan hal berikut:

  1. Tambahkan pengikatan antarmuka jaringan ke kode sumber aplikasi Anda menggunakan salah satu opsi berikut:
    • Gunakan bind() untuk mengikat soket ke alamat IP sumber tertentu
    • Gunakan opsi soket SO_BINDTODEVICE untuk mengikat soket ke antarmuka jaringan tertentu
  2. Ubah tabel {i>routing<i} kernel sesuai kebutuhan untuk memastikan rute ada dari antarmuka jaringan sumber ke alamat tujuan. Selain itu, rute mungkin diperlukan untuk mencegah perutean asimetris. Sebaiknya Anda mengonfigurasi perutean kebijakan seperti yang dijelaskan dalam Mengonfigurasi perutean untuk antarmuka jaringan tambahan.
  3. Anda juga dapat menggunakan perintah numactl untuk menjalankan aplikasi. Dalam pendekatan ini, Anda menggunakan memori dan CPU yang berada di node NUMA yang sama dengan antarmuka jaringan yang Anda pilih.

Setelah Anda menyelesaikan langkah-langkah sebelumnya, instance aplikasi Anda akan berjalan menggunakan antarmuka jaringan tertentu.

Mengubah aplikasi untuk menggunakan kedua antarmuka

Persyaratan:

  • Metode ini memerlukan perubahan kode pada aplikasi Anda.
  • Anda memerlukan izin untuk satu atau beberapa metode berikut:
    • bind() hanya memerlukan izin khusus jika menggunakan port sumber dengan hak istimewa.
    • SO_BINDTODEVICE: memerlukan izin CAP_NET_RAW.
  • Metode ini dapat mengharuskan Anda mengubah tabel perutean kernel untuk membuat rute dan mencegah perutean asimetris.

Ringkasan umum

Untuk menerapkan pola ini, Anda melakukan hal berikut:

  1. Tambahkan pengikatan antarmuka jaringan ke kode sumber aplikasi Anda menggunakan salah satu opsi berikut:
    1. Gunakan panggilan sistem bind() untuk mengikat soket ke alamat IP sumber tertentu
    2. Gunakan opsi soket SO_BINDTODEVICE untuk mengikat soket ke antarmuka jaringan tertentu
  2. Jika aplikasi Anda bertindak sebagai klien, Anda harus membuat soket klien terpisah untuk setiap antarmuka jaringan sumber.
  3. Ubah tabel {i>routing<i} kernel sesuai kebutuhan untuk memastikan rute ada dari antarmuka jaringan sumber ke alamat tujuan. Selain itu, Anda mungkin juga memerlukan rute untuk mencegah perutean asimetris. Sebaiknya Anda mengonfigurasi perutean kebijakan seperti yang dijelaskan dalam Mengonfigurasi perutean untuk antarmuka jaringan tambahan.
  4. Sebaiknya Anda mempartisi aktivitas jaringan ke dalam thread yang berjalan di node NUMA yang sama dengan antarmuka gVNIC. Salah satu cara umum untuk meminta node NUMA tertentu untuk thread adalah dengan memanggil pthread_setaffinity_np.
    1. Karena aplikasi menggunakan resource di beberapa node NUMA, hindari penggunaan numactl atau pastikan perintah numactl Anda menyertakan node NUMA dari semua antarmuka jaringan yang digunakan oleh aplikasi Anda.

Menggunakan namespace jaringan khusus untuk aplikasi tertentu

Persyaratan:

  • Memerlukan kemampuan CAP_SYS_ADMIN.
  • Tidak kompatibel dengan Autopilot GKE.
  • Jika menggunakan GKE, Anda harus memiliki container dengan hak istimewa.

Bagian ini menjelaskan pola yang dapat Anda gunakan untuk membuat namespace jaringan yang menggunakan antarmuka jaringan sekunder. Pola yang tepat untuk workload Anda bergantung pada skenario spesifik Anda. Pendekatan yang menggunakan switch virtual atau IPvlan lebih cocok untuk kasus ketika beberapa aplikasi perlu menggunakan antarmuka sekunder dari namespace jaringan yang berbeda.

Ringkasan umum: memindahkan antarmuka sekunder ke namespace jaringan khusus

Pola ini melibatkan pembuatan namespace jaringan, memindahkan antarmuka gVNIC sekunder ke namespace baru, lalu menjalankan aplikasi dari namespace ini. Pola ini mungkin lebih mudah disiapkan dan disesuaikan dibandingkan dengan menggunakan switch virtual. Namun, aplikasi di luar namespace jaringan baru tidak akan dapat mengakses gVNIC sekunder.

Contoh berikut menunjukkan serangkaian perintah yang dapat digunakan untuk memindahkan eth1 ke namespace jaringan baru yang disebut second.

ip netns add second
ip link set eth1 netns second
ip netns exec second ip addr add ${ETH1_IP}/${PREFIX} dev eth1
ip netns exec second ip link set dev eth1 up
ip netns exec second ip route add default via ${GATEWAY_IP} dev eth1
ip netns exec second <command>

Saat perintah ini dijalankan, ekspresi <command> kemudian dieksekusi di dalam namespace jaringan, dan menggunakan antarmuka eth1.

Aplikasi yang berjalan di dalam namespace jaringan baru kini menggunakan gVNIC sekunder. Anda juga dapat menggunakan perintah numactl untuk menjalankan aplikasi menggunakan memori dan CPU yang berada di node NUMA yang sama dengan antarmuka jaringan yang Anda pilih.

Ringkasan tingkat tinggi: menggunakan namespace jaringan dan switch virtual untuk antarmuka sekunder Pola ini melibatkan pembuatan penyiapan switch virtual untuk menggunakan gVNIC sekunder dari namespace jaringan.

Langkah-langkah tingkat tingginya adalah sebagai berikut:

  1. Buat pasangan perangkat Virtual Ethernet (veth). Sesuaikan unit transmisi maksimum (MTU) di setiap perangkat agar sesuai dengan MTU gVNIC sekunder.
  2. Jalankan perintah berikut untuk memastikan penerusan IP diaktifkan untuk IPv4: sysctl -w net.ipv4.ip_forward=1
  3. Pindahkan salah satu ujung pasangan veth ke namespace jaringan baru, dan biarkan ujung lainnya di namespace root.
  4. Memetakan traffic dari perangkat veth ke antarmuka gVNIC sekunder. Ada beberapa cara untuk melakukannya, tetapi sebaiknya Anda membuat rentang alias IP untuk antarmuka sekunder VM dan menetapkan alamat IP dari rentang ini ke antarmuka turunan di namespace.
  5. Jalankan aplikasi dari namespace jaringan baru. Anda dapat menggunakan perintah numactl untuk menjalankan aplikasi menggunakan memori dan CPU yang berada di node NUMA yang sama dengan antarmuka jaringan yang dipilih.

Bergantung pada penyiapan tamu dan beban kerja, sebagai alternatif, Anda dapat menggunakan driver IPvlan dengan antarmuka IPvlan yang ditautkan ke gVNIC sekunder, bukan membuat perangkat veth.

Memetakan seluruh traffic container ke satu antarmuka

Persyaratan:

  • Aplikasi Anda harus berjalan di dalam container yang menggunakan namespace jaringan untuk jaringan container, seperti GKE, Docker, atau Podman. Anda tidak dapat menggunakan jaringan host.

Banyak teknologi container, seperti GKE, Docker, dan Podman menggunakan namespace jaringan khusus untuk container guna mengisolasi trafficnya. Namespace jaringan ini kemudian dapat diubah, baik secara langsung maupun menggunakan alat teknologi container untuk memetakan traffic ke antarmuka jaringan yang berbeda.

GKE mewajibkan antarmuka utama ada untuk komunikasi internal Kubernetes. Namun, rute default di pod dapat diubah untuk menggunakan antarmuka sekunder, seperti yang ditunjukkan dalam manifes pod GKE berikut.

metadata:
  …
  annotations:
    networking.gke.io/default-interface: 'eth1'
    networking.gke.io/interfaces: |
      [
        {"interfaceName":"eth0","network":"default"},
        {"interfaceName":"eth1","network":"secondary-network"},
      ]

Pendekatan ini tidak menjamin penyelarasan NUMA antara antarmuka jaringan default dan CPU atau memori.

Lakukan peering VPC dan biarkan sistem menyeimbangkan beban sesi di seluruh antarmuka

Persyaratan:

  • Peering VPC harus dibuat antara VPC gVNIC utama dan sekunder.
  • Kernel Linux versi 6.16 diperlukan untuk menyeimbangkan beban sesi TCP di seluruh antarmuka sumber jika mengirim ke satu IP dan port tujuan.
  • Beban kerja masih dapat memenuhi persyaratan performa Anda saat stack jaringan menghasilkan transfer memori lintas soket.

Ringkasan tingkat tinggi

Dalam beberapa kasus, sulit untuk membagi koneksi jaringan dalam aplikasi atau antara instance aplikasi. Dalam skenario ini, untuk beberapa aplikasi yang berjalan di VM A3U atau A4 yang tidak sensitif terhadap transfer lintas-NUMA atau lintas-soket, akan lebih mudah untuk memperlakukan kedua antarmuka sebagai dapat dipertukarkan.

Salah satu metode untuk melakukannya adalah dengan menggunakan sysctl fib_multipath_hash_policy dan rute multipath:

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 for nic0
SECONDARY_IP=192.168.2.27  # internal IP nic1

sysctl -w net.ipv4.fib_multipath_hash_policy=1  # Enable L4 5-tuple ECMP hashing
ip route add <destination-network/subnet-mask> nexthop via ${PRIMARY_GW} nexthop
via ${SECONDARY_GW}

Membagi traffic di seluruh jaringan

Persyaratan:

  • nic0 dan nic1 di VM berada di VPC dan subnet yang terpisah. Pola ini mengharuskan alamat tujuan di-shard di seluruh VPC nic0 dan nic1.

Ringkasan tingkat tinggi

Secara default, kernel Linux membuat rute untuk subnet nic0 dan subnet nic1 yang akan merutekan traffic berdasarkan tujuan melalui antarmuka jaringan yang sesuai.

Misalnya, nic0 menggunakan VPC net1 dengan subnet subnet-a, dan nic1 menggunakan VPC net2 dengan subnet subnet-b. Secara default, komunikasi ke alamat IP peer di subnet-a akan menggunakan nic0, dan komunikasi ke alamat IP peer di subnet-b akan menggunakan nic1. Misalnya, skenario ini dapat terjadi dengan sekumpulan VM NIC tunggal pembanding yang terhubung ke net1 dan sekumpulan VM yang terhubung ke net2.

Menggunakan SNAT untuk memilih antarmuka sumber

Persyaratan:

  • CAP_NET_ADMIN diperlukan untuk menyiapkan aturan iptables awal, meskipun tidak untuk menjalankan aplikasi.
  • Anda harus mengevaluasi aturan dengan cermat saat menggunakannya bersama dengan aturan iptables atau konfigurasi perutean nontrivial lainnya.

Catatan:

  • Pengikatan NIC hanya benar pada saat koneksi dibuat. Jika thread berpindah ke CPU yang terkait dengan node NUMA lain, koneksi akan mengalami penalti lintas NUMA. Oleh karena itu, solusi ini paling berguna jika ada mekanisme untuk mengikat thread ke set CPU tertentu.
  • Hanya koneksi yang berasal dari komputer ini yang akan terikat ke NIC tertentu. Koneksi masuk akan dikaitkan dengan NIC yang cocok dengan alamat tujuannya.

Ringkasan umum

Dalam skenario yang sulit menggunakan namespace jaringan atau membuat perubahan aplikasi, Anda dapat menggunakan NAT untuk memilih antarmuka sumber. Anda dapat menggunakan alat seperti iptables untuk menulis ulang IP sumber untuk alur agar cocok dengan IP antarmuka tertentu berdasarkan properti aplikasi pengirim, seperti cgroup, pengguna, atau CPU.

Contoh berikut menggunakan aturan berbasis CPU. Hasil akhirnya adalah bahwa alur yang berasal dari thread yang berjalan di CPU tertentu akan ditransmisikan oleh gVNIC yang terpasang ke node NUMA yang sesuai dengan CPU tersebut.

# --- 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 ---

# This informs which interface to use for packets in each 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"

# This is not required for connections we originate, but replies to
# connections from peers need to know which interface to egress from.
# Add it before the fwmark rules to implicitly make sure 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"

# This informs which table to use 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.
# Otherwise, we will drop legitimate replies to the SNAT IPs.
sysctl -w net.ipv4.conf."$OUTPUT_INTERFACE_0".rp_filter=2
sysctl -w net.ipv4.conf."$OUTPUT_INTERFACE_1".rp_filter=2

# Mark packets/connections with a per-nic mark based on the source CPU.
# The `fwmark` rules will then use 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

# For established connections, restore the connection mark.
# Otherwise, we will send the packet to the wrong NIC, depending on existing
# routing rules.
iptables -t mangle -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark

# These rules NAT the source address after the packet is already destined to
# egress the correct interface. This lets replies to this flow target the correct NIC,
# and may be required to be accepted into the VPC.
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"