Złożoność routingu w sieciach AI: ECMP, routing adaptacyjny, DCQCN i dlaczego środowisko HPC ma na tym punkcie obsesję

Wcześniejsze artykuły omówiły kable, karty NIC, przełączniki i topologie. Ten dotyczy tego, co dzieje się piętro wyżej: w jaki sposób pakiety znajdują drogę przez strukturę wielu przełączników i co powstrzymuje tę strukturę przed załamaniem, gdy dziesięć tysięcy GPU postanowi wykonać all-reduce w tej samej chwili.

Ruch AI wygląda zupełnie inaczej niż ruch w zwykłym centrum danych. Frontend webowy wysyła miliony drobnych połączeń TCP. Trenowanie AI wysyła kilka ogromnych, idealnie zsynchronizowanych strumieni do znanych odbiorców, a wszyscy czekają na najwolniejszy z nich. Techniki, które sprawdzają się w pierwszym przypadku, w drugim się rozsypują.

Zastrzeżenie na wstępie: większość klientów Kentino pracuje na klastrach 1–4 węzłów. W tej skali żaden z opisanych problemów realnie nie boli. Wystarczy połączyć cztery węzły jednym przełącznikiem 100 GbE (albo bez przełącznika — patrz N05), uruchomić zwykłe RoCE na ustawieniach domyślnych i nigdy nie myśleć o ECMP ani DCQCN. Piszemy o tym mimo wszystko, ponieważ (a) to przydatne tło przy decyzjach o wymiarowaniu oraz (b) w dniu, w którym z czterech węzłów robi się szesnaście, wszystko to nagle zaczyna mieć znaczenie.

Czym jest ECMP i dlaczego wystarczało do czasu AI

ECMP — Equal-Cost Multi-Path — to sztuczka routingowa, dzięki której działają struktury leaf-spine i fat-tree. Gdy z leafa A do leafa B prowadzi kilka ścieżek o równym koszcie (przez spine'y S1..S4), przełącznik haszuje pola pakietu i na podstawie hasza wybiera spine. Klasyczny hasz z pięciu pól to (src IP, dst IP, src port, dst port, protocol).

Dla tradycyjnych obciążeń chmurowych — milionów krótkotrwałych połączeń TCP — ECMP sprawdza się znakomicie. Prawo wielkich liczb samo wykonuje równoważenie obciążenia. Przy 10 000 strumieni i 8 spine'ach uzyskuje się wynik odbiegający od idealnego balansu o kilka procent.

Ruch webowy — ECMP działa
  • Ponad 10 000 krótkotrwałych strumieni TCP
  • Prawo wielkich liczb równoważy spine'y
  • Rozkład obciążenia niemal idealny
  • Kolizja hasza ECMP: rzadka
Trenowanie AI — ECMP zawodzi
  • 8 strumieni-słoni, wszystkie naraz
  • Hasz z pięciu pól kieruje wiele strumieni na ten sam spine
  • Gorący spine = all-reduce o połowę wolniejszy
  • Prawdopodobieństwo kolizji: ~97% przy 8 strumieniach na 8 spine'ach

ECMP zaprojektowano dla wielu małych strumieni. Trenowanie AI wysyła kilka ogromnych, zsynchronizowanych strumieni — równowaga statystyczna przestaje działać.

Problem strumieni-słoni

Trenowanie AI to przeciwieństwo ruchu webowego. Krok trenowania: każde GPU liczy gradient, każde GPU wysyła swój gradient do wszystkich pozostałych (allreduce), wszyscy czekają na najwolniejszy transfer, powtórka.

Allreduce to niewielka liczba bardzo dużych strumieni. Ring-allreduce na 8 węzłach z kartami 200 Gbps to 8 równoczesnych strumieni, każdy wielkości kilku gigabajtów, wszystkie z prędkością łącza, wszystkie startujące w tej samej chwili. Dokument Meta o RoCE w dużej skali opisał to jasno: w klastrach AI znikoma liczba strumieni-„słoni” odpowiada za niemal wszystkie bajty i wszystkie chcą sieci w tym samym momencie.

Hasz ECMP z pięciu pól tego nie znosi. Przy N strumieniach-słoniach na S ścieżkach prawdopodobieństwo braku kolizji wynosi S! / ((S-N)! · S^N). Dla 8 strumieni na 8 spine'ach: około 2.4%. Nawet 32 spine'y dla 8 strumieni dają zaledwie ~33%. Dokładanie spine'ów nie zmienia tego rzutu monetą — daje więcej pustych łączy, podczas gdy dwa strumienie biją się o jedno.

Kolizja przeciąża łącze spine w stosunku 2:1, dotknięte strumienie pracują o połowę wolniej, a ponieważ krok czeka na najwolniejszy strumień, cała iteracja zwalnia o połowę. Pomiary na klastrach produkcyjnych raportują, że kolizje ECMP powodują nawet 40% straty wydajności przy allreduce.

Obejścia: lepsze haszowanie, równoważenie na poziomie pakietów, routing adaptacyjny

Cztery realne odpowiedzi, w kolejności rosnącej trudności wdrożenia:

1. Lepsze haszowanie (E-ECMP, świadome QP). Najtańsze rozwiązanie. Standardowy hasz z pięciu pól sprowadza ruch RDMA do jednej krotki na parę QP — pojedynczy strumień allreduce to naprawdę jeden kubełek ECMP. Wystarczy haszować także numer docelowego QP RoCE i sprawić, by aplikacja rozkładała ruch na wiele QP („skalowanie QP”). Liczby Meta: do 40% lepszy allreduce. Nadal statystycznie — kolizje są rzadsze, nie wyeliminowane.

2. Przełączanie flowletów. Wykrycie przerwy w ruchu i ponowne haszowanie od tego miejsca. Działa dla TCP, słabo dla RoCE nadawanego bez przerw.

3. Równoważenie na poziomie pakietów / rozpraszanie pakietów. Haszowanie per pakiet, zgoda na zmianę kolejności, a karta NIC składa całość z powrotem. Eliminuje problem strumieni-słoni, ale wymaga współpracy karty i przełącznika. Tak właśnie działa NVIDIA Spectrum-X — rozpraszanie per pakiet ze sprzętowym porządkowaniem w SuperNIC.

4. Routing adaptacyjny. Przełącznik śledzi przeciążenie na każdym porcie i w momencie przełączania wybiera najmniej obciążoną ścieżkę o równym koszcie, zamiast haszować na ślepo. W połączeniu z rozpraszaniem pakietów to właśnie to, co InfiniBand ma od piętnastu lat. Przeniesienie tego do Ethernetu jest sztandarową funkcją rozwiązań NVIDIA Spectrum-X (układy Spectrum-4/5 plus karty BlueField lub ConnectX-8 SuperNIC), Cisco Silicon One G200/P200 oraz Broadcom Tomahawk 5 / Jericho 3-AI z komórkową strukturą ze szeregowaniem.

Dla klastrów 1–8 węzłów routing adaptacyjny to przesada. Dla zadań na 64+ GPU skalowanych do 1 000 GPU jest różnicą między „wąskim gardłem jest sieć” a „wąskim gardłem są GPU”. Dlatego każdy poważny dostawca Ethernetu dla AI zbudował lub licencjonował krzemu do routingu adaptacyjnego w latach 2024–2026.

Kontrola przeciążenia: dlaczego „po prostu nie gubmy pakietów” nie jest darmowe

Druga połowa złożoności routingu to pytanie, co się dzieje, gdy do jednego portu przełącznika trafia naraz zbyt dużo ruchu. Dwie możliwości: sieć stratna gubi pakiety, a punkty końcowe zwalniają (tak działa otwarty internet); sieć bezstratna wymusza na przełączniku powyżej wstrzymanie nadawania — bez strat, ale przeciążenie propaguje się wstecz.

RoCE historycznie wymagał struktury bezstratnej. Karty RDMA źle znoszą utratę pakietów — pojedynczy zgubiony pakiet wyzwala retransmisję go-back-N całej wiadomości, co przy 100 GbE oznacza ponowne wysłanie megabajtów. RoCEv2 z go-back-N jest w praktyce nie do użytku w sieci stratnej przy wysokim wykorzystaniu.

PFC — Priority Flow Control (IEEE 802.1Qbb) to mechanizm, dzięki któremu Ethernet zachowuje się bezstratnie. Gdy kolejka wyjściowa przełącznika dla danego priorytetu przekroczy próg, przełącznik wysyła w górę ramkę PAUSE z prośbą o wstrzymanie nadawania na tym priorytecie. Osiem priorytetów, osiem niezależnych sygnałów stop/start.

Blokowanie czoła kolejki i strumienie-ofiary

Pauzy PFC są zgrubne. Pauza mówi „przestań nadawać priorytet 3 na tym łączu” — nie wie, który strumień wywołał przeciążenie. Jeśli dziesięć strumieni dzieli priorytet 3, a jeden z nich jest przeciążony dalej w sieci, PFC wstrzymuje wszystkie dziesięć. Pozostałych dziewięć „strumieni-ofiar” zostaje ukaranych za cudzy problem. To jest blokowanie czoła kolejki, podstawowa bolączka bezstratnego Ethernetu w dużej skali.

A B C Leaf 1 pauza PFC ← trunk Leaf 2 X przeciążony Y bez problemu ciężki strumień A→X PFC wstrzymuje CAŁY prio 3 B,C → Y też zablokowane

Blokowanie czoła kolejki: A→X wywołuje PFC na łączu trunk. B i C rozmawiające z Y (u którego wszystko jest w porządku) też zostają wstrzymane — to strumienie-ofiary.

Zakleszczenie PFC: jeśli topologia i ruch utworzą cykliczną zależność wstrzymanych łączy — A czeka na B, B na C, C na A — cała struktura się blokuje. Obserwowane w środowiskach produkcyjnych. Nowoczesne przełączniki mają wykrywanie zakleszczeń, a nowoczesne topologie Clos są wolne od zakleszczeń z samej konstrukcji; mimo to każde poważne wdrożenie RoCE ma plan wyjścia z takiej sytuacji.

Sensem nowoczesnej kontroli przeciążenia w AI jest utrzymanie buforów na tyle małych, żeby PFC nigdy nie odpaliło w stanie ustalonym. PFC pozostaje uzbrojone jako zabezpieczenie na wypadek prawdziwych mikroskoków. Mechanizmem, który nie pozwala mu odpalić, jest DCQCN.

DCQCN — standardowa kontrola przeciążenia dla RoCEv2

DCQCN (DataCenter Quantized Congestion Notification) to algorytm, na którym zbiegło się bezstratne RoCE. Opracowany przez Microsoft i Mellanox (SIGCOMM 2015). W latach 2025–2026 jest tym, co karty ConnectX/BlueField firmy NVIDIA uruchamiają domyślnie, i tym, co Azure raportuje jako standard produkcyjny obejmujący „~85% ruchu Azure, RDMA, we wszystkich regionach publicznych”.

DCQCN ma trzy role: CP (Congestion Point) to przełącznik, który znakuje pakiety przez ECN, gdy głębokość kolejki wyjściowej przekroczy próg (probabilistycznie od 0% przy Kmin do Pmax przy Kmax); NP (Notification Point) to karta odbiorcy, generująca CNP (Congestion Notification Packet) z powrotem do nadawcy po otrzymaniu oznaczeń ECN (z ograniczeniem częstości, zwykle jeden na 50 µs na strumień); RP (Reaction Point) to karta nadawcy, która multiplikatywnie zmniejsza przepływność danego QP po otrzymaniu CNP, a pod jego nieobecność zwiększa ją addytywnie, a potem hiperaddytywnie.

Typowa konfiguracja przełącznika dla DCQCN na 100 GbE:

# Profil ECN w stylu NVIDIA Cumulus na bezstratnym priorytecie RoCE (priorytet 3)
interface swp1..swp32
  qos remark dscp-to-tc 26 to 3       # DSCP 26 → TC 3
  qos congestion-mark ecn priority 3
  qos ecn-kmin       5KB              # początek znakowania
  qos ecn-kmax     200KB              # znakowanie na poziomie Pmax
  qos ecn-pmax       1%
  qos pfc priority 3
  qos pfc xoff     400KB              # pauza PFC (znacznie powyżej Kmax)
  qos pfc xon      300KB

Kmin/Kmax/Pmax to najczęściej strojona trójka w RoCE. Kmin ma być mały (kilka pakietów), żeby ECN zadziałało przed wyczerpaniem bufora; Kmax znacznie większy, żeby znakowanie narastało stopniowo; próg pauzy PFC znacznie powyżej Kmax, żeby PFC odpalało tylko wtedy, gdy DCQCN zareagowało za wolno. Pierwotne wdrożenie Microsoftu: Kmin = 5 KB, Kmax = 200 KB, Pmax = 1%.

Znane słabości DCQCN: załamanie przy incaście (100 nadawców uderza w jednego odbiorcę, kolejka zapełnia się szybciej, niż CNP wracają, odpala PFC — odpowiedzią jest DCQCN+); niesprawiedliwość w długim ogonie (strumienie startujące później są dławione dłużej); wrażliwość na parametry (Kmin dostrojone dla 4 węzłów nie przenosi się na 64). Uczciwe podsumowanie: DCQCN jest ustawieniem domyślnym, bo działa w większości przypadków. HPCC, Swift, EQDS i odnowione TIMELY istnieją jako propozycje zastąpienia go, ale żadna nie wyparła go do 2026 roku.

ECN, DCTCP i miejsce czystego TCP

Rozdzielmy to czysto, bo te pojęcia bywają mylone:

  • ECN — mechanizm warstwy IP (RFC 3168), w którym przełączniki znakują zamiast gubić. To sygnał, sam z siebie nic na niego nie reaguje.
  • DCQCN — reakcja punktu końcowego RDMA. Odczytuje ECN przez CNP i dostosowuje przepływność.
  • DCTCP — reakcja punktu końcowego TCP. Odczytuje ECN w ACK-ach i skaluje okno proporcjonalnie do udziału oznaczonych pakietów. Microsoft i Stanford, SIGCOMM 2010, dostępne w Windows Server i Linuksie.
Ruch Protokół Kontrola przeciążenia
Gradienty GPU-GPU (allreduce, NCCL po RoCE) RoCEv2 DCQCN (ECN + CNP + przepływność)
Pamięć masowa (NFS/RDMA, BeeGFS po RDMA) RoCEv2 DCQCN
Pamięć masowa (NFS po TCP, S3 do magazynu obiektów) TCP DCTCP (albo BBR, albo CUBIC)
Kubernetes / orkiestracja / warstwa sterowania TCP Domyślnie CUBIC, DCTCP po dostrojeniu
Telemetria / Prometheus / SSH TCP CUBIC

Kto pracuje na czystej strukturze RoCE, ten pracuje na DCQCN — warto znać swoje ustawienia domyślne. Jeśli na tym samym łączu jest także pamięć masowa i warstwa sterowania po TCP, warto włączyć DCTCP (net.ipv4.tcp_ecn = 1 plus przełączniki świadome ECN).

Dlaczego ruch AI obciąża to wszystko bardziej niż klasyczne centrum danych

Trzy cechy, pod które klasycznej kontroli przeciążenia nie projektowano:

  1. Zsynchronizowane skoki. Wszystkie GPU zaczynają allreduce w tej samej nanosekundzie. Od zera do 100% wykorzystania w mikrosekundach. Nie ma rozbiegu, w którym slow start znalazłby właściwą przepływność. Właśnie dlatego DCQCN startuje z prędkością łącza.
  2. Niewiele dużych strumieni. Prawo wielkich liczb nie przychodzi z pomocą. 8 strumieni → częste kolizje ECMP; 8 odbiorców → dotkliwe blokowanie czoła kolejki przez PFC.
  3. Ścieżką krytyczną jest najwolniejsze łącze. Czas kroku allreduce = maksymalny czas ukończenia strumienia. Nie ma „przypadku średniego”. Jednoprocentowe prawdopodobieństwo złej kolizji kumuluje się przez miesiące trenowania.

Dlatego ludzie od HPC i AI mają obsesję na punkcie sieci w sposób, jakiego operatorzy skali webowej historycznie nie mieli. Sieć webowa jest elastyczna — wolne żądania oznaczają, że część użytkowników poczeka chwilę dłużej. Trenowanie AI takie nie jest — całe zadanie biegnie z prędkością najwolniejszego zsynchronizowanego elementu.

Złożoność bez przełącznika (zapowiedź N05)

N05 omawia topologie bez przełącznika — połączenia bezpośrednie, siatkę, pierścień, torus 2D/3D, teserakt — dla małych klastrów, w których kupowanie przełącznika 100 GbE jest przesadą. Gdy usuwa się przełącznik, każdy węzeł staje się routerem: wiele kart, wiele ścieżek i coś musi wybrać następny skok.

Standardowa odpowiedź w 2026 roku to FRR (FRRouting) na każdym węźle, skonfigurowane w trybie BGP unnumbered. BGP unnumbered używa do sesji adresów link-local IPv6, więc nie trzeba przydzielać adresów IPv4 na każdym łączu. Każdy węzeł ogłasza swój loopback, uczy się loopbacków sąsiadów, a tablica routingu Linuksa wybiera właściwy następny skok.

# Minimalna konfiguracja FRR dla węzła w siatce bez przełącznika:
router bgp 65001
  bgp router-id 10.0.0.1
  neighbor enp1s0 interface remote-as external
  neighbor enp2s0 interface remote-as external
  neighbor enp3s0 interface remote-as external
  address-family ipv4 unicast
    network 10.0.0.1/32         # loopback tego węzła
    redistribute connected
  exit-address-family

Dwanaście linii na węzeł, ECMP po tylu parach kart, ile węzeł posiada — z tymi samymi zastrzeżeniami co ECMP na przełączniku. W siatce czterowęzłowej kolizje ECMP pojawiają się także po stronie hostów. Można je łagodzić większą liczbą QP albo zaakceptować stratę (przy 4 węzłach niewielką). „Brak przełącznika” nie oznacza „braku złożoności routingu” — przenosi ją na hosty.

Kiedy to ma znaczenie w praktyce

Większość czytelników nie będzie musiała robić nic z powyższych rzeczy.

  • 1–4 węzły, jeden przełącznik, RoCE do pamięci masowej i sporadycznego trenowania na wielu GPU: można zostawić przełącznik na ustawieniach domyślnych. Fabryczne progi DCQCN i ECN są w porządku. PFC jest włączone i najpewniej nigdy nie będzie widać pauzy. Kolizje ECMP są realne, ale ich wpływ na przebieg czterowęzłowy to pojedyncze procenty.
  • 4–16 węzłów, dedykowany klaster treningowy: należy jawnie włączyć DCQCN, ustawić Kmin/Kmax/Pmax na 5 KB / 200 KB / 1% (poziom bazowy Azure), włączyć skalowanie QP w NCCL oraz monitorować liczniki pauz PFC i częstość CNP. Jeśli pauz PFC przybywa, DCQCN jest zbyt łagodne — trzeba obniżyć Kmin.
  • 16+ węzłów lub 1 000+ GPU: routing adaptacyjny zwraca się z nawiązką. Warto kupić Spectrum-X z pasującymi kartami SuperNIC albo InfiniBand i przestać się przejmować ECMP, albo nawiązać współpracę z kimś, kto prowadził strukturę tej skali. Kosztem błędu są miesiące czasu trenowania.
  • Klaster bez przełącznika, dowolnej wielkości: FRR plus BGP unnumbered. 1–2 dni konfiguracji i testów na każde podwojenie liczby węzłów. Największa pułapka to zapomnienie o ECMP po stronie jądra (net.ipv4.fib_multipath_hash_policy = 1 dla haszowania na L4).

Odruch „dokupię pasma, to przeciążenie nigdy nie wystąpi” jest błędny. Zsynchronizowany ruch AI tworzy natychmiastowe zapotrzebowanie z prędkością łącza na każdej ścieżce, niezależnie od liczby spine'ów. Pasmo rozwiązuje problemy przepływności, a nie problemy koordynacji.

Co zrobić dalej

Jeśli cokolwiek z powyższego może dotyczyć danego klastra:

  1. Zinwentaryzować ruch. RoCE? TCP? Które łącza przenoszą jedno i drugie? Bez wiedzy, które strumienie na tym skorzystają, nie da się dostroić DCQCN.
  2. Sprawdzić rzeczywiste ustawienia domyślne DCQCN/ECN/PFC w przełączniku. Profile producentów opisane jako „zoptymalizowane pod AI” różnią się drastycznie. Część dostarczana jest z wyłączonym PFC. Część stosuje Kmin = prędkość portu × 5 µs — rozsądna heurystyka, nie zawsze trafna.
  3. Włączyć liczniki. Pauzy PFC RX/TX, CNP RX/TX, oznaczenia ECN, wykorzystanie poszczególnych łączy ECMP. Bez tego nie da się stwierdzić, czy struktura jest zdrowa pod obciążeniem.
  4. Zmierzyć realnym obciążeniem. nccl-tests/all_reduce_perf powie w pięć minut więcej niż tydzień syntetycznego iperfa.
  5. Ustalić, czy w ogóle występuje problem kolizji ECMP, zanim wyda się pieniądze na routing adaptacyjny. Większość klastrów 1–16-węzłowych go nie ma; większość klastrów 64+ węzłów ma.

N08 omawia faktyczną konfigurację RDMA — indeksy GID, MTU, zmienne środowiskowe NCCL, strojenie mlx5_core per karta, które zamienia działające łącze RoCE w szybkie. Tam ta teoria zamienia się w polecenia do wpisania.


To część Kentino Wiki, serii referencyjnej o infrastrukturze obliczeniowej AI, robotyce i systemach, które je łączą. Komentarze i sprostowania mile widziane pod adresem info@kentino.com.