Transport

Retransmisja TCP i Niezawodność

Fast retransmit, fast recovery, logika duplikatów ACK oraz SACK (Selective Acknowledgment).

Retransmisja TCP i niezawodność

Rozpatrzmy transfer danych podzielonych na ponumerowane segmenty, które odbiorca musi przetworzyć w określonej kolejności. Protokół Internetowy (IP) dostarcza te segmenty w modelu .

Segment może zaginąć, zostać zduplikowany albo dotrzeć po segmencie wysłanym później. Sama warstwa IP nie informuje nadawcy o każdej utracie. Odbiorca potrzebuje więc mechanizmu, który śledzi numery sekwencyjne, rozpoznaje brakujące dane i żąda ich ponownego przesłania.

TCP porządkuje strumień bajtów przekazywany aplikacji i wykorzystuje potwierdzenia oraz numery sekwencyjne do wykrywania braków. Jeśli połączenie pozostaje aktywne, mechanizmy retransmisji TCP pozwalają ponownie wysłać segmenty, których odbiorca nie potwierdził. Nie stanowią bezwarunkowej gwarancji dostarczenia, ponieważ połączenie może zostać przerwane. Ich zadaniem jest wykrycie prawdopodobnej utraty i dobranie momentu ponownej transmisji.

Wykrywanie Strat: Dwa Główne Wyzwalacze Retransmisji

Zanim TCP będzie mogło retransmitować utracony segment, musi najpierw zorientować się, że segmentu brakuje. Nie otrzymuje ono z sieci komunikatu o odrzuceniu konkretnego pakietu. Zamiast tego musi wnioskować o stracie na podstawie potwierdzeń (lub ich braku), które otrzymuje z drugiego końca. Istnieją dwa podstawowe sygnały, które wywołują to wnioskowanie.

1. Powolna Ścieżka: Przekroczenie Limitu Czasu Retransmisji (RTO)

To podstawowy mechanizm TCP wykrywania prawdopodobnie utraconego segmentu:

  1. Dla danych pozostających bez potwierdzenia nadawca utrzymuje jeden Licznik Czasu Retransmisji (ang. Retransmission Timer), związany z najstarszym niepotwierdzonym segmentem.
  2. Nadawca uruchamia licznik, gdy ma niepotwierdzone dane i nie działa jeszcze timer retransmisji, po czym oczekuje na ACK od odbiorcy.
  3. Jeśli ACK potwierdzi najstarsze dane przed wygaśnięciem timera, nadawca zatrzymuje go, gdy nie ma już danych w tranzycie, albo uruchamia ponownie dla kolejnych niepotwierdzonych danych.
  4. Jeśli timer wygaśnie, nadawca retransmituje najstarszy niepotwierdzony segment. RTO jest zwiększany przez wykładnicze wycofanie, ponieważ przyczyną może być utrata, opóźnienie albo zmiana kolejności segmentów.

Wygaśnięcie RTO może wskazywać na utratę segmentu, duże opóźnienie, zmianę kolejności albo przeciążenie. Nadawca retransmituje najstarsze niepotwierdzone dane i zmniejsza wysyłanie zgodnie z mechanizmem kontroli przeciążenia. RFC 6298 wyznacza RTO z estymat SRTT i RTTVAR, w uproszczeniu jako RTO=SRTT+max⁡(G,4×RTTVAR)\text{RTO} = \text{SRTT} + \max(G, 4\times\text{RTTVAR}). Przed uzyskaniem próbki RTT zalecane początkowe RTO wynosi 1 sekundę, a G oznacza ziarnistość zegara. Po wygaśnięciu wartość jest podwajana, a próbki obarczone niejednoznacznością retransmisji nie powinny służyć do aktualizacji RTT. Oczekiwanie na timer bywa powolne, zwłaszcza w sieciach o wysokiej latencji.

2. Szybka Ścieżka: Zduplikowane Potwierdzenia

TCP może wnioskować o utracie także na podstawie szybszego wzorca przychodzących potwierdzeń ACK. Mechanizm ten działa przed wygaśnięciem RTO, lecz jego wynik pozostaje heurystyką.

TCP używa schematu potwierdzeń kumulatywnych. ACK z numerem NN oznacza, że odbiorca otrzymał wszystkie bajty aż do N−1N-1 i teraz oczekuje bajtu NN. Jeśli segmenty dotrą w złej kolejności, odbiorca nie może jeszcze zwiększyć numeru potwierdzenia. Zamiast tego natychmiast wysyła kolejne ACK z niezmienioną wartością NN. Takie powtórzone ACK nazywa się zduplikowanym ACK.

Jeśli nadawca otrzyma trzy zduplikowane ACK bez ACK, który przesuwa punkt potwierdzenia, może uznać to za sygnał brakującego segmentu i uruchomić szybką retransmisję. Kolejne segmenty mogły dotrzeć poza kolejnością, lecz taki wzorzec może także wynikać z duplikacji ACK albo zmiany kolejności. Implementacja może ograniczyć reakcję na fałszywy sygnał, korzystając z SACK lub dodatkowych informacji. Jest to szybszy wyzwalacz niż oczekiwanie na pełne RTO.

Szybka Retransmisja i Szybkie Odzyskiwanie: Reakcja TCP

Wykrycie prawdopodobnej utraty za pomocą trzech zduplikowanych ACK uruchamia dwa powiązane algorytmy kontroli przeciążenia, Szybką Retransmisję i Szybkie Odzyskiwanie. Opisany wariant pochodzi z TCP Reno. Współczesne implementacje mogą stosować inne warianty, lecz zachowują podobną ideę szybszej reakcji.

Szybka Retransmisja (Fast Retransmit)

Algorytm Szybkiej Retransmisji jest prosty:

Po otrzymaniu trzeciego zduplikowanego ACK nie czekaj na wygaśnięcie Licznika Czasu Retransmisji. Natychmiast retransmituj segment zaczynający się w niezmienionym punkcie potwierdzenia, którego brak jest wnioskowany.

Taka retransmisja może zaoszczędzić czas jednego RTT oczekiwania na RTO. Nazywa się ją szybką, ponieważ wykorzystuje zduplikowane ACK przed wygaśnięciem timera.

Szybkie Odzyskiwanie (Fast Recovery)

Szybkie Odzyskiwanie określa działanie po Szybkiej Retransmisji. Zduplikowane ACK wskazują, że część segmentów dotarła do odbiorcy, więc połączenie nadal przenosi dane. Nie oznacza to jednak braku przeciążenia ani pewności, że wskazany segment zaginął.

Dlatego resetowanie z powrotem do 1 MSS, jak po RTO, ograniczyłoby przepustowość bardziej niż potrzeba przy tym sygnale.

Zamiast tego algorytm Szybkiego Odzyskiwania wykonuje następujące kroki:

  1. Mnożeniowy Spadek: Nadawca oblicza ssthresh=max⁡(FlightSize/2,2×SMSS)\text{ssthresh} = \max(\text{FlightSize}/2, 2\times\text{SMSS}), gdzie FlightSize oznacza dane w tranzycie, a SMSS segment danych. Po trzecim zduplikowanym ACK retransmituje brakujący segment i ustawia cwnd=ssthresh+3×SMSS\text{cwnd} = \text{ssthresh} + 3\times\text{SMSS}.
  2. Tymczasowe Zwiększenie: Za każde kolejne zduplikowane ACK nadawca zwiększa tymczasowo cwnd\text{cwnd} o SMSS. Pozwala to wysłać nowe segmenty, gdy odbiorca potwierdza wcześniej odebrane zakresy.
  3. Wznowienie Unikania Przeciążenia: Po ACK potwierdzającym wcześniej niepotwierdzone dane z fazy odzyskiwania nadawca zmniejsza cwnd\text{cwnd} do wartości ssthresh\text{ssthresh} i wznawia liniowy wzrost w fazie unikania przeciążenia.

Razem, Szybka Retransmisja i Szybkie Odzyskiwanie mogą naprawić pojedynczy brakujący segment bez oczekiwania na RTO. Wzór dotyczy klasycznego wariantu RFC 5681, a FlightSize oznacza faktyczną ilość danych w tranzycie, nie samą wartość cwnd. Czas zależy od RTT, kolejności segmentów, potwierdzeń i implementacji kontroli przeciążenia.

Ograniczenie Potwierdzeń Kumulatywnych i Rozwiązanie: SACK

Mechanizm Szybkiej Retransmisji i Szybkiego Odzyskiwania sprawdza się przy pojedynczej stracie, lecz ma ograniczenia, gdy z jednego okna transmitowanych danych zginie wiele segmentów.

Problem Wielokrotnej Utraty Pakietów

Rozważmy transfer 10 segmentów. Segmenty 3 i 6 zostają utracone, a odbiorca otrzymuje segmenty 1, 2, 4, 5, 7, 8, 9 i 10. Przy potwierdzeniach kumulatywnych odbiorca może zgłosić tylko, że nadal oczekuje segmentu 3.

Nadawca może otrzymać trzy zduplikowane ACK dla segmentu 3 i wykonać Szybką Retransmisję. Dopiero po ponownym otrzymaniu segmentu 3 odbiorca potwierdzi dane do segmentu 5 i wskaże oczekiwanie na segment 6. W tym uproszczonym wariancie Reno informacja o drugiej stracie dociera po kolejnym RTT, więc odzyskanie dwóch segmentów wymaga około dwóch RTT. Wynik zależy od liczby zduplikowanych ACK, rozmiaru okna i tego, czy odbiorca buforuje dane poza kolejnością.

Potwierdzenie Selektywne (SACK) przy Wielu Stratach

Aby ograniczyć to opóźnienie, opracowano rozszerzenie TCP zwane Potwierdzeniem Selektywnym (SACK). Obie strony muszą uzgodnić opcję SACK-Permitted w początkowych segmentach SYN i SYN-ACK.

Po uzgodnieniu odbiorca nadal wysyła potwierdzenie kumulatywne, lecz może dołączyć w nagłówku TCP bloki SACK. Każdy blok wymienia początkowy i końcowy numer sekwencyjny ciągłego zakresu danych, który został pomyślnie odebrany. Lewa krawędź oznacza pierwszy numer zakresu, a prawa krawędź numer następujący po jego końcu. Sama opcja nie uruchamia retransmisji. Nadawca wykorzystuje bloki do wyboru segmentów i nadal stosuje timer RTO jako zabezpieczenie.

Jak SACK Działa w Praktyce

Wróćmy do naszego przykładu z włączonym SACK. Nadawca wysyła segmenty 1-10. Segmenty 3 i 6 giną.

  1. Odbiorca otrzymuje segmenty 1 i 2. Wysyła normalne ACK z Numerem Potwierdzenia dla początku segmentu 3.
  2. Odbiorca otrzymuje segment 4 i wykrywa brak segmentu 3. Wysyła zduplikowane ACK dla początku segmentu 3 oraz Opcję SACK opisującą odebranie zakresu odpowiadającego segmentowi 4.
  3. Odbiorca otrzymuje segment 5. Wysyła kolejne zduplikowane ACK dla segmentu 3 z opcją SACK opisującą zakres segmentów 4-5.
  4. Nadawca otrzymuje te zduplikowane ACK. W klasycznym Fast Retransmit trzecie uruchamia retransmisję segmentu 3. Nadawca przetwarza także SACK i wie, że segmenty 4 i 5 zostały odebrane, więc nie musi ich retransmitować. Oznacza te zakresy w swoich strukturach danych jako potwierdzone selektywnie.
  5. Następnie odbiorca otrzymuje segment 7. Wysyła kolejne zduplikowane ACK dla segmentu 3, a opcja SACK zawiera zakresy 4-5 i 7.
  6. Na podstawie tej informacji nadawca wie, że segment 3 wymaga retransmisji, a segmenty 4, 5, 7 i kolejne zostały odebrane. Brakującym segmentem w tym przykładzie pozostaje segment 6. Nadawca może retransmitować go bez oczekiwania na kolejny RTT, jeśli pozwala na to jego algorytm odzyskiwania.

SACK przekazuje nadawcy zakresy odebranych danych, więc może on rozpoznać wiele brakujących segmentów bez czekania na osobne potwierdzenie każdej retransmisji. Przyspieszenie zależy od rozmiaru okna, RTT, limitu opcji i algorytmu kontroli przeciążenia. Bloki SACK zajmują miejsce w nagłówku, a ich liczba zależy od dostępnej przestrzeni opcji. Utrata ACK z blokiem może opóźnić rozpoznanie zakresu, dlatego timer RTO pozostaje potrzebny. SACK pozostaje użyteczny w sieciach z częstą utratą segmentów.

Powiązane artykuły