TCP/IP to duma inżynierii prawie z przed 30-tu lat, gdy protokoły te były projektowane ich twórcy nie mieli pojęcia jak będzie wyglądała sieć dziś. Mimo wszystko zostały opracowane tak dobrze, że mimo iż cała sieć zmienia się całkowicie w przeciągu każdych kolejnych 10 lat, to wciąż działa na tym samym TCP/IP.
Google ma chyba największe i najlepsze "laboratorium" do przeprowadzania optymalizacji połączeń w sieci (klient-serwer). Mało która firma ma tak dużo obciążonych serwerów i do tego własną przeglądarkę. Ten zestaw tworzy wspaniałe laboratorium, w którym Google dostrzegł problem i postanowił pracować nad jego rozwiązaniem. Tak właśnie powstał między innymi TCP Fast Open.
Tam i z powrotem
Jak zapewne wiesz, protokół TCP (RFC 793) jest protokołem stanowym, dlatego musi nawiązać sesję przed przesłaniem danych. To nawiązanie jest zwane 3-way handshake (3WHS). Zanim serwer prześle treści do przeglądarki, klient musi wysłać pakiet SYN, a serwer na niego odpowiedzieć pakietem SYN-ACK. W tym momencie klient może już przesyłać pierwsze dane wraz z potwierdzeniem ACK. Dopiero po odebraniu tego pakietu serwer połączenie uważa się za nawiązane (ESTABLISHED) i przystępuje do wysyłania kodu strony dla klienta. Podróż pakietu od klienta do serwera i z powrotem określana jest mianem round-trip time (RTT), czyli czasem podróży tam i z powrotem.
Zauważ, że serwer HTTP jest bezstanowy, czyli każde żądanie jest dla niego indywidualne. Dlatego często trzeba nawiązywać nowe połączenia TCP, a każde takie nawiązanie zawiera w sobie koszt RTT.
Ile kosztuje RTT?
Wartość RTT jest celem dla mechanizmu TCP Fast Open, im większa ona jest, tym zysk jest większy. Dlatego warto dobrze zrozumieć istotę sprawy. Wyobraź sobie, że chcesz wybrać się do kina. Wcześniej jednak musisz pojechać do kina i zakupić bilet. Po otrzymaniu biletu, musisz wrócić do domu i z powrotem wrócić na film, o wyznaczonej porze. Tak w skrócie można zobrazować nawiązanie sesji TCP. W tym miejscu pominiemy fakt, że pierwszy raz bez sensu musisz jechać do kina tylko po to, aby kupić bilet. Skupmy się na tym, ile czasu tracisz przez to.
W rzeczywistym świeci wziąłbyś ze sobą zegarek i zmierzył czas, w świecie komputerów służy do tego program ping. Jeżeli ping-niesz różne strony, to w wyniku otrzymasz czas RTT. Jeżeli masz wolne łącze podróż pakietom zajmie więcej czasu. Ponadto należy pamiętać, że przeciętne strony wymagają wielu zapytań, często do różnych serwerów i w każdym z nich jest zawarty czas RTT.
Jak już wspomniałem wcześniej Google posiada największe "laboratorium", w którym dokładnie policzono jaki jest rzeczywisty koszt RTT.
Wykres przedstawia wyniki badań przeprowadzone na serwerach Google. Czerwony słupek reprezentuje procentowy koszt nowego trójstopniowego połączenia TCP, zielony to suma pierwszych i kolejnych zapytań w nawiązanych sesjach. Dla różnych usług Google te wartości są inne, ale jak widać w procesie wyszukiwania aż 15% czasu zabiera nawiązanie sesji TCP z serwerem.
Problem ten wcale nie jest nowy, po części rozwiązano go już wcześniej wprowadzając do protokołu HTTP mechanizm zwany Persistent Connection (RFC2616). Dla przykładu w serwerze Apache służy do tego dyrektywa KeepAlive, która jest domyślnie włączona. Również wszystkie przeglądarki implementują ten mechanizm.
Problem z Persistent Connection polega na tym, że o ile po stronie klient zasoby są raczej nie wykorzystywane maksymalnie, to po stronie serwera mechanizm ten zużywa bardzo dużo zasobów. Poza tym jak wynika z badań przeprowadzonych przez Google w 33% sytuacji mechanizm ten nie zdaje egzaminu. Wynika to z tego, jak obecnie złożone są strony internetowe i ze sposobu w jaki deweloperzy starają się przyśpieszyć ich ładowanie. Wiele serwisów korzysta z kilku równoległych połączeń, aby przyśpieszyć generowanie treści. Poza tym co raz popularniejsze urządzenia przenośne nie przechowują długo nieaktywnych połączeń z uwagi na mniejszą ilość zasobwów.
Persistent Connection to nie jedyny mechanizm przyśpieszenia protokołu HTTP, jest jeszcze HTTP Pipelining, o którym również pisałem wcześniej.
Pominąć 3WHS
Obecny standard TCP zezwala na wysyłanie danych wraz z pierwszym pakietem SYN, chociaż nie zezwala na wymianę danych przed zakończenie trójstopniowego połączenia. Dlatego postanowiono wykorzystać ten fakt i dodano do pakietu SYN tzw. prośbę o ciasteczko (cookie request) - przedstawia to schemat poniżej.
Gdy serwer otrzyma wraz z pakietem SYN prośbę o ciasteczko, wygeneruje je na podstawie adresu IP klienta i odeśle wraz z pakietem SYN, ACK. Klucz używany przez serwer do generowania ciasteczek jest zmieniany co jakiś czas ze względów bezpieczeństwa. Klient otrzymane ciasteczko przechowuje podobnie jak odpowiedzi serwera DNS, na przyszły użytek. Po rejestracji nowego klienta wymiana danych przebiega standardowo.
Korzyści zaczynają się wtedy, gdy ten sam klient ponownie wyśle zapytanie do serwera. Najpierw klient sprawdza, czy dysponuje ciasteczkiem dla danego serwera. Jeżeli takie posiada, to dołączy je i dane do pierwszego pakietu SYN. Serwer spostrzegając ciasteczko w pakiecie SYN przystępuje do jego weryfikacji. Są to podobno bardzo szybkie operacje szyfrowania, które mają minimalny wpływ na opóźnienia.
Prawidłowe ciasteczko sprawia, że serwer przekazuje dane z pakietu SYN do aplikacji, której wynik jest przesyłany z powrotem do klienta wraz z pakietem SYN, ACK. W ten sposób, w przypadku kolejnych zapytań, klient otrzymuje kod strony (w innym przypadku dane) w czasie jednego RTT, czyli pinga.
Ponad to serwer może zacząć wysyłać kolejne dane jeszcze przed otrzymania potwierdzenia, czyli ostatniego kroku 3WHS.
Gdyby nie mechanizm ciasteczek, można byłoby od razu przesyłać dane w pierwszym pakiecie SYN. Niestety, wtedy protokół TCP straciłby jedną ze swoich głównych zalet - stałby się niepodatny na fałszowanie adresu IP. Mimo konieczności generowania ciasteczek mechanizm ten nadal przyśpiesz połączenia (np. o 15% dla każdego kolejnego zapytania do google.com).
Implementacja
W każdym moim wpisie przychodzi czas na stwierdzenie, że GNU/Linux jest najlepszy :). W tym tekście ten czas przyszedł właśnie teraz. Przebrneliśmy przez tyle rzeczy tylko po to, abym znów mógł napisać, że Linux jest najlepszy. Właściwie czytanie tego tekstu można by rozpocząć od tego momentu, ale zapomniałem wspomnieć o tym na samym początku.
Tak więc, Linux jest obecnie pierwszym systemem, który będzie wspierał mechanizm TCP Fast Open. Do wersji jądra 3.6 dodano obsługę client-side, natomiast server-side została dodany do zbliżającej się wersji 3.7.
Obecnie TFO jest na poziomie wdrażania i testowania, istnieje propozycja standardu w IETF, co do której są oczekiwania, że w 2013 roku stanie się oficjalnym standardem. Na chwilę obecną trwają jeszcze rozważania nad propozycjami wdrożenia tego mechanizmu w przyszłości do innych systemów operacyjnych, zwłaszcza systemu Windows. Natomiast korzyści TFO będzie przynosił już niedługo, np. dla Google w samej serwerowni.
Zasoby:
"TCP Fast Open", CoNEXT 2011
"TCP Fast Open: expediting web services", lwn.net
"Let's make TCP faster", The Official Google Code blog
"Main development phase of Linux 3.7 completed", h-online.com
"How Google Wants to Make TCP Faster", readwrite.com
"How Google Wants to Make TCP Faster", readwrite.com
Internet Draft "TCP Fast Open", tools.ietf.org