praca dyplomowa pablos IMLTUMTOOYGSCAOEOJYFSHPDGNMELNC5HVQDL2A


Spis treści


1. Wstęp - cel i zakres pracy

Celem pracy jest przeprowadzenie pomiarów parametrów określających jakość transmisji danych (QoS - Quality Of Service) w sieci komputerowej pomiędzy Europejskim Centrum Badań Jądrowych CERN pod Genewą, a Akademickim Centrum Komputerowym CYFRONET w Krakowie.

Wyniki pracy zostaną wykorzystane w ramach projektu analizującego przydatność dynamicznego zarządzania rozproszonymi zasobami komputerowymi dla systemu filtracji Atlas[1].

Atlas jest jednym z czterech eksperymentów przygotowywanych do rejestracji zjawisk fizycznych, występujących podczas zderzeń protonów generowanych w budowanym akceleratorze LHC w CERN.

W czasie pracy akceleratora będzie dochodziło do około 1000*106 zderzeń na sekundę. Ponieważ na każde z nich przypadnie około 2MB danych, zapamiętanie wszystkich przypadków wymagałoby przepustowości około 80*1012 bajtów/sekundę.

Większość oddziaływań pomiędzy protonami prowadzi do dobrze poznanych zjawisk i w związku z tym nie jest interesująca. Takie przypadki należy odfiltrować, pozostawiając tylko interesujące i prowadzące do nowych zjawisk

System filtracji zajmujący się selekcją redukuje liczbę rejestracji do około 200 zdarzeń na sekundę (200 * 2MB = 400MB/s). Aby proces był efektywny (nie odrzucał interesujących przypadków, które występują niezmiernie rzadko) system prowadzący filtracje budowany jest jako wielostopniowy, gdzie wyższe poziomy, pracując na przypadkach zakwalifikowanych jako interesujące przez poziomy niższe, przeprowadzają coraz dokładniejszą analizę. Precyzja selekcji zależy więc od mocy komputerowych, jakie można wykorzystać do wykonywania algorytmów selekcji. Im większa moc obliczeniowa, tym większa selektywność procesu filtracji.

Projekt analizujący przydatność dynamicznego zarządzania rozproszonymi zasobami komputerowymi ma na celu oszacowanie, czy możliwe byłoby wykorzystanie zasobów komputerowych rozlokowanych w instytutach współpracujących z CERN-em oraz jakie warunki powinna spełniać sieć komputerowa, aby zapewnić przepływ danych z eksperymentu do ośrodków obliczeniowych w czasie rzeczywistym.

Komunikacja ma się odbywać w oparciu o dostępne łącza GigaEthernetowe przy wykorzystaniu protokołu TCP. Dlatego też konieczne było wcześniejsze przetestowanie przyszłych tras pod kątem przepustowości, ilości pakietów zgubionych, opóźnień, reakcji na chwilowe obciążenia, charakteru generowanego ruchu (parametry QoS).

W ramach pracy przeprowadziłem pomiary pomiędzy CERN-em a CYFRONET-em. Wchodzące w skład systemu testującego (patrz Rys.1.2) komputery zostały wyposażone w karty GigaEthernetowe Alteon, karty zegarowe oraz odbiorniki GPS, użyte do synchronizacji czasu (patrz rozdziały 2,3,4). Komunikacja została zrealizowana w oparciu o istniejącą, europejską sieć naukowo-badawczą GEANT (patrz dodatek B). Ponadto na trasie z Krakowa do Poznania zaalokowano 100-megabitowy kanał na cele przeprowadzanych pomiarów (patrz Rys. 1.1)

0x01 graphic

Rys.1.1. Trasa pomiarowa[2]

0x01 graphic

Rys.1.2. System testujący[2]

Na potrzeby badań napisałem oraz uruchomiłem na obu hostach aplikację pomiarową (patrz rozdział 4), umożliwiającą wygenerowanie ruchu w oparciu o protokół UDP i TCP oraz przeprowadzenie wymaganych testów, obejmujących:

2. Synchronizacja układu z wykorzystaniem systemu GPS

2.1 Wstęp

Jeden z parametrów transmisji, który miał zostać uzyskany w wyniku przeprowadzonych testów stanowiło opóźnienie pakietów przesyłanych pomiędzy CERN-em a CYFRONET-em. W tym celu w obu miejscach konieczne było posiadanie dwóch, precyzyjnie zsynchronizowanych źródeł czasu, co wymagało użycia specjalnego systemu złożonego z odbiornika GPS168PCI (patrz rozdział 2.2) oraz karty zegarowej (patrz rozdział 2.3).

Standardową metodą policzenia opóźnienia jest pomiar tzw. RTT (Round-Trip Time), czyli czasu jaki upływa od momentu wysłania pakietu ze źródła do momentu jego powrotu i następnie podzielenie uzyskanej wartości przez dwa. Niewątpliwie zaletą tego sposobu jest fakt, iż do odczytu czasu używany jest ten sam zegar, co sprawia, że nie musimy rozwiązywać problemu synchronizacji, a jedyny błąd pomiaru wynika z dokładności jego odczytu. Jakkolwiek metoda ta jest łatwa do zaimplementowania, tak do jej poprawności konieczne jest spełnienie kilku warunków. Pierwszy z nich wymaga, żeby trasa po której pakiet wraca z punktu docelowego była taka sama jak ta, po której do niego dotarł, co w warunkach internetu, gdzie w zależności od chwilowego stanu sieci występuje wiele możliwych ścieżek routowania, nie zawsze jest możliwe. Drugi wynika z faktu, iż pomimo spełnienia pierwszego warunku, zachowanie sieci niekoniecznie musi być takie samo w obu kierunkach. Chwilowe zatory czy taki a nie inny sposób funkcjonowania sprzętu sieciowego może mieć znaczący wpływ na utratę symetryczności trasy, która jest warunkiem koniecznym wymaganym przy pomiarze metodą RTT.

Obliczenie opóźnienia w jednym kierunku pozwala dokładniej oszacować i zrozumieć zachowanie sieci przy różnych warunkach i stanach, np. rodzaju i intensywności generowanego ruchu, porze dnia, stopniu wykorzystania przez inne stacje, rodzaju użytego sprzętu itp. Uzyskane wyniki mogą zostać użyte do dokładnego studiowania architektury badanej sieci czy analizy charakteru występujących zatorów, ich częstości, czasu trwania, powodu występowania. W celu wykonania takich obliczeń konieczne jest posiadanie dwóch, bardzo dobrze zsynchronizowanych zegarów, umożliwiających pobranie precyzyjnych czasów: pierwszego w momencie wysyłania danych na stacji nadawczej (wartość ta zostaje zapamiętana w pakiecie) oraz drugiego podczas jego odbioru na stacji docelowej.

Dokładna synchronizacja z dokładnością do części mikrosekund jest zadaniem bardzo trudnym, nawet w przypadku, gdy oba źródła czasów znajdują się w jednym pokoju, nie mówiąc już o sytuacji, kiedy stacje nadawcze i odbiorcze są oddalone od siebie o setki kilometrów. Dodatkowo problem ten potęguje fakt, iż operacją wstawiania czasu musi zostać objęty każdy pakiet, co w warunkach sieci GigaEthernet, zwiększa wymagania związane z dokładnością synchronizacji czy szybkością dostępu do zegarów.

Obecnie na rynku dostępne są komercyjne urządzenia umożliwiające analizę sieci pod kątem wyżej rozważanych warunków. Jednakże ceny ich są bardzo wysokie, natomiast elastyczność związana z generowanym ruchem dość ograniczona. Ponadto trudniejsza staje się późniejsza analiza uzyskanych wyników, umożliwiająca zamodelowanie zachowania sieci w pewnych warunkach.

Niekomercyjnym sposobem pozbawionym ww. ograniczeń, a przodującym przede wszystkim pod względem niższych kosztów finansowych, jest wykorzystanie do synchronizacji czasu dwóch kart: GPS168PCI oraz karty zegarowej. Implementacja systemu sprowadza się do zamontowania obu urządzeń w hostach uczestniczących w testach oraz ich odpowiedniego skonfigurowania i połączenia. Obecnie zostały opracowane dwie metody synchronizacji czasu, opartej na powyższym rozwiązaniu. Kryterium wyboru jednej z nich stanowi odległość pomiędzy dwoma hostami, uczestniczącymi w testach. Pierwsze, tzw. lokalne rozwiązanie stosuje się dla dystansu nie przekraczającego kilku metrów, natomiast drugie, globalne, dla pozostałych sytuacji, przy czym urządzenia testowane mogą znajdować się w praktycznie dowolnym miejscu na ziemi.

Dla pomiarów pomiędzy CERN-em a CYFRONET-em zostało wykorzystane rozwiązanie globalne (patrz rozdział 2.4) wraz z synchronizacją PPS (Pulse Per Second) (patrz rozdział 2.6).

2.2 Karta GPS168PCI

GPS168PCI jest kartą zegarową, wyprodukowana przez niemiecką firmę Meinberg[3], stanowiącą wysoce precyzyjne źródło czasu UTC, kontrolowane poprzez globalny system nawigacyjny GPS. Przeznaczeniem jej są aplikacje, dla których krytycznym elementem, odpowiadającym za poprawność działania, jest dokładny odczyt czasu. Produkt firmy Meinberg zapewnia tą precyzję przez 24 godziny w praktycznie dowolnym miejscu na kuli ziemskiej, co stanowi jego niewątpliwą zaletę.

2.2.1 Charakterystyka

GPS168PCI jest kartą typu plug-in, przeznaczoną do komputerów wyposażonych w magistralę PCI, pracującą w oparciu o dostępny system GPS. Sygnał nawigacyjny wysyłany przez satelity odbiera specjalna antena, przyłączona za pomocą 50 ohmowego miedzianego kabla. Uzyskane informacje są następnie przetwarzane przez wbudowany mikroprocesor, co pozwala uzyskać czas z dokładnością do 250nsec. Odbierany sygnał używany jest również do korekcji błędów, których źródłem może być m.in. czas propagacji sygnału poprzez kabel antenowy oraz niedokładność wbudowanego oscylatora TCXO, generującego wewnętrzny sygnał 10MHZ.

Z tyłu płytki mamy wejście na kabel antenowy, dwie diody sygnalizacyjne (zielona oraz czerwona) i 9-pinowe, szeregowe łącze COM0 (patrz Rys.2.1).

0x01 graphic

Rys.2.1. Karta GPS168PCI - widok z tyłu[3]

Antena przyłączona do karty powinna być umieszczona w takim miejscu, aby jak największy obszar nieba był widzialny. W przeciwnym przypadku mogą wystąpić pewne zakłócenia związane z widocznością satelitów.

Czerwona dioda sygnalizuje wystąpienie błędów podczas danej operacji lub brak pełnej synchronizacji karty.

Zielona dioda zostaje zapalona, gdy po uruchomieniu systemu możliwe jest zlokalizowanie co najmniej czterech satelitów wraz z określeniem ich pozycji.

Przy pomocy łącza COM0 możemy wyprowadzać lub wprowadzać odpowiednie sygnały, w zależności od ustawień umieszczonych na karcie dziesięciu przełączników DIL, powodujących zablokowanie lub uaktywnienie odpowiadających im pinów. Przypisanie do poszczególnych pinów wykonane zostało zgodnie z Tabelą 2.1.

Pin

Sygnał

DIL2

1

+5V

1

2

RxD

-

3

TxD

-

4

P_MIN

5

4

10MHZ

10

5

GND

-

6

CAP0

2

7

CAP1

3

8

P_SEC

4

9

DCF_OUT

6

Tabela 2.1. Rozkład sygnałów na wyjściu COM0 GPS168PCI

Karta GPS168PCI umożliwia wyprowadzenie sygnałów TTL, mających źródło w atomowym zegarze satelity, w których impulsy występują co sekundę (P_SEC-pin8) oraz co minutę(P_MIN-pin4). Pin 8 ustawiamy przez włączenie lub wyłączenie przełącznika4, natomiast pin4-przełącznika5. Niemożliwe jest jednak jednoczesne włączenie przełączników 4 i 5, ponieważ w danym momencie tylko jeden z sygnałów, P_MIN lub P_SEC, może być wyprowadzony na zewnątrz.

Odbiornik posiada wbudowany oscylator TCXO, generujący wewnętrzny sygnał o częstotliwości 10MHZ(pin4-regulacja poprzez przełącznik 10, zamiennie z sygnałem P_MIN).

Sygnały wejściowe CAP0(pin6-przełącznik 2) oraz CAP1(pin7-przełącznik 3) powodują zapamiętanie poszczególnych czasów. Jedno z opadających zboczy tych sygnałów sprawia, iż mikroprocesor zapisuje aktualny, rzeczywisty czas w specjalnym buforze. Zapamiętane wartości mogą być następnie wyświetlone przy pomocy programu monitorującego lub przekazane do portu COM1 (szeregowy port umieszczony na karcie w postaci 5-pinowego bloku). Bufor może przechować około 500 zapisów. W przypadku braku miejsca przez port COM1 transmitowana jest wiadomość „**capture buffer full**”, natomiast gdy przerwa pomiędzy poszczególnymi próbami zapamiętania jest zbyt krótka - „**capture overrun**”.

Sygnały przypisane do pinów łącza COM0, niezwiązane z przełącznikami DIL, są stale dostępne.

2.2.2 Opis startu systemu

Po zamontowaniu płytki w komputerze oraz podpięciu anteny, system jest gotowy do działania. Po około 10 sekundach oscylator TCXO, stopniowo korygowany poprzez otrzymywane z satelitów informacje nawigacyjne, pracuje z początkową, wymaganą dokładnością około +-2usec. Jeżeli w specjalnym buforze, którego zawartość podtrzymywana jest przez baterię, znajdą się parametry orbit satelitów, pozwalające określić ich położenie (almanac) oraz pozycja odbiornika (ephemeris), która nie uległa znaczącej zmianie od ostatniej operacji, może on natychmiast ustalić, które satelity są w jego zasięgu (strzałka nr1 - Rys.2.2). Po około 1 minucie następuje synchronizacja układu, do której wymagany jest pojedynczy satelita. Po 20 minutach pracy, TCXO osiąga końcową precyzję, generując sygnały z dokładnością do 250nsec.

Jeżeli jednak pozycja odbiornika ulegnie znaczącemu przesunięciu od ostatniego położenia, przy zachowaniu danych w buforze o położeniu satelitów, następuje przejście w tzw. tryb warm boot (strzałka nr2 - Rys.2.2). Po zlokalizowaniu co najmniej czterech, odbiornik oblicza nowe współrzędne i przechodzi do normalnego trybu pracy. W przypadku, gdy stracimy współrzędne satelitów np. na skutek wykasowania pamięci przechowującej odpowiednie dane, wtedy następuje przejście w tzw. tryb cold boot. Trwa to około 12 minut do momentu uzyskania wymaganych parametrów. Wówczas odbiornik przechodzi w opisany wcześniej stan warm boot. W trybie normalnym, wykorzystując magistralę PCI, dana aplikacja może pobierać z karty GPS ten sam czas w dowolnym miejscu na kuli ziemskiej z dokładnością do ok. 250nsec. Są to niewątpliwe zalety tego urządzenia, jednak karta ta posiada również swoje wady, nie wspomniane przez producenta, które ograniczają wachlarz jej zastosowań (patrz rozdział 3.2).

Podsumowując, GPS168PCI przechodzi przez następujące stany - patrz Rys.2.2.

0x01 graphic

Rys.2.2. Stany karty GPS168PCI

Przy czym tryby COLD BOOT oraz WARM BOOT są pomijane, w przypadku posiadania przez odbiornik wymaganych parametrów w buforze.

2.3 Karta zegarowa

Karta zegarowa stanowi wysoce precyzyjne źródło czasu, którego dokładność uzależniona jest od częstotliwości sygnału użytego do jego synchronizacji. Posiada wbudowany 32-bitowy licznik, inkrementowany z każdym rosnącym zboczem dostarczanego do niej kodu. Domyślnie taktowanie odbywa się w oparciu o lokalny oscylator, generujący sygnał 66MHZ. Pozwala to na uzyskanie czasu z dokładnością do 15nsec.

Licznik może być również taktowany w oparciu o dostarczany za pośrednictwem jednego z wejść sygnał zewnętrzny, mnożony przez wewnętrzny układ PLL razy 4(możliwość tą wykorzystano przy synchronizacji układu z użyciem odbiornika GPS).

Karta zegarowa została wyposażone w trzy wejścia i jedno wyjście, opisane w Tabeli 2.2.

nazwa

Opis

wejście nr 1

Służy do pobierania zewnętrznego sygnału, używanego do taktowania wbudowanego licznika.

wejście nr 2

Służy do pobierania zewnętrznego sygnału, kontrolującego moment wykonywania danej operacji.

wejście nr 3 (fire-in)

Służy do pobiera z zewnątrz sygnału, odpowiadającego poszczególnym komendom karty zegarowej.

wyjście (fire-out)

Służy do wyprowadzania na zewnątrz otrzymanych komend.

Tabela 2.2. Opis wejść i wyjścia karty zegarowej

Wszystkie wejścia i wyjście są wyprowadzone z tyłu karty w postaci czterech pinów.

Firmware karty zegarowej został zmodyfikowany na potrzeby synchronizacji systemu. Zostały dodane nowe i zmodyfikowane istniejące funkcje. Pełna lista związanych z nimi komend znajduje się w rozdziale 2.5.2.

2.4 Synchronizacja układu - rozwiązanie globalne

0x01 graphic

Rys.2.3. Synchronizacja układu - rozwiązanie globalne

Rozwiązanie globalne podchodzi do całej sieci jako do grup komputerów połączonych między sobą, wewnątrz których zrealizowano tzw. rozwiązanie lokalne, opisane poniżej.

W metodzie tej spośród wszystkich dostępnych, uczestniczących w testach w ramach lokalnej grupy kart zegarowych, wybieramy jedną, która pełni rolę karty głównej, natomiast pozostałe traktujemy jako podporządkowane, kontrolowane przez pierwszą[4]. Rola karty głównej sprowadza się do wygenerowania i przesłania odpowiedniego, tego samego sygnału taktującego liczniki dla pozostałych, podłączonych do niej kart. Dla niej samej odpowiedni kod uzyskujemy, wykorzystując w tym celu odbiornik GPS168PCI (port COM0-pin4-10MHZ) lub wewnętrzny generator, znajdujący się na samej karcie, wytwarzający sygnał o częstotliwości 66MZ. Tak więc w zależności od wykorzystanego źródła (66 MHZ lub 40MHZ=10MHZ*4), możemy odczytywać czas z dokładnością do 15 nsec lub 25nsec.

Z pozoru problem sprowadza się do właściwej synchronizacji wszystkich kart głównych, co możemy uzyskać poprzez zastosowanie w każdym węźle odbiorników GPS jako źródeł wymaganego sygnału, jednak w trakcie testów zauważono pewne niedokładności (patrz rozdział 2.6) i w celu ich wyeliminowania zmodyfikowano firmware na kartach zegarowych, uaktualniono w odbiornikach GPS oraz zastosowano inny sposób połączeń pomiędzy nimi.

Dla przeprowadzonych testów wykorzystano dwie lokalne grupy (jedna w CERN-ie a druga w Cyfronecie) z tym, że każda z nich składała się wyłącznie z jednej karty zegarowej, pełniącej rolę karty głównej, synchronizowanej w oparciu o satelitarny sygnał uzyskany z odbiornika GPS (patrz Rys.1.1).

2.5 Opis konfiguracji systemu

2.5.1 Hardware

Jak wcześniej zostało wspomniane, każdą lokalną grupę wyposażono w odbiornik GPS. Przyłączona do niego antena powinna być tak umiejscowiono, aby jak największy obszar nieba pozostawał w jej obrębie (wykorzystując dostarczony wraz z kartą program mbgstatus można sprawdzić czy odpowiednia liczba satelitów jest widoczna).

Dla prawidłowego funkcjonowania całego systemu, znajdujące się na odbiorniku GPS przełączniki DIL zostały ustawione w następujący sposób (patrz Tabela 2.3).

DIL

STAN

OPIS

10

WŁĄCZONY

sygnał 10MHZ dostępny na pinie 4 COM0

4

WŁACZONY

sygnał 1HZ dostępny na pinie 10 COM0

Wszystkie pozostałe przełączniki - wyłączone

Tabela 2.3. Ustawienia przełączników DIL

Na dwa pierwsze wejścia kart zegarowych dostarczano z odbiornika GPS sygnały: 10MHZ i 1HZ. Wszystko to odbyło się za pośrednictwem dostępnego okablowania. Karty nie wykorzystywały swoich wszystkich wejść, ponieważ wszelkie komendy przesyłane były do nich za pośrednictwem magistrali PCI.

Karty zegarowe zostały połączone z odbiornikami GPS według schematu przedstawionego w Tabeli 2.4.

GPS168PCI

Karta zegarowa

GPS COM0 pin 4 (sygnał 10MHZ)

->

wejście nr 1 na karcie zegarowej

GPS COM0 pin 8 (sygnał 1HZ)

->

wejście nr 3 na karcie zegarowej

wyjście nr 2 na karcie zegarowej (fire-out)

->

wejście nr 4 na karcie zegarowej(fire-in)

Tabela 2.4. Połączenia kart zegarowych z odbiornikami GPS

2.5.2 Software

Wraz z kartami dostarczony został pakiet oprogramowania, zarządzający systemem. Wśród nich najważniejsza jest aplikacja hs_master inicjująca i kontrolująca cały mechanizm synchronizacji, przy wykorzystaniu zbioru komend.

W celu zaimplementowania nowych możliwości do całego systemu i zwiększenia poprawności synchronizacji, firmware kart zegarowych został zmodyfikowany, poprzez dodanie nowych poleceń do już istniejących. W Tabeli 2.5 przedstawiłem listę wszystkich komend, dostępnych po uaktualnieniu.

komenda

opis

PRE_ATTENTION

Wskazuje karcie, że następny impuls na wejściu „sterującym” oznacza ATTENTION - uwaga przy następnym impulsie 1HZ zresetuj się.

PRE_ATTENTION_USING_PPS THREAD

Jak poprzednio z tym, że po zresetowaniu karta jest synchronizowana metodą PPS.

TESTING_MODE

Wskazuje karcie, że następny impuls przychodzący na wejście sterujące jest typu WRITE_DOWN, oznaczający konieczność zapisania aktualnego czasu w wektorze testującym.

komenda

opis

PRE_GPS_TESTING

Nakazuje karcie wraz z pojawieniem się pierwszego impulsu na wejściu „sterującym”, przejście w tryb GPS_START, który powoduje, iż przez kolejne 32 impulsy 1Hz, karta zapisuje aktualne czasy do wektora testującego.

ATTENTION/

WRITE_DOWN/

START_GPS

Jeżeli karta odbierająca sygnał (polecenie) jest w trybie PRE_ATTENTION, komenda ta oznacza ATTENTION, TESTING_MODE - WRITE_DOWN, natomiast PRE_GPS_TESTING-START_GPS. Ponadto powoduje wyemitowanie przez kartę impulsu na wyjściu „sterującym” fire-out.

READ_TIME

Ustawia kartę w tryb, w którym przy zapytaniu o czas podaje na wyjściu aktualny odczyt.

READ_TESTS

Ustawia kartę w tryb, w którym przy zapytaniu o czas podaje na wyjściu pierwszą wartość odczytaną z wektora testującego. Po tej operacji następuje inkrementacja indeksu o jeden, aby przy kolejnym zapytaniu dla tego trybu podać kolejną zapamiętaną wartość.

REWIND_TESTS

Polecenie to powoduje, że wartość indeksu wymienionego powyżej zostaje ustalona na 1. Oznacza to, że przy następnym odczycie w trybie testującym zostanie podana pierwsza wartość zapisana w wektorze, natomiast zapisywanie(nadpisywanie) będzie odbywało się od początku tablicy.

GET_TEST_DATA

Powoduje pobranie zawartości wektora testującego.

Tabela 2.5. Komendy karty zegarowej

Wszystkie polecenia związane z przestawianiem kart w odpowiednie tryby (pre_attention, pre_attention_using_pps thread, pre_gps_testing, testing_mode), wykonywane są lokalnie na komputerze poprzez magistralę PCI - dla każdej karty osobno. Jedna z komend (attention, write_down, gps_start) reprezentowana jest przez to samo polecenie, a jego interpretacja zależy tylko od trybu w jakim znajduje się dana karta. Wszystkim stanom przypisane są osobne polecenia, natomiast attention, write_down, gps_start reprezentuje jedna komenda.

Jako przykład można przytoczyć standardową procedurę resetowania kart:

  1. Wprowadzamy wszystkie karty w tryb PRE_ATTENTION, poprzez wysłanie właściwej komendy.

  2. Następnie wydajemy polecenie, które zostaje zinterpretowane jako ATTENTION, ponieważ karty są w trybie PRE_ATTENTION. Wszystkie karty czekają i wraz z impulsem 1HZ, który przesyłany jest równocześnie do wszystkich, resetują swoje liczniki.

Na każdym hoście uruchamiany jest program hs_master. Umożliwia on dwie metody synchronizacji: pierwszą, powodująca jednoczesne zresetowanie kart, a następnie pozostawienie ich pod kontrolą generowanych przez odbiornik GPS impulsów 10MHZ, oraz drugą wykorzystującą tzw. synchronizację PPS, opierającą się na impulsie 1HZ, wykorzystywanym do obliczania nowych wartości liczników kart zegarowych.

Ponadto przy pomocy hs_master możemy przetestować poprawność synchronizacji wszystkich węzłów.

Procedura jest następująca. Ustawiamy karty zegarowe w tryb testowania globalnego(PRE_GPS_TESTING), wskaźnik wektora testującego przesuwamy na początek(REWIND_TESTS), ustawiamy czas(tzw.reference time), po którym zostanie przesłany impuls(START_GPS) powodujący, że z każdym zboczem sygnału 1HZ, karty zegarowe zapiszą wartość odczytanego czasu do test_wektora. Odczekujemy około 37 sekund i następnie poprzez polecenie GET_TEST_DATA wyprowadzamy zapamiętane wyniki do pliku i dokonujemy ich porównania.

Nie w każdym przypadku możliwy jest jednak globalny test całego systemu. Szczególną taką sytuację stanowi aktywna synchronizacja z użyciem korekcji PPS. Wtedy musimy użyć opcji umożliwiającej odczytanie wartości licznika przed wystąpieniem impulsu 1HZ, ponieważ przy każdym zboczu licznik jest korygowany przez firmware, co zawsze w wyniku dawałoby idealną wartość i nie moglibyśmy zauważyć ewentualnych błędów.

2.6 Opis procedury synchronizacji

Problem synchronizacji może być podzielony na dwie zasadnicze części:

Jak zostało wcześniej wspomniane, sygnał 10MHZ dostarczany jest do kart zegarowych za pomocą specjalnych połączeń, które muszą być jak najkrótsze, aby zniwelować błąd wynikający z opóźnień transmisji. Sygnał ten stanowi zewnętrzne źródło czasu dla taktowanych nim kart zegarowych. Posiadają one wbudowany wewnętrzny 32-bitowy licznik inkrementowany z każdym wznoszącym się zboczem. Ponieważ do wszystkich z nich doprowadzany jest ten sam sygnał z kart GPS, dlatego teoretycznie po jednoczesnym ich zresetowaniu, uzyskamy wymaganą, automatyczną synchronizację. Także jedyny problem to wyzerowanie, do którego wykorzystany został drugi z dostępnych sygnałów, o częstotliwości 1HZ.

Jest on jednocześnie propagowany do wszystkich kart zegarowych za pośrednictwem specjalnych połączeń z odbiorników GPS, co zapewnia, iż w danym momencie każda karta posiada tą samą charakterystykę dla poszczególnych zegarów. Firmware kart udostępnia specjalny tryb, w którym następuje jednoczesne zresetowanie liczników. Stan ten jest aktywowany poprzez sekwencję dwóch komend: PRE_ATTENTION oraz ATTENTION. W tym trybie, pierwszy impuls 1HZ powoduje wyzerowanie liczników. Procedura resetująca jest następująca. Na początku ustawiamy wszystkie karty w tryb PRE_ATENTION (tryb ten pozwala zinterpretować kolejny sygnał jako ATTENTION, nie jako WRITE_DOWN lub START_GPS). Następnie ustalamy tzw. reference time, czyli przybliżony czas, w którym nastąpi wyzerowanie liczników. Przybliżony, ponieważ sama karta około 0,5sec przed jego upływem otrzymuje sygnał ATTENTION. Jak wcześniej zostało wspomniane, wskazuje on, iż przy pierwszym sygnale 1HZ ma nastąpić wyzerowanie licznika. Czas propagacji polecenia poprzez okablowanie jest rzędu dziesiątek nanosekund, a więc wystarczająco mały, aby założyć, iż karty odbiorą go w tym samym momencie. Następnie oczekują na sygnał 1HZ, a ponieważ jak wiemy, jego źródło dla wszystkich zegarów jest takie samo, także ich liczniki wyzerowują się jednocześnie.

Problem zresetowania mamy już rozwiązany. Pozostaje tylko zapobiec dryfowaniu czasu. Dzięki sygnałowi TTL 10MHZ z odbiorników GPS, wykorzystywanemu do taktowania liczników kart, możemy automatycznie synchronizować ich wartość. Jednak tylko teoretycznie, ponieważ jak się okazało maksymalny błąd wyprowadzania 10MHZ sygnału wynosi ok. 0,1usec. Rozbieżność ta powoduje niedokładność metody zwłaszcza, iż ulega ona kumulacji w miarę upływu czasu, powodując błędy sięgające nawet około 3000 taktów (75usec) po około 10 dniach, co znacznie ogranicza możliwą precyzję wykonywanych pomiarów.

W celu zniwelowania tego błędu zmodyfikowano firmware kart zegarowych. Założono wstępnie, iż sygnał 1HZ jest dokładny, co po przeprowadzonych testach okazało się słuszne. Modyfikacje polegały na tym, iż z każdym nadchodzącym sygnałem 1HZ wartość licznika jest „normalizowana” do „idealnej” wartości zliczeń. Za pośrednictwem poprawionego oprogramowania kart, licznik ustawia się wg wzoru:

nowa_wartość licznika = poprzednia_wartość+40 000 000

Poprzednia_wartość jest stanem licznika zapamiętanym przy ostatniej modyfikacji, przy czym w momencie zresetowania równa się zero. Metoda ta pomiędzy poszczególnymi impulsami 1HZ pozostawia licznik wpływowi sygnału 40MHZ (zastosowano to wspomniany wcześniej mnożnik 4), natomiast przy każdym zboczu powoduje jego ustawienie na „idealną” wartość. W efekcie tej korekty wyeliminowano efekt kumulacji błędu od dryfowania czasu. Przy testowaniu odczytywane są wartości tuż przed pojawieniem się impulsu 1HZ tak, aby nie porównywać wielkości „idealnych” wpisywanych do niego, które w rzeczywistości na każdej karcie są zawsze takie same.

Po przeprowadzeniu testów zauważono, iż różnice wskazań sięgają ok.+-4 taktów zegara, a w większości przypadków wynoszą 0, co na pewno jest wystarczające dla nawet najbardziej precyzyjnych pomiarów. Metoda ta została nazwana korekcją PPS.

W zainstalowanym systemie w celu przeprowadzenia właściwej synchronizacji kart z wykorzystaniem metody PPS po ustaleniu reference time wydałem następujące komendy: PRE_ATTENTION_USING_PPS_THREAD oraz ATTENTION.

2.7 Porównanie metody do innych dostępnych

Dokładność jaką można uzyskać dzięki zastosowaniu opisanego powyżej systemu wynosi około 100nsec co stanowi jego niezaprzeczalną zaletę. W Tabeli 2.6 zostało przedstawionych kilka rozwiązań dostępnych obecnie na rynku, umożliwiających synchronizację czasów wraz z ich dokładnością.

Produkt

Opis

TymServe2100

Dokładność 2usec przy wykorzystaniu GPS i 10msec przy użyciu NTP

TrueTime NTS Family

Dokładność 10msec

Lantronix CoBox NTP-E1

Dokładność rzędu 1usec

Tabela 2.6. Inne metody synchronizacji

Systemy te wykorzystują NTP (Network Time Protocol) do synchronizacji czasu (błędy rzędu milisekund) oraz dodatkowo GPS, który pozwala osiągnąć większą dokładność sięgającą mikrosekund.

Ostatni system tzw. network tester charakteryzuje się dokładnością porównywalną do uzyskanej dzięki opisanej metodzie, jednak ogólny koszt implementacji całego systemu jest dużo większy.

Niezaprzeczalną zaletą PPS jest fakt, iż przy wykorzystaniu dwóch odbiorników GPS można zsynchronizować większą liczbę komputerów, co obniża ogólne koszty. Ponadto istnieje możliwość zmiany firmware'u na kartach zegarowych, co zapewnia większą elastyczność i kontrolę, jeżeli chodzi o przeprowadzane testy.

3. Oszacowanie dokładności procesu synchronizacji z wykorzystaniem GPS

3.1 Wstęp

Podczas przygotowania i testowania systemu synchronizacyjnego wykonałem trzy pomiary. W pierwszym dwóch uzasadniłem, dlaczego do bezpośredniego odczytu czasu nie wykorzystujemy odbiornika GPS168PCI a odpowiednią wartość pobieramy z karty zegarowej, natomiast w ostatnim pokazałem jak niedokładny może być pomiar czasu przy użyciu zegara systemowego.

3.2 Pomiar czasu dostępu do karty zegarowej oraz GPS 168PCI

3.2.1 Cel pomiaru

Celem pomiaru było oszacowanie czasu dostępu do karty zegarowej oraz karty GPS168PCI poprzez magistralę PCI. Przy pomiarze opóźnienia każdy pakiet (zarówno ten wysyłany jak i odbierany) musi być oznaczony dokładnym czasem. Ponieważ różnice pomiędzy poszczególnymi pakietami oscylują wokół 100usec dla przepustowości 100Mb/s oraz 10usec dla 1Gb/s, zegar źródłowy również musi odpowiednio szybko dostarczać wymagane dane (patrz Tabela 3.1). Czas, jaki upływa pomiędzy zażądaniem przez aplikację potrzebnych parametrów, a ich otrzymaniem nie może przekraczać tej wielkości, a dobrze byłoby, gdyby zapewniał również „zapas” na wypadek nagłego przeciążenia systemu i powstałych w ten sposób opóźnień.

protokół

rozmiar danych

docelowa przepustowość

różnica pomiędzy pakietami

UDP

1472B

100Mb/s

116usec

1Gb/s

11,6usec

TCP

1448B

100Mb/s

115usec

1Gb/s

11,5usec

Tabela 3.1.Opóźnienia pomiędzy pakietami dla różnych przepustowości

3.2.2 Sposób przeprowadzenia pomiaru

W celu otrzymania właściwych danych dla karty zegarowej napisałem aplikację, w której w ustalonej co do ilości powtórzeń pętli „for” pobieram z karty poprzez magistralę PCI aktualne czasy (funkcja hs_pci_read, pozwalająca odczytać stan licznika karty z dokładnością do mikrosekund), zapamiętując je w jednowymiarowej tablicy tab[indeks], przy czym „indeks” reprezentuje numer kolejnego odczytu czasu. Wykonałem READ_NR odczytów:

#define READ_NR 1000

#define MAX_HIST 100

#define MIN_HIST 1

#define OFFSET 0

.

unsigned long tab[READ_NR];

.

int i,hist[MAX_HIST-OFFSET+2];

.

for (i=0;i<=READ_NR-1;i++) hs_pci_read_data(&tab[i]);

Następnie dokonuję przetworzenia zapisanych danych tak, aby można było na ich podstawie stworzyć histogram obrazujący czas dostępu do urządzenia. W tym celu w tablicy hist[indeks] zapamiętałem częstość występowania danych wartości, przy czym w pierwszym elemencie scharakteryzowałem wszystkie wartości mniejsze niż MIN_HIST(=1), natomiast w ostatnim-większe niż MAX_HIST(=100). „Indeks” reprezentuje wartość czasu dostępu. W tym przypadku nie dokonywałem skalowania(OFFSET=0), ponieważ wcześniej przeprowadziłem wstępne oszacowanie, na podstawie którego można było założyć, iż uzyskane wartości są z przedziału (0..100). Po uzupełnieniu tablicy hist[], zapisałem jej wartości do pliku „clock”, celem późniejszego wykorzystania do narysowania histogramu. Poniższy fragment kodu reprezentuje ww. zadania:

for (i=0;i<READ_NR-1;i++)

{

if ((tab[i+1]-tab[i]) >=MIN_HIST) && (tab[i+1]-tab[i])<=MAX_HIST)

{

hist[ tab[i+1]-tab[i]-OFFSET]++;

}

else

{

hist[(tab[i+1]-tab[i]) > MAX_HIST ? (MAX_HIST-OFFSET+1) : 0]++;

}

}

for (i=0;i<=MAX_HIST;i++)

{

fprintf(fp,"%d\t%lu\n",i+1,hist[i]);

}

fclose(fp);

W celu otrzymania właściwych danych dla GPS168PCI, wykorzystałem aplikację podobną do poprzedniej. Jedyne różnice są następujące.

Zamiast polecenia hs_pci_read_data(&tab[i]) do pobrania czasu użyłem instrukcji:

tab[i]=frac_sec_from_bin( ht.tstamp.frac, PCPS_HRT_FRAC_SCALE );

Powoduje odczytanie z odbiornika GPS poprzez magistralę PCI części ułamkowej sekundy z dokładnością do setek nanosekund oraz zapamiętanie wartości w tablicy tab[].

Po wstępnym oszacowaniu, iż czas dostępu zawiera się w przedziale (1000...2000-mikrosekund), dokonałem przeskalowania indeksacji tablicy hist[] o 1000, także częstość wystąpienia wartości 1001usec odpowiada elementowi hist[1], natomiast 2000usec - hist[1000]. Liczbę wystąpień wszystkich wartości mniejszych niż 1001 zapamiętałem w hist[0], natomiast większych niż 2000 w hist[1001].

Fragment kodu odpowiedzialny za przetworzenie zapamiętanych wyników jest identyczny jak poprzednio z tym, że wykonuje się dla innych definicji makr.

A mianowicie:

#define READ_NR 1000

#define MAX_HIST 2000

#define MIN_HIST 1001

#define OFFSET 1000

Końcowe dane zapisałem w pliku „clock_gps”.

3.2.3 Uzyskane wyniki

Na podstawie danych zapisanych w pliku „clock” narysowałem wykres, obrazujący czas dostępu do karty zegarowej poprzez magistralę PCI (patrz Rys.3.1).

0x01 graphic

Rys.3.1. Czas dostępu do karty zegarowej - wykres

Można zauważyć, iż czas dostępu oscyluje wokół 40 taktów zegara. Ponieważ wewnętrzny licznik taktowany jest sygnałem o częstotliwości 40MHZ, tak więc uzyskana wartość odpowiada 1usec.

Jak wcześniej zostało wspomniane, w zależności od docelowej przepustowości, którą należy uzyskać, różnica pomiędzy poszczególnymi pakietami, zarówno tymi odbieranymi jak i wysyłanymi oscyluje wokół 100usec dla 100Mb/s oraz 10usec dla 1GB/s.

Tak więc wartość 1usec otrzymana w przeprowadzonym pomiarze jest wystarczająca, aby aplikacje klienta oraz serwera mogły odpowiednio szybko pobrać dokładny czas i przypisać go do kolejnych pakietów. Uzyskałem w ten sposób pewność, iż użycie badanej karty zegarowej nie wprowadzi dodatkowych opóźnień (błędów) do przeprowadzanych pomiarów.

Na podstawie danych z pliku „clock_gps” narysowałem wykres, obrazujący czas dostępu do odbiornika GPS168PCI (patrz Rys.3.2).

0x01 graphic

Rys.3.2. Czas dostępu do karty GPS168PCI - wykres

Na jego podstawie można zauważyć, że czas dostępu do GPS168PCI wynosi około 1400usec (1,4msec). W przypadku wykonywanych pomiarów i wymagań związanych z tym parametrem, taka wielkość jest nie do zaakceptowania. Największa przepustowość, jaką można wtedy uzyskać wynosi około 900Kb/s, co kategorycznie przekreślałoby sens wykonywanych badań (przepustowości ok. 100Mb/s).

3.3 Pomiar fluktuacji czasu systemowego

3.3.1 Cel pomiaru

Celem pomiaru było oszacowanie zachowania zegara systemowego na komputerze w stosunku do wybranego wzorcowego źródła czasu oraz ustalenie przebiegu ewentualnych rozbieżności.

3.3.2 Sposób przeprowadzenia pomiaru

Pomiar fluktuacji czasu został przeprowadzony na komputerze wyposażonym w kartę zegarową, synchronizowaną przy pomocy systemu GPS.

Idea badania opiera się na odczytywaniu czasu systemowego oraz czasu karty zegarowej (źródło wzorcowe) przez określony czas, obliczaniu występujących różnic oraz ich zapamiętywaniu, a następnie narysowaniu na ich podstawie wykresu obrazującego fluktuację tej wielkości.

W napisanej w tym celu aplikacji, pobieranie obu wymienionych czasów występuje co 5 sekund. Wielkość systemowa odczytywana jest za pomocą funkcji gettimeofday(). Jedyny problem pojawia się w przypadku karty zegarowej. Wiadomo, że zawiera ona wbudowany, wewnętrzny 32-bitowy licznik, inkrementowany z każdym taktem sygnału 40MHZ (1 impuls odpowiada 0,25usec). Maksymalna wartość, jaką może uzyskać wynosi 232 (4294967296), po osiągnięciu której zliczanie odbywa się od 0. Sytuacja taka występuję co około 107 sekund. Kolejne pobierane wartości są lokalne w obrębie danej „sesji licznika”.

W przypadku czasu systemowego uzyskiwanego przez gettimeofday(), wartości są globalne, dlatego w celu otrzymania poprawnych różnic, konieczne jest zbudowanie zegara opartego o stany licznika.

W napisanej w tym celu aplikacji zaimplementowałem następujący algorytm realizujący powyższe zadanie (patrz Rys. 3.3).

0x01 graphic

Rys.3.3. Algorytm zegara opartego o stany karty zegarowej

Opis algorytmu:

  1. Wczytanie z karty zegarowej czasu t.

  2. Jeżeli jest on mniejszy niż czas t0 (czas odczytany podczas poprzedniej iteracji, na początku równy zero) wtedy wiadomo, że licznik przekroczył maksimum i zaczyna pracować od początku.

    1. W takiej sytuacji zmienne pamiętające aktualną liczbę sekund (clock_sec) oraz mikrosekund (clock_usec) zwiększone zostają odpowiednio o c_s (maksymalna liczba sekund, jaką może zapamiętać licznik) oraz c_u (maksymalna liczba mikrosekund). Są to stałe wielkości.

    2. Jeżeli zmienna clock_usec osiągnie lub przekroczy wartość 1000000, wtedy zwiększona zostaje liczba zapamiętanych sekund (clock_sec++) kosztem mikrosekund (clock_usec-=1000000).

    3. Do zmiennej t dodane zostaje 16, ponieważ maksymalna wartość licznika wynosi 232=(c_s*1000000+c_u)*40+16. Jedna mikrosekunda reprezentowana jest przez 40 taktów zegara, dlatego pozostała, niewykorzystana wartość przeniesiona zostaje do następnego odczytu.

  3. Zamiana aktualnego odczytu t na sekundy i mikrosekundy poprzez funkcję get_sec_usec(t, &clock_sec_t, &clock_usec_t). W ten sposób aktualny czas w oparciu o kartę zegarową wynosi: (clock_sec+clock_sec_t) sekund oraz (clock_usec_clock_usec_t) mikrosekund.

  4. Przejście do następnej iteracji.

Mając teraz wzorcowe źródło czasu utworzone w oparciu o kartę zegarową, można dokonać jego porównania z wielkością uzyskaną poprzez funkcję gettimeofday().

Operacja ta zostaje wykonana pomiędzy punktem 3 a 4, zapisując obliczoną różnicę do pliku „czasy” co 5 sekund (opóźnienie pomiędzy kolejnymi iteracjami).

Aplikacja została uruchomiona na jedną godzinę (720 pętli co 5 sekund).

Poniżej przedstawiłem fragment kodu realizujący opisane powyżej operacje.

for (i=0 ; i < 720 ; i++)

{

//(1)

gettimeofday(&time,0);

hs_pci_read_data(&t);

//(2)

if (t<t0) {

//(2a)

clock_sec += c_s;

clock_usec += c_u;

//(2b)

if ( clock_usec >= 1000000 ) {

clock_sec++;

clock_usec-=1000000;}

//( 2c)

t+=16;

}

//( 3)

get_sec_usec(t, &clock_sec_t, &clock_usec_t);

//porównanie czasu systemowego i czasu odczytanego z karty zegarowej oraz zapisanie różnicy do pliku

if ((clock_usec+clock_usec_t) >= 1000000)

{

fp=fopen("Czasy","a");

if (time.tv_usec >= ( clock_usec+clock_usec_t-1000000 ))

{

fprintf(fp,"%lu\t%lu\n",time.tv_sec-(clock_sec+clock_sec_t+1),time.tv_usec-(clock_usec+clock_usec_t-1000000));

}

else

{

fprintf(fp,"%lu\t%lu\n",time.tv_sec-(clock_sec+clock_sec_t+1)-1,time.tv_usec+1000000-(clock_usec+clock_usec_t-1000000));

}

close(fp);

}

else

{

fp=fopen("Czasy","a");

if (time.tv_usec >= (clock_usec+clock_usec_t) )

{

fprintf(fp,"%lu\t%lu\n\n",time.tv_sec - (clock_sec+clock_sec_t),time.tv_usec - (clock_usec+clock_usec_t) );

}

else

{

fprintf(fp,"%lu\t%lu\n",time.tv_sec - (clock_sec+clock_sec_t) - 1, time.tv_usec +1000000 - (clock_usec+clock_usec_t));

}

close(fp);

}

t0=t;

sleep(5);

}

3.3.3 Uzyskane wyniki

Na podstawie różnic zapisanych w pliku „czasy” narysowałem wykresy, przedstawiające fluktuację czasu systemowego (patrz Rys.3.4 oraz Rys.3.5).

0x01 graphic

Rys. 3.4. Fluktuacja czasy systemowego - wykres(1)

0x01 graphic

Rys.3.5. Fluktuacja czasu systemowego - wykres(2)

Pierwszy z wykresów przedstawia przebieg pomiaru dla pierwszej minuty, natomiast drugi ukazuje zachowanie w całym czasie trwania badania.

Jak można zauważyć, wartość różnicy wzrasta liniowo, proporcjonalnie do czasu pomiaru. Zakładając, iż karta zegarowa stanowi dokładny wzorzec (synchronizacja poprzez system GPS) można stwierdzić, iż rzeczywiście systemowe źródło czasu fluktuuje. Wykres nr 3.4 pokazuje, iż błąd ten ulega kumulacji z szybkością około 900usec co 5 sekund. Przyrost jest stały.

W ten sposób zostało pokazane jak niedokładne może być użycie do pewnych pomiarów funkcji gettimeofday(). Przykładowo, mierząc czas trwania operacji (szacowany na 5sekund), wynik obarczamy błędem wynoszącym około 1msec, rosnącym proporcjonalnie do czasy trwania pomiaru. Źródło jego nie tkwi jednak w niedokładności samej funkcji, a fluktuacji zegara systemowego, z którego pobiera ona wartość. Gettimeofday() dostarcza nam czas z dokładnością do mikrosekund, co zostało pokazane na poniższym wykresie (patrz Rys.3.6).

0x01 graphic

Rys. 3.6. Różnica kolejnych odczytów gettimeofday - wykres

W celu otrzymania powyższego wykresu napisałem aplikację, w której w pętli bez żadnych dodatkowych opóźnień, dokonałem serii odczytów czasów poprzez funkcję gettimeofday, zapisując je do pliku. Następnie policzyłem różnice pomiędzy kolejnymi wartościami, które przedstawiłem na wykresie (patrz Rys.3.6). Jak można zauważyć, otrzymane wartości wynoszą 0 lub 1usec, co potwierdza, iż dokładność funkcji gettimeofday jest równa 1usec.

3.4. Podsumowanie

Jako wniosek wypływający z dwóch pierwszych pomiarów, można potwierdzić słuszność wykorzystania do precyzyjnego odczytu czasów karty zegarowej, synchronizowanej przez odbiornik GPS. GPS168PCI pomimo, iż udostępnia taki sam, dokładny czas w dowolnym miejscu na kuli ziemskiej, jednak opóźnienie związane z jego uzyskaniem sięga 1,5msec co sprawia, iż niemożliwe jest jego wykorzystanie do bezpośredniego odczytu czasu. Problem ten nie występuje przy karcie zegarowej, która w czasie około 1usec jest nam w stanie dostarczyć żądany czas, dlatego została wykorzystana jako dokładne źródło czasu, synchronizowane przy wykorzystaniu odbiornika GPS168PCI.

Na podstawie testu fluktuacji czasu systemowego można zauważyć, że jego użycie jako źródła obarczone jest błędem proporcjonalnym do czasu trwania pomiaru (1msec na 5sec), co w wielu przypadkach wyklucza takie rozwiązanie.

4. Program pomiaru QoS sieci komputerowej

W celu przeprowadzenia dalszych testów w ramach pomiarów parametrów transmisji danych, napisałem w języku C pod system Linux aplikację testującą[5,6,7]. Umożliwia ona generowanie ruchu w oparciu o protokół TCP oraz UDP. Dla celów badań istnieje możliwość parametryzacji, obejmującej wybór numerów portów, ilości generowanych wiadomości, ich rozmiaru, wielkości buforów strony nadawczej oraz odbiorczej, a także przy wykorzystaniu TCP, ustawienie wybranych parametrów tego protokołu.

Program umożliwia zapisanie do plików wyników przeprowadzanych testów oraz generację podsumowań.

Dla wybranych pomiarów wymagających precyzyjnego odczytu czasu, pobiera odpowiednie wartości z karty zegarowej, synchronizowanej przy wykorzystaniu satelitarnego systemu nawigacyjnego GPS.

Celem zwiększenia przejrzystości oraz skalowalności aplikacji, pogrupowałem specyficzne funkcje w biblioteki. W ten sposób mogłem łatwiej dodawać, usuwać czy modyfikować kod implementacyjny.

Aby uniknąć kłopotliwej sytuacji związanej z kompilacją każdego modułu osobno, napisałem plik `makefile' w znaczący sposób ułatwiający realizację tych funkcji.

Jak wcześniej zostało wspomniane, aplikacja ma charakter modularny. Poniżej zamieściłem listę wszystkich, tworzących ją plików:

Opis rozpocznę od pliku `glowny.c'. Od niego zaczyna się start całego systemu, począwszy od inicjacji karty zegarowej, poprzez wczytania danych z pliku konfiguracyjnego, wybranie danego protokołu i przeprowadzenie dla niego testów. Stanowi on główną część całej aplikacji, do której w procesie kompilacji dołączane są pozostałe biblioteki.

Operacjom tym odpowiada następujący schemat blokowy (patrz Rys.4.1).

0x01 graphic

Rys.4.1. Plik `glowny.c' - algorytm działania

Poniżej przedstawiłem odpowiadający mu kod:

setup_read(&set,"setup"); (1)

(2)

build_device_names(atoi(arg1));

hs_pci_open_devices();

if ( !hs_pci_write_command(READ_TIME) )

{

perror("hs_pci_init//write_command");

exit(1);

}

(3)

switch (set.protocol)

{

case TCP :setup_write(&set); (4)

sd=tcp_init(set,&socket); (5)

test_tcp(sd, (struct sockaddr *) &socket,sizeof(socket),set.is_server, set.nmessages, set.msglen, set.delay); (6)

break;

case UDP : sd=udp_init(set,&socket); (7)

test_udp(sd, (struct sockaddr *) &socket,sizeof(socket),set.is_server, set.nmessages, set.msglen, set.delay); (8)

setup_write(&set); (9)

break;

default : { printf("unknown protocol: %i\n",set.protocol); break;}

}

We fragmencie tym na podstawie wartości pola set.protocol podejmowana jest decyzja, który protokół ma zostać zainicjowany wraz z przeprowadzeniem następnie odpowiedniego testu.

Z kolei plik `setup' zawiera parametry konfiguracyjne, na podstawie których aplikacja decyduje o wyborze protokołu, ustawieniu jego opcji, sposobie przeprowadzenia testów.

Dane parametry wprowadzane są przez użytkownika w postaci tekstowej przed uruchomieniem aplikacji. Przykładowa zawartość pliku wygląda następująco:

protocol:2;

local_address:127.0.0.2;

local_port:3001;

remote_address:127.0.0.1;

remote_port:3000;

is_server:0;

nmessages:10000;

msglen:1448;

delay:0;

tcp_nodelay:1;

tcp_mss:1460;

tcp_windowclamp:0;

so_sndbuf:65535;

so_rcvbuf:65535;

Podstawowa struktura pliku składa się z: nazwy_parametru : wartości_parametru;

Na podstawie nazwy_parametru aplikacja rozpoznaje daną zmienną, do której podstawia wartość odczytaną z wartości_parametru.

W Tabeli 4.1 opisałem znaczenie poszczególnych pól.

nazwa parametru

definicja

protocol

Określa protokół, który chcemy użyć do testów.

Możliwe wartości:

1 - TCP

2 - UDP

local_address

Określa adres lokalnego interfejsu uczestniczącego w przekazywaniu ruchu.

Przykładowa wartość:

127.0.0.1

local_port

Określa lokalny port uczestniczący w przekazywaniu ruchu.

Przykładowa wartość:

3000

remote_address

Określa adres interfejsu uczestniczącego w przekazywaniu ruchu na przeciwnej stacji.

Przykładowa wartość:

127.0.0.2

remote_port

Określa port uczestniczący w przekazywaniu ruchu na przeciwnej stacji.

Przykładowa wartość:

3001

is_server

Określa czy dana stacja pełni rolę klienta czy serwera.

Możliwe wartości:

0 - klient

1 - serwer

nmessages

Określa liczbę wysyłanych/odbieranych wiadomości.

Przykładowa wartość:

20000

msglen

Określa rozmiar danych zamykanych w warstwie czwartej.

Przykładowa wartość:

1448

nazwa parametru

definicja

delay

Określa opóźnienie pomiędzy kolejnymi, wysyłanymi pakietami.

Przykładowa wartość:

10000

tcp_nodelay

Opcja TCP - określa stan algorytmu Nagle'a.

Możliwe wartości:

0 - włączony

1 - wyłączony

tcp_mss

Opcja TCP - określa maksymalny rozmiar segmentu dla warstwy transportowej.

Przykładowa wartość:

1460

tcp_windowclamp

Opcja TCP - określa wielkość maksymalnego rozgłaszanego okna.

Przykładowa wartość:

100000

so_sndbuf

Określa rozmiar bufora nadawczego.

Przykładowa wartość:

100000

so_rcvbuf

Określa rozmiar bufora odbiorczego.

Przykładowa wartość:

100000

Tabela 4.1. Opis pól pliku setup

Plik `makefile` ułatwia kompilację całości aplikacji. Na początku tworzy na podstawie plików źródłowych pliki obiektowe, a następnie łączy je w całość, dając ostatecznie program główny o nazwie `glowny'. Umożliwia również usunięcie wszystkich utworzonych plików obiektowych.

Poniżej zamieszczam jego strukturę:

PRG=glowny

LIBPATH=./biblioteki

INCLUDE=./biblioteki

OBJS = $(LIBPATH)/timef.o $(LIBPATH)/setup.o $(LIBPATH)/tcp.o $(LIBPATH)/udp.o glowny.o $(LIBPATH)/test.o

LIBSRC= $(LIBPATH)/timef.c $(LIBPATH)/tcp.c $(LIBPATH)/setup.c $(LIBPATH)/test.c $(LIBPATH)/udp.c

SRC=glowny.c

all: $(OBJS)

gcc -o $(PRG) $(OBJS)

$(OBJS):

gcc -c $(LIBSRC)

cp *.o $(LIBPATH)

rm *.o

gcc -c $(SRC) -I$(INCLUDE)

clean:

rm -rf $(PRG) $(OBJS)

Biblioteka `setup.c' realizuje dwa główne zadania: odczytanie parametrów z pliku konfiguracyjnego oraz wypisanie ich na ekran.

Zostały one zgrupowane w następujących funkcjach:

int setup_read(setup_struct *s , char *filename) - powoduje wczytanie z pliku o nazwie określonej przez zmienną *filename odpowiednich parametrów oraz zapamiętanie ich w strukturze setup_struct.

int setup_write(setup_struct *s) - powoduje wyprowadzenie na ekran zawartości struktury setup_struct.

setup_struct wygląda następująco:

typedef struct{

int is_server;

int msglen;

int tcp_nodelay;

int tcp_mss;

int tcp_windowclamp,so_sndbuf,so_rcvbuf,protocol;

long nmessages;

long delay;

char* local_address;

char* local_port;

char* remote_address;

char* remote_port;

} setup_struct;

i zdefiniowana jest w pliku `setup.h'.

Plik `tcp.c' umożliwia zainicjowanie struktury gniazda, ustawienie parametrów TCP dla danej sesji oraz wyprowadzenie na ekran ich zawartości.

Realizowane jest to przez poniższe funkcje:

int tcp_init(setup_struct set, struct sockaddr_in *sa) - inicjuje gniazdo dla danego połączenia reprezentowane przez wskaźnik sa, ustawia związane z nim parametry na podstawie wartości pobranych z struktury set, ostatecznie zwracając identyfikator gniazda będącego już w stanie ESTABLISHED. Na podstawie parametru set.is_server rozróżnia czy powyższe funkcje realizowane są dla klienta czy serwera.

int set_tcp_socket_opt(int sd,setup_struct set) - powoduje ustawienie dla gniazda reprezentowanego przez identyfikator sd, wybranych parametrów TCP określonych poprzez strukturę set. Wywoływana na początku inicjacji gniazda, w funkcji tcp_init(). Wyjątek stanowi parametr set.tcp_windowclamp, który ustawiany jest bezpośrednio w tcp_init(), dla gniazda będącego w stanie ESTABLISHED.

int show_tcp_socket_opt(int sd) - funkcja ta powoduje wyprowadzenie na ekran parametrów gniazda, określonego przez identyfikator sd. W ten sposób można sprawdzić jego domyślne ustawienia czy stan już po nawiązaniu połączenia. Wywoływana jest w tcp_init().

Plik `udp.c' spełnia podobne zadania jak `tcp.c' z tym, że wykonuje je dla protokołu UDP. Zawiera następujące funkcje:

int udp_init(setup_struct set, struct sockaddr_in *sa) - inicjuje gniazdo dla transmisji przy wykorzystaniu protokołu UDP, reprezentowane przez wskaźnik sa, ustawia związane z nim parametry na podstawie wartości pobranych ze struktury set, ostatecznie zwracając identyfikator gniazda. Na podstawie parametru set.is_server rozróżnia czy powyższe funkcje realizowane są dla klienta czy serwera.

int set_udp_socket_opt(int sd,setup_struct set) - powoduje ustawienie dla transmisji UDP rozmiaru buforów: odbiorczego i nadawczego (jako jedynych parametrów). Jest wywoływana na początku inicjacji gniazda, w funkcji udp_init().

int show_udp_socket_opt(int sd) - powoduje wyprowadzenie na ekran rozmiarów obu buforów. W ten sposób można sprawdzić ich domyślne wartości oraz stan po wprowadzeniu własnych ustawień.

Plik `test.c' (patrz Rys.4.2) umożliwia przeprowadzenie odpowiednich testów dla danego protokołu, a następnie przetworzenie i zapisanie otrzymanych rezultatów do pliku. W skład jego wchodzi następująca funkcja:

int test_tcp(int socket, struct sockaddr *sa ,socklen_t sa_len,int server, long int nmessages,int msglen, int sleep) - w zależności od wartości parametru

server, umożliwia odbieranie(serwer) lub generowanie(klient) nmessages pakietów o rozmiarze msglen, przy wykorzystaniu protokołu TCP.

0x01 graphic

Rys.4.2. Plik `test.c' - algorytm działania (1)

Poniżej zamieściłem algorytm operacji wykonywanych przez serwer (patrz Rys.4.3).

0x01 graphic

Rys.4.3. Plik `test.c' - algorytm działania (2)

Poprzez wykorzystanie parametru gniazda SO_RCVTIME0(1) serwer automatycznie przerywa proces nasłuchiwania, jeżeli w ciągu 5 sekund nie pojawią się nowe dane.

Informacje są przekazywane w postaci struktury:

typedef struct {

long int sequence;

unsigned long time;

char dummy[DUMMY];

} test_data;

gdzie:

sequence - numer wysyłanego pakietu,

time - czas określający moment wygenerowania po stronie nadawczej (wykorzystywane przy UDP),

dummy - dopełnienie całej struktury do wymaganego rozmiaru.

Na początku pętli odczytującej zeruję całą strukturę (2). Następnie przeprowadzam nasłuch gniazda (3). W przypadku pojawienia się nowych danych, pobieram je a następnie odczytuje stan karty zegarowej, w celu otrzymania precyzyjnego czasu (5). Dla pierwszej iteracji zapamiętuję wartość w osobnej zmiennej. W kolejnej operacji zliczam aktualnie pobraną liczbę danych.

W przypadku nieotrzymania nowych informacji w przeciągu 5 sekund, pętla jest przerywana. Następnie wyprowadzam na ekran informacje o aktualnych parametrach gniazda (7) oraz uzyskaną przepustowość (8).

Poniżej zamieściłem fragment kodu wykonujący opisane operacje:

setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)); (1)

do

bzero(&data,sizeof(data)); (2)

result = recv(socket, (char *)&data, msglen, 0) ; (3)

hs_pci_read_data(&time); (5)

if (data.sequence==1) timestart=time;

if (result<=0)

{

perror("test::recvfrom()");

break;

}

bytes+=result;(6)

}

while ( 1 );

show_tcp_socket_opt(socket); (7)

printf("Bity odebrane: %lu**przepustowosc(b/sec): %.0f\n",bytes*8,(bytes*8)/((time-timestart)/40000000)); (8)

W przypadku funkcji wykonywanych przez stronę klienta, schemat jest następujący (patrz Rys.4.4):

0x01 graphic

Rys.4.4. Plik `test.c' - algorytm działania (3)

Poniżej zamieściłem odpowiadający mu kod:

for (i=1; i <= nmessages; i++) (1)

{

data.sequence = i; (2)

result = sendto(socket, (char*)&data , msglen,0,sa,sa_len); (3)

if (result<0)

{

perror("test::sendto()");

}

for (k=0;k< sleep ;k++); (4)

}

Głównym celem funkcji związanych z testowaniem TCP jest wygenerowanie odpowiedniego ruchu z możliwością jego parametryzacji oraz obliczenia przepustowości.

Wszelkie potrzebne dane gromadzone są przy wykorzystaniu programu tcpdump, a następnie analizowane przez napisane w tym celu krótkie aplikacje, których charakterystykę zawarłem wraz z opisem pomiarów.

W przypadku funkcji związanych z testowaniem przy wykorzystaniu protokołu UDP (patrz Rys.4.5), sytuacja wygląda inaczej. W tym przypadku główny cel stanowiło oszacowanie opóźnień pomiędzy CERN-em a CYFRONET-em w obu kierunkach oraz określenie ilości pakietów gubionych w zależności od intensywności generowanego ruchu. Potrzebne dane oraz ich analiza mogła zostać przeprowadzona w samej aplikacji, dlatego funkcje związane z protokołem UDP różnią się od opisanych poprzednio.

Jedna z nich wchodząca w skład pliku `test.c' wygląda następująco:

int test_udp(int socket, struct sockaddr *sa ,socklen_t sa_len,int server, long int nmessages, int msglen, int sleep)- W zależności od wartości parametru

server, umożliwia odbieranie(serwer) lub generowanie(klient) nmessages pakietów o rozmiarze msglen przy wykorzystaniu protokołu UDP.

0x01 graphic

Rys.4.5. Plik `test.c' - algorytm działania (4)

Poniżej przedstawiłem algorytm strony serwera (patrz Rys.4.6).

0x01 graphic

Rys.4.6. Plik `test.c' - algorytm działania (5)

Odpowiada mu następujący fragment kodu:

for (i=0; i< TIMES ; i++) times[i]=0; (1)

for (i=0; i< TIMES_VAL ; i++) times_val[i]=0;

fd=fopen("stats","w"); (2)

if (fd<0)

{

perror("fopen():");

exit (-1);}

setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)); ( 3)

puts("waiting for data");

do

{

bzero(&data,sizeof(data)); (4)

result = recv(socket, (char *)&data, msglen, 0) ; (5)

if (result<=0)

{

perror("test::recvfrom()");

break;

}

hs_pci_read_data(&tv1); (6)

if (data.sequence==1) tv0=tv1;

nreads++; (7)

bytes+=result;

times_val[data.sequence-1]=(int)((tv1-data.time)/40000000) (8)

}

while ( 1 );

(9)

printf("Bity odebrane: %u *** przepustowosc(b/sec): %.0f\n",bytes*8,(bytes*8)/((tv1-tv0)/40000000));

printf("Lost %d * \n",nmessages-nreads);

fprintf(fd,"Bity odebrane: %u *** przepustowosc(b/sec): %.0f\n",bytes*8,(bytes*8) /((tv1-tv0)/40000000));

fprintf(fd,"Lost %d * \n",nmessages-nreads);

fclose(fd);

(10)

for (i=0;i < nmessages ; i++)

{

if ( (times_val[i]) >= (TIMES - 1 + OFFSET ) )

{

times[TIMES-1]++;

}

else

if ( (times_val[i]) <= (OFFSET ) )

{

times[0]++;

}

else

times[times_val[i] - OFFSET ]++;

}

fd=fopen("./results/timeshist","w"); (11)

(12)

for (i=0; i< TIMES ; i++)

{

fprintf(fd,"%d\t%d\n",i+OFFSET,times[i]);

}

fclose(fd);

W przypadku operacji wykonywanych przez stronę klienta, schemat jest następujący (patrz Rys.4.7).

0x01 graphic

Rys.4.7. Plik `test.c' - algorytm działania (6)

Poniżej zamieściłem odpowiadający mu kod:

for (i=1; i <= nmessages; i++) (1)

{

data.sequence = i; (2)

hs_pci_read_data(&data.time); (3)

result = sendto(socket, (char*)&data , msglen,0,sa,sa_len); (4)

if (result<0)

{

perror("test::sendto()");

}

for (k=0;k< sleep ;k++); (5)

}

Kolejny plik `clock_gps.c', zawiera zbiór funkcji umożliwiających zainicjowanie karty zegarowej, synchronizowanej przez system GPS, pobranie precyzyjnego czasu oraz wysłanie za pośrednictwem magistrali PCI jednej z komend (patrz Tabela 2.5).

W pliku tym zdefiniowane zostały następujące funkcje:

void build_device_names(int i) - każda zainstalowana karta zegarowa ma swój numer, począwszy od 1,2 itd. Funkcja ta umożliwia utworzenie odwołania do pliku w systemie, reprezentującego dane urządzenie.

sprintf(hslclock,"/dev/hslclock%d",i-1);

sprintf(hslcookie,"/dev/hslcookie%d",i-1);

printf(" using devices >> %s,%s\n ", hslclock, hslcookie);

void hs_pci_open_devices() - powoduje zainicjowanie karty zegarowej, poprzez otwarcie plików za pośrednictwem, których wysyłamy lub pobieramy informacje.

fclock=open(hslclock , O_RDONLY);

fcookie=open(hslcookie , O_WRONLY);

int hs_pci_read_data(unsigned long *data) -umożliwia pobranie danych z karty zegarowej. W zależności od trybu, w jakim znajduje się w danym momencie, informacje te mogą zawierać albo aktualny czas albo czas z wektora testującego (patrz Tabela 2.5).

result=read(fclock,data,sizeof(*data));

return result==4;

int hs_pci_write_command(unsigned long command) -umożliwia wysłanie poprzez magistralę PCI odpowiedniej komendy. Np. polecenie hs_write_command (READ_TIME) powoduje ustawienie karty zegarowej w tryb, w którym można pobierać aktualny czas.

result=write(fcookie,&command,sizeof(command));

return result==4;

Wszystkie te funkcje wywoływane są w pliku `glowny.c'.

5. UDP

5.1 Wstęp

W kolejnym przeprowadzonym pomiarze zmierzyłem opóźnienia pomiędzy CERN-em a CYFRONET-em oraz ustaliłem ilości pakietów gubionych w zależności od rozmiaru przesyłanych danych oraz intensywności generowanego ruchu, w obu kierunkach niezależnie. Testy wykonałem w oparciu o protokół UDP, który ze względu na niskie, dodatkowe narzuty czasowe wprowadzane przez wewnętrzne mechanizmy w warstwie transportowej, pozwala uzyskać wyniki nie odbiegające w znaczący sposób od rzeczywistości.

5.2 Charakterystyka UDP

UDP (User Datagram Protocol) jest prostym protokołem warstwy transportowej[8], w którym dane procesu aplikacji są zamykane w postaci datagramu. W przeciwieństwie do strumieniowego TCP, gdzie jeden zapis nie determinuje tego, co jednorazowo zostanie odczytane po drugiej stronie, informacje przesyłane przez UDP mają wyraźny początek i koniec. W takiej też postaci są odbierane.

UDP nie zapewnia niezawodnego dostarczenia danych. Generując datagram nie mamy gwarancji, że zostanie on poprawnie odczytany po drugiej stronie. Jeżeli aplikacja wymaga takiej cechy, wówczas musimy sami zaimplementować odpowiednie składniki lub wykorzystać TCP.

UDP jest protokołem bezpołączeniowym. Oznacza to, iż przed wysyłaniem danych nie musi zostać nawiązane połączenie pomiędzy obiema stronami. Przykładowo klient UDP po utworzeniu i sparametryzowaniu gniazda, może bezpośrednio wysyłać datagramy na różne adresy i porty. W tej sytuacji nie następuje przypisanie do danego połączenia z konkretnym hostem docelowym, co ma miejsce przy TCP. Serwer UDP po utworzeniu i skonfigurowaniu gniazda może odbierać na nim dane z różnymi parametrami źródłowymi.

UDP nie zapewnia również, że wysyłane pakiety nie ulegną fragmentacji. Leży to w gestii aplikacji, aby dane przesyłane do niższej warstwy miały odpowiedni rozmiar, który po dodaniu nagłówków, nie przekroczy minimalnego MTU ścieżki.

5.3 Budowa datagramu UDP

Dane aplikacji przy użyciu protokołu UDP zamykane są do datagramu, przy czym w przeciwieństwie do TCP, nie następuje ich wewnętrzny podział. Jednostka informacji UDP składa się z nagłówka oraz danych (patrz Rys.5.1).

0x01 graphic

Rys.5.1. Budowa datagramu UDP (1)

Rozmiar nagłówka jest stały i wynosi 8B. Ponieważ całość datagramu może zajmować 655535B, dlatego dane aplikacji minimalnie mają 0B, natomiast maksymalnie 65527B.

Szczegóły przedstawiłem na Rysunku 5.2 oraz w Tabeli 5.1.

0x01 graphic

Rys.5.2. Budowa datagramu UDP (2)

Nazwa pola

Opis

Rozmiar

source port

Określa port źródłowy, identyfikujący odbiorcę warstwy wyższej po stronie nadawczej.

2B

destination port

Określa port źródłowy, identyfikujący odbiorcę warstwy wyższej po stronie docelowej.

2B

length

Określa rozmiar całego datagramu w bajtach, włączając nagłówek oraz dane. Maksymalnie 65535B.

2B

checksum

Zawiera wartość CRC obliczoną dla nagłówka datagramu i danych. Na jego podstawie istnieje możliwość weryfikacji poprawności przez stronę odbierającą, która osobno przelicza wartość CRC i następnie porównuje z tą zapisaną w polu checksum.

2B

data

Dane przesłane z warstwy wyższej.

0...65527B

Tabela 5.1. Opis pól datagramu UDP

5.4 Przepływ informacji w UDP

Na poniższym rysunku przedstawiłem przepływ informacji przy wykorzystaniu protokołu UDP z aplikacji w jednym systemie do aplikacji w drugim (patrz Rys. 5.3).

0x01 graphic

Rys.5.3. Przepływ informacji w UDP

Aplikacja z własnego bufora wykonuje zapis do bufora nadawczego gniazda UDP, określonego przez parametr SO_SNDBUF, stanowiącego w rzeczywistości górny rozmiar bajtów, jaki może zostać do niego przesłany. Jeżeli aplikacja zapisze więcej danych niż określa to ten parametr, wówczas zostaje zwrócony błąd. Ponieważ UDP jest protokołem zawodnym, dlatego też nie musi przechowywać kopii zapasowej wysyłanych informacji.

UDP po otrzymaniu danych aplikacji zamyka je w datagram, dodając nagłówek, obliczając CRC a następnie przekazując go do warstwy sieciowej. Tam IP tworzy pakiet, determinuje wychodzący interfejs, wykonuje ewentualną fragmentację i wysyła go do warstwy sprzętowej, gdzie po zamknięciu w ramkę, zostaje ustawiony w kolejce wyjściowej. W przypadku jej przepełnienia i odrzucenia danych, do UDP wysyłana jest informacja o zaistniałej sytuacji.

Po dotarciu do hosta docelowego proces odbywa się w kierunku przeciwnym. Po odebraniu ramki przez interfejs docelowy, zostaje ona umieszczona w buforze karty. W przypadku braku wystarczającej ilości miejsca, następuje jej odrzucenie.

Z warstwy sprzętowej, dane ramki zostają przesłane do protokołu warstwy sieciowej, skąd po ewentualnej defragmentacji, już w postaci gotowego datagramu trafiają do bufora odbiorczego gniazda, określonego przez parametr SO_RVFBUF. Następnie właściwe informacje po otrzymaniu żądania z procesu aplikacji, zostają przez nią pobrane.

6. Pomiar opóźnienia i ilości pakietów zgubionych z wykorzystaniem protokołu UDP

6.1 Cel pomiaru

Celem pomiaru było oszacowanie opóźnienia na trasie CYFRONET-CERN oraz CERN-CYFRONET w zależności od intensywności generowanego ruchu oraz rozmiaru przesyłanych pakietów. Do badań został wykorzystany protokół UDP ze względu na mniejsze, dodatkowe narzuty czasowe warstwy transportowej. Jest on pozbawiony mechanizmów zapewniających niezawodne dostarczanie danych (zawodność), kontrolujących i zarządzających połączeniem (bezpołączeniowość), które powodują nadmiarowe obciążenie sieci, generując dodatkowy ruch, wymagający przetworzenia i zanalizowania, przez co wprowadzane są kolejne opóźnienia, przyczyniające się ostatecznie do niedokładności uzyskiwanych wyników. UDP pozbawione tych cech, pozwala uzyskać rezultaty zbliżone do rzeczywistych wartości. Operacja odczytywania i pobierania czasów odbywa się na poziomie aplikacji, dlatego tak ważne jest, aby opóźnienia wprowadzane przez warstwy niższe były jak najmniejsze.

Dodatkowo, przy okazji powyższych pomiarów dokonałem oszacowania ilości pakietów gubionych w zależności od ich rozmiaru, a także intensywności generowania.

6.2 Sposób przeprowadzenia pomiaru

Pomiar został wykonany na drodze CERN-CYFRONET, dla obu kierunków, przy zaalokowanym kanale pomiędzy Poznaniem a Krakowem.

Celem uzyskania odpowiednich wyników wykorzystałem aplikację pomiarową (patrz rozdział 4), generując ruch w oparciu o protokół UDP.

Po wczytaniu danych zapisanych w plikach konfiguracyjnych (patrz Tabela 6.1), programowo ustawiłem odpowiadające im parametry na komputerze nadawczym i odbiorczym.

UDP

KLIENT/SERWER

SERWER/KLIENT

CERN

CYFRONET

rozmiar pakietu

1500B/100B

1500B/100B

liczba pakietów

20 000

20 000

bufor odbiorczy

100 000B

100 000B

bufor nadawczy

100 000B

100 000B

Tabela 6.1. Konfiguracja klienta i serwera - pomiar UDP

Przy wykorzystaniu aplikacji wysyłam pakiety o rozmiarze 1500B oraz 100B, z różną częstotliwością. Ich całkowitą liczbę ustawiłem na 20 000.

Po stronie nadawczej do każdego pakietu przed jego wysłaniem wstawiam czas pobrany z karty zegarowej. Na hoście docelowym po odebraniu danych również odczytuję wartość zegara, porównując ją z wielkością otrzymaną, a obliczoną różnicę zapisuję do tablicy. Po odebraniu ostatniego pakietu, analizuję zapamiętane wyniki, celem uzyskania danych do histogramu opóźnień, które ostatecznie zapisuję do pliku. Komputer odbiorczy umożliwia wygenerowanie dodatkowych informacji, takich jak: liczba pakietów odebranych, liczba pakietów zgubionych, uzyskana przepustowość, średnia wartość opóźnienia, które zapamiętuję w pliku.

6.3 Uzyskane wyniki

Na podstawie otrzymanych wyników, narysowałem wykresy przedstawiające histogram wartości opóźnień pakietów na drodze CYFRONET-CERN (patrz Rys.6.1, Rys.6.2, Rys.6.3, Rys.6.4, Rys.6.5, Rys.6.6).

0x01 graphic

Rys. 6.1. Pomiar opóźnienia na drodze CYFRONET-CERN - wykres (1)

0x01 graphic

Rys. 6.2. Pomiar opóźnienia na drodze CYFRONET-CERN - wykres (2)

0x01 graphic

Rys. 6.3. Pomiar opóźnienia na drodze CYFRONET-CERN - wykres (3)

0x01 graphic

Rys. 6.4. Pomiar opóźnienia na drodze CYFRONET-CERN - wykres (4)

0x01 graphic

Rys. 6.5. Pomiar opóźnienia na drodze CYFRONET-CERN - wykres (5)

0x01 graphic

Rys. 6.6. Pomiar opóźnienia na drodze CYFRONET-CERN - wykres (6)

W Tabeli 6.2 zebrałem i podsumowałem otrzymane rezultaty.

liczba

wysłanych

pakietów

rozmiar

pakietu

przepustowość

liczba zgubionych

pakietów

średnie

opóźnienie

20 000

100B

175Kb/s

22 (0.1%)

31 740usec

1,3Mb/s

21(0.1%)

31 731usec

16Mb/s

23(0.1%)

31 750usec

20 000

1500B

2,6Mb/s

128 (0.6%)

32 021usec

30Mb/s

110(0.6%)

32 015usec

80Mb/s

1028(5%)

32 027usec

Tabela 6.2. Wyniki pomiarów opóźnienia na drodze CYFRONET-CERN

Wartość opóźnienia na kierunku CYFRONET-CERN wynosi około 32msec, przy czym dla pakietów o rozmiarze 100B jest nieznacznie mniejsza, co w stosunku do całości nie ma jednak dużego znaczenia (różnica około 1%).

Tak więc można stwierdzić, iż opóźnienie w tym przypadku nie zależy od intensywności generowanego ruchu oraz rozmiaru wysyłanych danych.

Rozbieżności natomiast pojawiają się przy ilości zgubionych pakietów. Widzimy wyraźnie, iż wpływ na ten parametr mają oba czynniki.

Poniżej przedstawiłem wykresy obrazujące liczbę pakietów zgubionych w zależności od uzyskiwanej przepustowości (patrz Rys. 6.7 oraz Rys.6.8)

0x01 graphic

Rys.6.7. Liczba pakietów zgubionych na drodze CYFRONET-CERN - wykres(1)

0x01 graphic

Rys.6.8. Liczba pakietów zgubionych na drodze CYFRONET-CERN - wykres(2)

Jak można zauważyć, liczba pakietów zgubionych zależy zarówno od rozmiaru przesyłanych danych jak i intensywności ruchu.

Dla pakietów 100-bajtowych ginie średnio około 20 (0.1%), bez względu na uzyskiwaną przepustowość.

Przy rozmiarze 1500 bajtów liczba ta wyraźnie zależy od intensywności generowanego ruchu, osiągając wartość 1024 (5%) dla 80Mb/s.

Tak więc parametr ten jest wyraźnie gorszy dla pakietów o większych rozmiarach. Już dla przepustowości 2,6Mb/s ginie 128 (0.6%), natomiast przy mniejszych, dla 16Mb/s, wartość ta ciągle wynosi 23 (0.1%) pomimo, iż w tym przypadku liczba pakietów wysłanych w ciągu sekundy dla tej samej przepustowości jest większa.

Poniżej zamieściłem wykresy przedstawiające histogramy wartości opóźnień pakietów na drodze CERN-CYFRONET (patrz Rys.6.9, Rys.6.10, Rys.6.11, Rys.6.12, Rys.6.13).

0x01 graphic

Rys. 6.9. Pomiar opóźnienia na drodze CERN-CYFRONET - wykres (1)

0x01 graphic

Rys. 6.10. Pomiar opóźnienia na drodze CERN-CYFRONET - wykres (2)

0x01 graphic

Rys. 6.11. Pomiar opóźnienia na drodze CERN-CYFRONET - wykres (3)

0x01 graphic

Rys. 6.12. Pomiar opóźnienia na drodze CERN-CYFRONET - wykres (4)

W Tabeli 6.3 zebrałem i podsumowałem otrzymane rezultaty.

liczba

wysłanych

pakietów

rozmiar

pakietu

przepustowość

liczba zgubionych

pakietów

średnie

opóźnienie

20 000

100B

165Kb/s

0

31 750usec

1,5Mb/s

0

31 725usec

20 000

1500B

1,6Mb/s

0

32 018usec

32Mb/s

0

32 006usec

Tabela 6.3. Wyniki pomiarów opóźnienia na drodze CERN-CYFRONET

Tak jak w poprzednim pomiarze, opóźnienie oscyluje wokół 32msec, nie zależąc w znaczący sposób od rozmiaru danych czy intensywności ich generowania.

Różnice pojawiają się przy ilości pakietów zgubionych. Na drodze CERN-CYFRONET prawie wszystkie dane dotarły do celu. Nieznaczna ich liczba zaginęła tylko przy dużych przepustowościach, co w porównaniu do kierunku przeciwnego (1028 pakietów straconych) jest wynikiem bardzo dobrym i nie mającym znaczącego wpływu na poprawność transmisji.

Na podstawie wykonanych pomiarów można stwierdzić, iż badana trasa ma charakter asymetryczny. Wynika to z faktu różnej ilości pakietów zgubionych podczas transmisji. Pod tym względem wyraźnie lepsze parametry występują na kierunku CERN-CYFRONET niż w przeciwnym.

7. TCP

7.1 Wstęp

W kolejnych pomiarach zbadałem wydajność protokołu TCP (Transmission Control Protocol). Testy rozpocząłem od jego optymalizacji, tak aby maksymalnie wykorzystać przepustowość na badanej trasie. Następnie dla ustalonych parametrów rozpocząłem głębszą analizę charakteru generowanego ruchu TCP, obejmującą:

7.2 Charakterystyka TCP

TCP jest połączeniowym, niezawodnym, strumieniowym i pełnodupleksowym protokołem warstwy transportowej[8].

Połączeniowy oznacza, iż przy próbie przesłania danych pomiędzy dwoma węzłami, wcześniej musi zostać nawiązane połączenie. Następnie po jego pomyślnym zainicjowaniu, może zaistnieć obustronna komunikacja, aż do momentu jej przerwania przez jedną ze stron lub zdarzenie losowe (np. fizyczne uszkodzenie połączenia).

TCP zapewnia również niezawodne dostarczenie danych. Kiedy jeden z węzłów transmituje do drugiego pakiety wymaga wówczas, aby ten przesłał mu potwierdzenie ich odebrania. W przypadku jego nieotrzymania (zaginięcie danych lub samego ACK), TCP automatycznie retransmituje segment, ponownie oczekując na potwierdzenie, tym razem jednak przez dłuższy okres czasu. Po pewnej ilości prób (w zależności od implementacji), ostatecznie następuje przerwanie transmisji danych i zerwanie połączenia. TCP wykorzystuje tzw. estymację RTT w celu oszacowania czasu, jaki musi w przybliżeniu oczekiwać na potwierdzenie. Obliczenia są dynamicznie modyfikowane w trakcie całej transmisji, a to ze względu na fakt, iż RTT może być zmienne w czasie, np. ze względu na zaistniałe zatory.

TCP wprowadza numerację wysyłanych danych, poprzez przypisanie tzw. numeru sekwencyjnego dla konkretnej partii informacji. W ten sposób można jednoznacznie zidentyfikować dowolny bajt i ustalić jego właściwe położenie w całym strumieniu danych. Przykładowo, jeżeli strona nadawcza wytransmituje dwa segmenty, pierwszy z bajtami o numerach sekwencyjnych 1-1448 oraz drugi o numerach 1449-2896 a odbiorca otrzyma je w innej kolejności (np. w wyniku zmiany trasy routowania w sieci), wtedy na podstawie tego mechanizmu identyfikacji, TCP może je właściwie posegregować przed przekazaniem do warstwy wyższej. W przypadku otrzymania danych o powtarzających się numerach sekwencyjnych (duplikacja), strona odbiorcza rozpoznaje taką sytuację, odrzucając zbędny segment.

TCP wprowadza mechanizm kontroli przepływu, poprzez zastosowanie tzw. okien. Okno jest rozgłaszane przez stronę odbiorczą i wskazuje, jaką liczbę bajtów może ona pomieścić w konkretnym momencie w swoim buforze. Dla hosta nadawczego oznacza to rozmiar danych, jakie może wytransmitować, bez oczekiwania w międzyczasie na potwierdzenie. W rzeczywistości sytuacja wygląda trochę inaczej, ponieważ po stronie nadawczej uruchomiony jest algorytm, który również ustala własne okno (tzw.cwnd - Congestion WiNdow) i ostatecznie to właściwe stanowi minimum rozgłoszonego przez stronę odbiorczą oraz obliczonego przez nadawczą. Rozmiar okna jest zmienny w czasie, w zależności od intensywności generowania pakietów, szybkości ich odbierania przez stronę docelową, ilości retransmisji oraz momentu transmisji (slow start oraz congestion avoidance - patrz rozdział 7.6).

TCP sprawdza również poprawność otrzymanych danych poprzez mechanizm detekcji błędów CRC. Odpowiednie pole występuje w segmencie i zawiera wartość specjalnej funkcji obliczoną dla nagłówka oraz pozostałych informacji otrzymanych z warstw wyższych. Strona odbiorcza po otrzymaniu danych, oblicza własną wartość CRC i porównuje z tą zapisaną. W przypadku różnicy taki segment jest odrzucany, a host nadawczy w sytuacji nieotrzymania żądanego potwierdzenia w danym czasie, inicjuje retransmisję.

TCP jest protokołem strumieniowym, tzn. transmisja bajtów odbywa się w sposób ciągły. Strona nadawcza generuje strumień danych, natomiast węzeł odbiorczy go pobiera. Nie ma w nim znaczników, rozgraniczających dane z kolejnych transmisji. Przykładowo informacje mogą być wysłane w dwóch zapisach po dziesięć bajtów lub jednym dwudziestobajtowym. Host odbiorczy widzi dane jako strumień i może pobrać je w jednej próbie lub np. czterech po pięć bajtów. Dla TCP nie ma to znaczenia. Na poziomie warstwy transportowej nie przeprowadzana jest interpretacja odebranych danych. Rozróżnienie czy są to informacje binarne, tekstowe czy innego typu odbywa się na poziomie warstw wyższych.

TCP zapewnia również komunikację pełnodupleksową, tzn. równolegle może odbierać i transmitować dane. W tym celu przechowuje osobno informacje o każdym kierunku komunikacyjnym, związane z numerami sekwencyjnymi, rozmiarami okien oraz innymi parametrami. Oczywiście, aby w rzeczywistości komunikacja była pełnodupleksowa, warstwy niższe również muszą spełniać ten warunek.

7.3 Budowa segmentu TCP

Dane aplikacji zamykane w warstwie transportowej przy pomocy protokołu TCP dzielone są na porcje informacji, których rozmiar określa parametr MSS (Maximum Segment Size). W nowszych implementacjach TCP istnieje mechanizm pozwalający określić minimalną wartość MTU na całej trasie, tzw. MTU path discovery. W takiej sytuacji MSS określa wzór:

MSS <= MTU - 40 - rozmiar_opcji_TCP

Dzięki „paczkowaniu” bajtów aplikacji uzyskujemy pewność, iż IP w warstwie sieciowej nie zastosuje fragmentacji.

Podstawowa jednostka informacji w TCP nosi nazwę segmentu. Składa się nagłówka oraz danych aplikacji (patrz Rys.7.1).

0x01 graphic

Rys.7.1. Budowa segmentu TCP (1)

Rozmiar nagłówka standardowo jest równy 20B, jednak w przypadku, gdy używane są opcje TCP, wówczas może być większy (np. timestamp zajmuje dodatkowe 12B). Rozmiar danych aplikacji określa parametr MSS.

Szczegóły budowy segmentu przedstawiłem na Rysunku 7.2 oraz w Tabeli 7.1.

0x01 graphic

Rys.7.2. Budowa segmentu TCP (2)

Nazwa pola

Opis

Rozmiar

source port

Określa port źródłowy, identyfikujący odbiorcę warstwy wyższej po stronie nadawczej.

2B

destination port

Określa port źródłowy, identyfikujący odbiorcę warstwy wyższej po stronie docelowej.

2B

sequence number

Identyfikuje położenie bajtu w przesyłanym strumieniu danych,wyznaczającego początek segmentu. TCP przydziela numery od 0 do 232-1, a następnie po przekroczeniu maksymalnej wartości, rozpoczyna zliczanie od 0.

Przy nawiązywaniu połączenia (segment z aktywną flagą SYN), pole to zawiera tzw. startowy numer sekwencyjny (ISN). Pierwszy wysłany bajt danych będzie miał przydzielony numer ISN+1.

4B

acknowledgment number

Określa kolejny bajt, którego spodziewa się dana strona. Równy jest numerowi ostatnio, poprawnie odebranego bajtu zwiększonego o jeden. Dla poprawności tego pola musi być aktywna flaga ACK.

4B

HLEN

Określa liczbę 32-bitowych słów, jakie zajmuje nagłówek segmentu (maksymalnie 15*4B=60B).

2B

reserved

Wypełnione zerami.

code bits

Zawierają bity kontrolne, a wśród nich flagi określające charakter segmentu (ACK, URG, PSH, RST, SYN, FIN).

window

Określa wielkość rozgłaszanego okna. Maksymalny rozmiar standardowo wynosi 65535B. Po włączeniu opcji window_scaling może ulec zwiększeniu.

2B

checksum

Zawiera wartość CRC obliczoną dla nagłówka segmentu i danych. Na jego podstawie istnieje możliwość weryfikacji poprawności przez stronę odbierającą, która osobno przelicza wartość CRC i następnie porównuje z tą zapisaną w polu checksum.

2B

urgent pointer

Pole aktywne wówczas, gdy ustawiona jest flaga URG. Zawiera offset, który po dodaniu do numeru sekwencyjnego wskazuje koniec „ważnych danych”. Wykorzystywane wówczas, gdy TCP chce przesłać dane o wysokim priorytecie.

2B

Nazwa pola

Opis

Rozmiar

options

W polu tym zawarte są dodatkowe opcje TCP, n.p. timestamping czy MSS, negocjowane przy inicjacji połączenia.

zmienny

padding

Wypełnia nagłówek zerami do pełnego słowa.

zmienne

data

Dane przesłane z warstw wyższych.

zmienne

Tabela 7.1. Opis pól segmentu TCP

7.4 Przepływ informacji w TCP

Na Rysunku 7.3 przedstawiłem przepływ informacji przy wykorzystaniu protokołu TCP z aplikacji w jednym systemie do aplikacji w drugim systemie.

0x01 graphic

Rys.7.3. Przepływ informacji w TCP

W wyniku wywołania funkcji zapisującej następuje przesłanie danych z bufora aplikacji do bufora gniazda, którego rozmiar można określić poprzez parametr SO_SNDBUF. W przypadku braku wystarczającej ilości wolnego miejsca, proces zostaje uśpiony (gniazda typu blocking). Po umieszczeniu wszystkich danych w buforze aplikacji, funkcja powraca do stanu wyjściowego. Pomimo, iż nie wystąpiły w takiej sytuacji żadne błędy, nie oznacza to, iż informacje zostały poprawnie przesłane do odbiorcy lub opuściły interfejs. Wskazuje tylko na fakt, iż operacja umieszczania ich w buforze gniazda zakończyła się powodzeniem i aplikacja może spróbować dokonać kolejnego zapisu.

Po przesłaniu danych do warstwy transportowej, kontrolę nad nimi przejmuje protokół TCP. Dzieli je na porcje określone przez parametr MSS i następnie zamyka w segmenty. W międzyczasie ustawia parametry nagłówka, zgodnie z wewnętrznymi mechanizmami.

Po przygotowaniu całego segmentu, przesyła go do warstwy sieciowej, gdzie kontrolę przejmuje protokół IP. Zamyka otrzymane dane w pakiet, dodając własny nagłówek. Następnie przeszukuje tablicę routingu, w celu ustalenia interfejsu dla adresu docelowego. Po wykonaniu odpowiednich operacji, przesyła pakiet do warstwy sprzętowej.

W drugiej warstwie po zamknięciu do ramki, dane zostają umieszczone w kolejce wyjściowej. Jeżeli jest pełna, ramka zostaje odrzucona, a odpowiedni komunikat o błędzie przesłany do TCP, który ponawia transmisję. Warstwa aplikacji nie zostaje poinformowana o zaistniałym fakcie. Następnie ramka opuszcza interfejs.

Na hoście docelowym proces odbywa się w odwrotnym kierunku. Po odebraniu ramki przez interfejs docelowy, zostaje umieszczona w buforze karty. W przypadku braku wystarczającej ilości miejsca, następuje jej odrzucenie.

Z warstwy sprzętowej, dane ramki zostają przesłane do protokołu warstwy sieciowej, skąd w postaci segmentu trafiają do warstwy transportowej. TCP umieszcza je w buforze odbiorczym, którego rozmiar można regulować poprzez parametr SO_RCVBUF. Po otrzymaniu żądania z procesu użytkownika, zostaje mu przekazany dany fragment strumienia.

7.5 Zegary TCP

Dla każdego nowo otwartego połączenia protokół TCP obsługuje cztery różne zegary:

  1. retransmission timer - używany wówczas, gdy zostaje wysłany dany segment i TCP oczekuje na jego potwierdzenie. Na jego podstawie podejmowana jest decyzja o ewentualnej retransmisji.

  2. persist timer - używany w sytuacji, gdy jedna ze stron zamknie swoje okno. Umożliwia sprawdzenie jego faktycznego rozmiaru.

  3. keepalive timer - umożliwia rozpoznanie sytuacji, gdy podczas nieaktywności danego połączenia jedna ze stron uległa awarii.

  4. 2MSL timer - używany przy szacowaniu stanu TIME_WAIT.

Dla przeprowadzonych pomiarów związanych z wydajnością TCP duże znaczenie ma pierwszy z nich, dlatego też dokładniejszy jego opis zamieściłem poniżej.

Retransmission timer

Protokół TCP zapewnia niezawodne dostarczenie danych poprzez ich potwierdzanie. Może jednak wystąpić sytuacja, gdy jeden z segmentów zaginie. TCP rozpoznaje taką sytuację, poprzez ustawienie zegara dla każdych wysyłanych danych. Jeżeli nie otrzyma potwierdzenia do momentu, gdy osiągnie on specyficzną wartość, wówczas inicjuje retransmisję. Podstawowe pytanie brzmi: na jakiej podstawie określany jest ten graniczny czas i jak często mają być ponawiane próby?

Zegarem kontrolującym odliczanie czasu w takiej sytuacji jest retransmission timer. W celu dokładnego ustalenia czy pakiet zaginął czy nie, TCP musi oszacować RTT dla danej trasy. Oczywiście w trakcie transmisji wartość ta może ulec zmianie ze względu na zmianę routingu czy intensywności ruchu, dlatego konieczne jest ciągłe monitorowanie i ewentualne modyfikacje.

Parametrem w oparciu o który TCP przeprowadza retransmisję jest RTO, szacowane rekurencyjnie na podstawie jego poprzedniej wartości i aktualnego RTT.

Pomiar RTT odbywa się przy wykorzystaniu wewnętrznych taktów zegara, występujących co 500msec i odzwierciedla czas, jaki upływa pomiędzy wysłanym danym segmentem a odebranym jego potwierdzeniem. Oszacowanie to wprowadza duże niedokładności. Np. dla rzeczywistego RTT wynoszącego 60msec, odczyt TCP wynosi 0 lub 500msec (w zależności od momentu wystąpienia taktu zegara).

RTO jest szacowane w inny sposób przy nawiązywaniu połączenia i przy transmisji danych właściwych.

Dla segmentów SYN początkowa wartość wynosi 6 sekund, na podstawie wzoru:

RTO=A+2*D=0+2*3=6

Jeżeli w przeciągu tego czasu nie zostanie otrzymane potwierdzenie SYN, wówczas TCP inicjuje retransmisję, zerując zegar, a nową wartość RTO ustalając na 24 sekundy. Następne RTO wyniesie 48 sekund, po upłynięciu którego TCP rezygnuje z nawiązania połączenia.

Po pomyślnej inicjacji, pierwsze szacowanie RTO dla transmisji danych odbywa się na podstawie wzorów (wartości zmiennych podane są w sekundach):

RTO=A+4*D

A=M+0,5

D=A/2

Jedynym wymaganym parametrem jest M, który określa aktualnie oszacowane RTT.

Otrzymany rezultat TCP traktuje jako wstępne RTO. Kolejne oszacowania zostają przeprowadzone rekurencyjnie, w miarę uzyskiwania nowych wartości RTT, stosując tym razem wzory:

Err = M-Apop

gdzie:

M - aktualnie oszacowane RTT

Apop - wartość A z poprzednich obliczeń

A= Apop+g*Err

gdzie:

A - aktualna wartość A

Apop - wartość A z poprzednich obliczeń

g - stała równa 0,125

D=Dpop ­+ h*( |Err| - Dpop)

gdzie:

D - aktualna wartość D

Dpop - wartość D z poprzednich obliczeń

h - stała równa 0,25

RTO=A+4*D

TCP przy estymacji RTO stosuje zasadę, iż zmianę wartości wykonuje tylko w przypadku, gdy RTT zostało obliczone dla segmentu, dla którego pomiędzy jego wysłaniem a odebraniem nie nastąpiła retransmisja.

7.6 Dodatkowe mechanizmy zapewniające niezawodność transmisji

TCP jest protokołem zapewniającym niezawodne dostarczenie danych. Stosuje w tym celu wiele mechanizmów, a wśród nich opisane wcześniej: system potwierdzeń ACK, kontrolę przepływu poprzez wprowadzenie okna przesuwnego, retransmisje.

Przy ustalaniu rozmiaru okna duży wpływ na wydajność ma zastosowanie przez TCP tzw. wolnego startu (slow start) oraz algorytmu zapobiegającego powstawaniu zatorów (congestion avoidance).

W przypadku sieci WAN trasa pomiędzy danymi węzłami przebiega przez wiele punktów pośrednich. Załóżmy teraz, iż jeden z routerów charakteryzuje się słabszą wydajnością, kolejkując przekazywane pakiety. Przy dużej intensywności ruchu może dojść do sytuacji, iż dane zostaną przez niego odrzucane, co przyczyni się do wzrostu ilości retransmisji oraz ogólnego spadku wydajności. W celu zapobieżenia takim przypadkom, TCP stosuje slow start oraz congestion avoidance.

Oba algorytmy wprowadzają pojęcie nowego okna tzw. cwnd. Obliczanie jego wartości odbywa się na hoście nadawczym, który w ten sposób ma wpływ na kontrolę przepływu. Jak wcześniej zostało wspomniane, okno określa ilość danych, jakie mogą zostać wysłane do sieci bez oczekiwania na potwierdzenie. Dotyczy to oczywiście strony generującej pakiety. Host odbiorczy rozgłasza własne okno a nadawczy dodatkowo oblicza swoje lokalne. Pytanie brzmi: które z nich ma ostateczne, decydujące znaczenie? Odpowiedzią jest sposób wyboru, dokonywany na hoście nadawczym, który jako właściwe wybiera najmniejsze spośród obu otrzymanych, czyli:

cur_wnd = min (cwnd, rwnd)

gdzie:

cur_wnd - aktualne okno

cwnd - okno obliczone po stronie nadawczej

rwnd - okno rozgłoszone przez stronę odbiorczą

Algorytm slow start uzależnia intensywność generowanego ruchu od ilości otrzymanych potwierdzeń. Początkowo ustala cwnd na rozmiar umożliwiający wysłanie jednego segmentu, zwiększając go o odpowiadającą mu liczbę bajtów z każdym odebranym ACK, co powoduje podwojenie rozmiaru co jeden RTT. Mechanizm taki mam miejsce, aż do momentu gdy cwnd przekroczy wartość parametru ssthreshold (domyślnie 65535B). Wówczas TCP zaczyna stosować algorytm zapobiegający zatorom (congestion avoidance).

W tej sytuacji cwnd rośnie liniowo z każdym otrzymanym ACK według wzoru:

cwnd = cwndpop + segsize*segsize/cwndpop +segsize/8

gdzie:

cwnd - aktualny rozmiar cwnd

cwndpop - poprzedni rozmiar cwnd

segsize - rozmiar segmentu w bajtach

Oczywiście aktualnie używany rozmiar okna nie może przekroczyć wartości rozgłoszonej przez stronę odbiorczą, która stanowi jego górną granicę.

TCP wprowadza modyfikacje do powyższych mechanizmów na wypadek wystąpienia retransmisji. Rozróżnia dwa zasadnicze przypadki:

  1. przekroczenie czasu zegara retransmisji (retransmission timer),

  2. otrzymanie co najmniej trzech zdublowanych potwierdzeń.

Dla pierwszej sytuacji TCP niezależnie od momentu transmisji inicjuje algorytm slow start. Ustawia zmienną ssthreshold na połowę rozmiaru cwnd, ale nie mniejszą niż dwa segmenty a samo cwnd na jeden segment, dalej postępując zgodnie z regułami obu algorytmów.

Dla drugiego przypadku TCP wykonuje następujące czynności:

  1. Po odebraniu trzeciego zdublowanego ACK ustawia ssthreshold na połowę cwnd, wykonuję retransmisję i cwnd ustala jako ssthreshold plus trzy rozmiary segmentów.

  2. Ponieważ w międzyczasie mogą dochodzić kolejne zdublowane ACK, wówczas z każdym jego otrzymaniem zwiększa rozmiar cwnd o jeden segment i transmituje następną porcję danych (jeżeli pozwala na to rozmiar cwnd).

  3. W przypadku otrzymania ACK potwierdzającego nowy segment, TCP ustala cwnd na rozmiar ssthreshold z punktu pierwszego, stosując dalej właściwy algorytm congestion avoidance.

7.7 Problem wydajności TCP w sieciach WAN

Wydajność TCP w sieciach WAN zależy od wielu czynników. Trasa WAN'owska ze względu na swoją złożoność i nieprzewidywalność w pewnych sytuacjach w dużym stopniu utrudnia osiągnięcie wymaganych przepustowości.

TCP zapewnia niezawodne dostarczenie danych, dzięki implementacji w tym celu wielu mechanizmów i cech. Jednak dodatkowe operacje i generowany ruch znajdują swe odzwierciedlenie w niższej wydajności. Kolejne implementacje TCP starają się te straty zminimalizować, poprzez poprawę istniejących i wprowadzanie nowych opcji. Jednak samo ich wykorzystanie nie wystarczy, ponieważ nie w każdych warunkach spełniają swoje zadanie, czasami wręcz wywołując efekt przeciwny. Dlatego też konieczne jest poznanie specyfikacji danej trasy przez użytkownika oraz odpowiednie sparametryzowanie protokołu TCP, tak aby jego wydajność stała się optymalna przy danych warunkach.

Obejmuje to ustawienie odpowiednich rozmiarów buforów po stronie klienta i serwera, sprawdzenie przydatności użytych opcji, ustalenie sposobu generowania danych, itp.

Ponadto, jednym z głównych czynników mających znaczący wpływ na wydajność TCP w sieciach WAN jest pojęcie tzw. pojemności ścieżki. W tej sytuacji należy pamiętać, iż połączenie TCP jest pełnodupleksowe, tzn. występuję równoległe płynięcie strumieni w obu kierunkach.

Pojemność ścieżki określona jest przez tzw. bandwith-delay product, specyfikowany przez wzór:

bdp = bandwith * RTT

gdzie:

bandwith - minimalna pojemność na danej trasie

RTT - czas jaki upływa od wysłania danego pakietu do momentu otrzymania jego potwierdzenia (w TCP)

Można zauważyć, iż pojemność ścieżki zależy proporcjonalnie od RTT i przepustowości. Pojęcie to określa liczbę danych, jaka powinna zostać wysłana bez konieczności oczekiwania w międzyczasie na potwierdzenie (rozmiar okna), aby dana ścieżka została optymalnie wykorzystana. W przypadku mniejszej ilości pakietów pojawia się sytuacja, iż w pewnym momencie host nadawczy wstrzymuje wysyłanie danych, czekając na potwierdzenie. W ten sposób tworzą się niepożądane „dziury” w strumieniu, zmniejszające uzyskiwaną przepustowość.

Bandwith-delay product specyfikuje rozmiar okna w warunkach idealnej sieci, bez retransmisji, czy zmiany chwilowych warunków, dlatego też w rzeczywistości konieczne jest oszacowanie wielkości tego parametru w zależności od charakterystyki trasy oraz generowanego ruchu.

8. Pomiar wpływu wybranych parametrów TCP na przepustowość

8.1 Cel pomiaru

Celem pomiaru było ustalenie wpływu wybranych parametrów TCP na ogólną przepustowość, a następnie ich zoptymalizowanie pod kątem transmisji danych.

TCP jest protokołem warstwy transportowej, dysponującym mechanizmami zapewniającymi niezawodność dostarczania danych. W tym celu zaimplementowano w nim wiele parametrów umożliwiających zapobieganie błędom transmisji oraz przedsięwzięcie właściwych środków celem ich ewentualnego skorygowania. Wszystko to odbywa się jednak kosztem przepustowości przesyłanych danych, zależnej od warunków, w których realizowana jest transmisja.

Wydajność może zostać poprawiona poprzez parametryzację wybranych opcji, celem dopasowania ich do charakterystyki trasy pomiarowej.

W poniższym pomiarze pokazałem jaki wpływ na ogólną przepustowość ma parametr MSS (Maximum Segment Size), window_clamp, rozmiar danych zamykanych w warstwie transportowej, rozmiary buforów na hoście odbiorczym i nadawczym.

8.2 Sposób przeprowadzenia pomiarów

Pomiar został wykonany na drodze CERN-CYFRONET dla jednego kierunku, przy zaalokowanym kanale pomiędzy Poznaniem a Krakowem.

Celem uzyskania odpowiednich wyników wykorzystałem aplikację testującą (patrz rozdział 4), generującą ruch w oparciu o protokół TCP. Następnie dokonałem serii pomiarów dla różnych wartości badanych parametrów, zapisując je i uzyskane przepustowości do pliku, na podstawie którego mogłem dokonać ich późniejszej analizy.

8.3 Uzyskane wyniki

W pierwszym pomiarze zbadałem wpływ MSS na ogólną przepustowość, przy stałych, pozostałych parametrach (patrz Tabela 8.1).

TCP

KLIENT

SERWER

CERN

CYFRONET

rozmiar danych

1448B

1448B

liczba pakietów

20 000

20 000

MSS

zmienna

zmienna

window_clamp

-

73552

no_delay

ON

ON

window_scaling

ON

ON

bufor odbiorczy

100 000B

100 000B

bufor nadawczy

100 000B

100 000B

Tabela 8.1. Konfiguracja klienta i serwera - pomiar TCP (1)

Parametr MSS został zaimplementowany w TCP celem zapobieżenia fragmentacji przesyłanych pakietów, powodującej powstanie dodatkowej ilości danych w sieci, które z kolei przyczyniają się do jej nadmiernego obciążenia. W ten sposób zwiększa się również prawdopodobieństwo, iż dany segment będzie wymagał retransmisji (wystarczy, aby zaginął co najmniej jeden fragment).

Maksymalna wartość danych segmentu, który nie ulegnie fragmentacji dla badanej trasy wynosi 1448B, zgodnie ze wzorem:

M = MTU - IP_HEADER - TCP_HEADER - TCP_OPTIONS

gdzie:

MTU - maximal transfer unit (1500B)

IP_HEADER - rozmiar nagłówka IP (20B)

TCP_HEADER - rozmiar nagłówka TCP (20B)

TCP_OPTIONS - rozmiar użytych opcji TCP (timestamping=12B)

Dlatego jako maksymalną wartość MSS przy pomiarze wybrałem 1460B. Kolejne serie przeprowadziłem dla 1000B oraz 600B.W Tabeli 8.2 oraz na Rysunku 8.1 zamieściłem uzyskane wyniki.

MSS

przepustowość

1460B

8,7Mb/s

1000B

5,3Mb/s

600B

4,8Mb/s

Tabela 8.2. Wpływ MSS na przepustowość

0x01 graphic

Rys.8.1.Wpływ MSS na przepustowość - wykres

Jak można zauważyć, maksymalna przepustowość została uzyskana dla MSS=1460B. Ponieważ dla większych wartości nastąpi fragmentacja niekorzystnie wpływająca na ogólną wydajność, dlatego ostatecznie tą wielkość parametru zastosowałem do dalszych transmisji.

W kolejnym pomiarze zbadałem, jaki wpływ na przepustowość ma rozmiar danych zamykanych w warstwie transportowej, przy następujących parametrach (patrz Tabela 8.3)

TCP

KLIENT

SERWER

CERN

CYFRONET

rozmiar danych

zmienny

zmienny

liczba pakietów

20 000

20 000

MSS

1460B

1460B

window_clamp

-

73552

no_delay

ON

ON

window_scaling

ON

ON

bufor odbiorczy

100 000B

100 000B

bufor nadawczy

100 000B

100 000B

Tabela 8.3. Konfiguracja klienta i serwera - pomiar TCP (2)

Rozpatrzyłem trzy przypadki:

W Tabeli 8.4 oraz na Rysunku 8.2 zamieściłem uzyskane wyniki.

rozmiar danych

przepustowość

1448B

8,7Mb/s

1000B

7,2Mb/s

2000B

7,3Mb/s

Tabela 8.4. Wpływ rozmiaru danych na przepustowość

0x01 graphic

Rys.8.2.Wpływ rozmiaru danych na przepustowość - wykres

Na podstawie uzyskanych wyników można zauważyć, iż największa przepustowość została uzyskana dla 1448B. Rozmiar ten zapewnia przesłanie maksymalnej ilości danych podczas jednej transmisji.

W pozostałych przypadkach nastąpił spadek wydajności ze względu na nieefektywne wykorzystanie zasobów. Przykładowo dane o rozmiarze 2000B warstwa transportowa dzieli na dwie części: o rozmiarze 1448B (MSS) oraz 552B. Przy pierwszym fragmencie, liczba danych przesłanych w jednej ramce jest maksymalna, natomiast przy drugim stanowi tylko 38%.

Na podstawie przeprowadzonych badań stwierdziłem, iż najefektywniejszy rozmiar danych przesyłanych w segmencie wynosi 1448B.

W kolejnym pomiarze sprawdziłem wpływ wielkości parametru window_clamp na uzyskaną przepustowość.

Window_clamp jest to maksymalny rozmiar okna rozgłaszanego przez komputer odbiorczy wskazujący, jaką ilość danych host nadawczy może wytransmitować bez oczekiwania na potwierdzenie (ACK) z drugiej strony. Domyślnie jego wielkość jest ustalana przez algorytm TCP (patrz rozdział 9).

W Tabeli 8.3 zamieściłem pozostałe parametry transmisji.

TCP

KLIENT

SERWER

CERN

CYFRONET

rozmiar danych

1448B

1448B

liczba pakietów

20 000

20 000

MSS

1460B

1460B

window_clamp

-

zmienne

no_delay

ON

ON

window_scaling

ON

ON

bufor odbiorczy

100 000B

100 000B

bufor nadawczy

100 000B

100 000B

Tabela 8.5. Konfiguracja klienta i serwera - pomiar TCP (3)

Poniżej przedstawiłem wykres narysowany na podstawie uzyskanych wyników (patrz Rys.8.3).

0x01 graphic

Rys.8.3.Wpływ window_clamp na przepustowość - wykres (1)

Pomiar został przeprowadzony dla rozmiaru bufora odbiorczego hosta nadawczego równego 100 000B. Ponieważ istnieje ścisła zależność między nim a maksymalnym rozgłaszanym oknem, dlatego największą możliwą wartością była wielkość 73552B (patrz rozdział 9).

Na wykresie widać wyraźny wzrost badanej zależności. Można się spodziewać, iż tendencja ta utrzyma się aż do pewnej maksymalnej wartości, której przekroczenie nie będzie możliwe ze względu na algorytm TCP i właściwości badanej trasy. Przypomnę, iż window_clamp nie specyfikuje wartości okna rozgłaszanej w danym momencie a tylko jego górną granicę. Mechanizm podlega samoregulacji, co oznacza, iż niekoniecznie musi zostać osiągnięta wartość ustawiona przez ten parametr.

Wpływ na to ma wiele czynników, m.in. czas przesyłania pakietów, przepustowość trasy, obciążenie, niezawodność związana z ilością zagubionych pakietów, itp. Dlatego też zwiększanie window_clamp powyżej pewnej wartości nie przyniesie wymiernych korzyści, ponieważ i tak maksymalne okno nie przekroczy rozmiaru ustalonego przez algorytm TCP. W przypadku, gdy rozgłoszone okno będzie za małe, wtedy nie uzyskamy w naszej sieci pełnej wydajności, a ograniczymy ją odgórnie.

Dla otrzymania optymalnych parametrów, host nadawczy powinien mieć możliwość wysłania ilości pakietów (w bajtach) równej iloczynowi RTT oraz minimalnej przepustowości badanej trasy (patrz rozdział 7.7). Oczywiście jest to słuszne w przypadku sieci o stałej charakterystyce w czasie, bez zgubionych pakietów, zatorów, itp.

Ostatecznie dla trasy, na której wykonywałem pomiary, wybrałem wartość 800 000B, uzyskaną na podstawie poniższych parametrów (patrz Tabela 8.6).

minimalna przepustowość

RTT

window_clamp (RTT*min_przep)

100Mb/s

0,064 sec

800 000 B

Tabela 8.6. Wartość window_clamp w zależności od RTT i przepustowości

Przepustowości otrzymywane dla tej wartości oscylowały wokół 15Mb/s. Po zwiększeniu window_clamp, sytuacja nie uległa zmianie, co zostało zilustrowane na Rysunku 8.4.

0x01 graphic

Rys.8.4. Wpływ window clamp na przepustowość - wykres (2)

W celu oszacowania wielkości buforów odbiorczych i nadawczych, posłużyłem się uzyskanymi wcześniej wynikami.

Przepływ ruchu TCP odbywa się pomiędzy CERN-em a CYFRONET-em. Do Krakowa przesyłane są pakiety z danymi co sprawia, iż ma on bardziej intensywny charakter, natomiast w kierunku przeciwnym potwierdzenia ich dostarczenia - ACK.

Ze względu na te właściwości, najważniejszą rolę pełni bufor odbiorczy na komputerze w Cyfronecie. Na podstawie przeprowadzonych pomiarów (patrz rozdział 9) zauważyłem, iż istnieje ścisła zależność pomiędzy maksymalnym rozmiarem rozgłaszanego okna a wielkością bufora odbiorczego (max_win ≅ 73%buf_odb). Dlatego dla dalszych badań przyjąłem wartość 1,5MB, tak aby parametr window_clamp równy 800 000B nie przekroczył granicy 73% tej wielkości.

Pozostały bufor nadawczy na hoście w Cyfronecie nie ma tak wielkiego znaczenia, ponieważ służy on do wysyłania potwierdzeń ACK, których intensywność jest wystarczająco mała. Wartość jego ustaliłem na 200 000B.

Bufor nadawczy komputera w CERN-ie ustawiłem na 1,5MB. On również nie ma aż tak dużego wpływu, ponieważ jego wielkość określa, jak szybko dane z warstwy aplikacji zostaną umieszczone w warstwie transportowej. Dalszy etap (przesłanie segmentu do warstwy sieciowej) regulowany jest przez algorytm TCP. Jedyny problem mógłby pojawić się w przypadku, gdy rozmiar tego bufora byłby skrajnie mały (dodatkowe opóźnienie przed zamknięciem danych w segment) lub skrajnie duży (wyczerpanie zasobów pamięci i spowolnienie systemu).

Bufor odbiorczy komputera nadawczego wykorzystywany jest do gromadzenia ACK i również nie ma znaczącego wpływu na ogólną przepustowość. Domyślnie ustawiłem go na rozmiar 200 000B.

Ostatecznie w Tabeli 8.7 zebrałem wszystkie wartości uzyskane w wyniku przeprowadzonych pomiarów, pozwalające na osiągnięcie maksymalnych wydajności dla danej charakterystyki testowanej trasy.

TCP

KLIENT

SERWER

CERN

CYFRONET

no_delay

ON

ON

liczba pakietów

20 000

20 000

window_scaling

ON

ON

SACK

ON

ON

rozmiar danych

1448B

1448B

MSS

1460B

1460B

window_clamp

-

800KB

bufor odbiorczy

200KB

1,5MB

bufor nadawczy

1,5MB

200KB

Tabela 8.7. Optymalne parametry konfiguracyjne klienta i serwera

9. Badanie okna rozgłaszanego przez hosta odbiorczego w transmisji TCP

9.1 Cel pomiaru

Celem pomiaru było zbadanie mechanizmu decydującego o rozmiarze rozgłaszanego okna oraz ustalenie korelacji z wielkością bufora odbiorczego.

Jest to jeden z ważniejszych elementów mających bezpośredni wpływ na wydajność transmisji.

Szczególny nacisk położyłem na ustalenie zależności rozmiaru okna od stopnia nasycenia bufora odbiorczego przesyłanymi danymi. Na poniższym wykresie przedstawiłem punkty, których współrzędne oszacowałem w wyniku pomiaru (patrz Rys.9.1).

0x01 graphic

Rys.9.1. Punkty pomiarowe

punkt

oś wartości

oś rzędnych

A

początkowy rozmiar okna

procentowe nasycenie okna odebranymi danymi

B

maksymalny rozmiar okna

D

maksymalny rozmiar okna

E

okno=0 (brak transmisji)

Tabela 9.1. Punkty pomiarowe - opis

Dodatkowo określiłem szybkość zmiany rozmiaru okna na odcinku A-B oraz C-D, wyrażoną w segmentach na jednostkę.

9.2 Sposób przeprowadzenia pomiaru

Pomiar został wykonany na drodze CERN-CYFRONET dla jednego kierunku, przy zaalokowanym kanale pomiędzy Poznaniem a Krakowem.

Celem uzyskania odpowiednich wyników wykorzystałem napisaną wcześniej aplikację, generującą ruch w oparciu o protokół TCP.

Dla oszacowania wspomnianych punktów dokonałem modyfikacji standardowego programu, poprzez usunięcie z kodu klienta linii odpowiadającej za odbieranie pakietów z bufora i przekazywanie ich do warstwy aplikacji. W ten sposób mogłem kontrolować jego stopień zapełnienia.

Podczas całej sesji pomiarowej na hoście nadawczym był uruchomiony program tcpdump (aplikacja dostarczona wraz z dystrybucją linuksa, umożliwiająca zapisanie pakietów pojawiających się na lokalnych interfejsach, wraz z wyszczególnieniem zawartych w nich informacji oraz czasu ich odebrania), zapisujący do pliku informacje z nagłówków segmentów, wysyłanych do CYFRONET-u w ramach danego połączenia.

Następnie po zakończeniu pomiaru mogłem dokonać ich analizy.

W Tabeli 9.2 zamieściłem konfigurację obu komputerów.

TCP

KLIENT

SERWER

CERN

CYFRONET

rozmiar danych

zmienny

zmienny

liczba pakietów

100

100

MSS

zmienny

zmienny

window_clamp

-

46 552B

no_delay

ON

ON

window_scaling

ON

ON

bufor odbiorczy

65 535B

zmienny

bufor nadawczy

131 070B

131 070B

Tabela 9.2. Konfiguracja klienta i hosta - pomiar TCP

Wykonałem cztery przykładowe testy dla różnych wartości bufora odbiorczego na hoście w Cyfronecie (59KB, 64KB, 100KB, 120KB) oraz rozmiaru danych zamkniętych w segmencie (1000B, 1100B).

9.3 Uzyskane wyniki

Na początku, na podstawie danych otrzymanych z programu tcpdump, ustaliłem startowy rozmiar okna, rozgłaszanego przez hosta odbiorczego. W Tabeli 9.3 przedstawiłem uzyskane rezultaty.

rozmiar danych

bufor

okno początkowe

1000B

59KB

7KB

64KB

7KB

100KB

3,5KB

120KB

3,5KB

1100B

120KB

3,85KB

Tabela 9.3. Startowy rozmiar okna

Dla dwóch pierwszych przypadków rozmiary buforów są mniejsze niż 65535B, dlatego też rozmiar okna początkowego jest równy temu, wskazanemu przez tcpdump (7KB). Dla 100KB oraz 120KB przed podaniem ostatecznego rezultatu należy przeskalować uzyskane wyniki odpowiednio o 21­­­, otrzymując również wartość 7KB.

Ponieważ w tym przypadku rozmiar danych segmentu wynosi 1000B, dlatego też można stwierdzić, iż algorytm rozgłaszania okna wartość startową ustala na 7-krotny rozmiar segmentu.

W celu potwierdzenia przeprowadziłem test, wysyłając segmenty o  wielkości 1100B. Dla tego przypadku okno początkowe zostało ustalone na 3850B, co po przeskalowaniu dało wartość 7700B, odpowiadającą również siedmiu odebranym segmentom.

Podsumowując, na podstawie przeprowadzonych testów można stwierdzić, iż startowy rozmiar okna dla badanego systemu odpowiada wielkości siedmiu odebranych segmentów (punkt A na schemacie).

Korzystając z wygenerowanych przez tcpdump'a wyników, oszacowałem również parametry punktu B, odpowiadającego maksymalnemu, rozgłaszanemu rozmiarowi okna. Okazało się, iż istnieje zależność pomiędzy nim a wielkością bufora odbiorczego.

Przy definicji okna wspomniane jest, iż przy jego pomocy host odbiorczy rozgłasza, jaką ilość danych może pomieścić w swoim buforze, którego wielkość powinno określać maksymalne rozgłaszane okno. Jak się jednak okazało, w badanym systemie sprawa wygląda inaczej. W Tabeli 9.4 przedstawiłem zależności potwierdzające ww. tezę.

rozmiar bufora odbiorczego

maksymalny rozmiar okna

procent

59 000B

42 802B

72,5%

64 000B

46 552B

72,7%

100 000B

73 552B

73,5%

120 000B

88 552B

73,7%

Tabela 9.4. Maksymalny rozmiar okna

Jak można zauważyć, maksymalne rozgłaszane okno wcale nie jest równe całkowitej wielkości bufora odbiorczego, a stanowi około 70% jego rozmiaru.

Ma to duży wpływ przy korzystaniu z parametru window_clamp. Tzn. aby ustawić daną wartość należy zapewnić wcześniej, iż rozmiar bufora jest wystarczająco duży.

Kolejnym etapem było oszacowanie parametrów punktu C, określającego od jakiego stopnia zapełnienia bufora odbiorczego, rozgłaszane okno zaczyna systematycznie maleć, aż do osiągnięcia punktu D (okno=0).

W Tabeli 9.4 zamieściłem wyniki, otrzymane na podstawie pliku utworzonego przy pomocy programu tcpdump.

Bufor odbiorczy

rozmiar segmentu

liczba segmentów

procent

59KB

1 100B

17

32%

64KB

18

31%

100KB

1 000B

30

30%

120KB

36

30%

Tabela 9.5. Górna granica nasycenia bufora dla maksymalnego okna

Tabela 9.5 pokazuje po jakiej ilości segmentów umieszczonych w buforze, host odbiorczy zaczyna rozgłaszać zmniejszone okno. Na jej podstawie można zauważyć, iż sytuacja ta występuje po zapełnieniu bufora w około 30%.

Dlatego w celu uzyskania optymalnych rezultatów podczas pomiarów należy zadbać o to, aby liczba przechowywanych segmentów nie przekroczyła tej wartości.

W kolejnym pomiarze oszacowałem, przy jakim stopniu zapełnienia bufora, host odbiorczy zaczyna rozgłaszać zerowe okno (punkt D).

W Tabeli 9.6 zamieściłem wyniki otrzymane na podstawie pliku utworzonego przy pomocy programu tcpdump.

bufor odbiorczy

rozmiar segmentu

liczba segmentów

procent

59 000B

1 100B

50

93%

64 000B

53

91%

100 000B

1 000B

90

90%

120 000B

108

90%

Tabela 9.6. Nasycenie bufora dla okna zerowego

Podsumowując można stwierdzić, iż przy zapełnieniu bufora w około 90%, host odbiorczy wstrzymuje transmisję, poprzez rozgłaszanie okna o wartości 0.

Następnie oszacowałem szybkość zmiany rozmiaru okna na odcinku A-B oraz C-D, wyrażoną w segmentach na jednostkę.

Poniżej przedstawiłem wykresy dla dwóch przykładowych konfiguracji hosta (patrz Rys.9.2 oraz Rys.9.3).

0x01 graphic

Rys. 9.2. Szybkość zmiany rozmiaru okna na odcinku A-B oraz C-D - wykres(1)

Wykres ten został narysowany dla hosta odbiorczego o rozmiarze bufora 59KB oraz segmentu 1100B. Na podstawie uzyskanych danych można zauważyć, iż początkowy przyrost występuje co 2200B, co odpowiada wielkości dwóch segmentów, natomiast spadek co 1100B (jeden segment).

Identyczne rezultaty uzyskałem również dla hosta o rozmiarze bufora 100KB oraz 1000 bajtowych danych zamykanych w warstwie transportowej.

0x01 graphic

Rys. 9.3. Szybkość zmiany rozmiaru okna na odcinku A-B oraz C-D - wykres(2)

Dla tego przypadku przyrost występuje co 1000B, natomiast spadek co 500B. Ponieważ rozmiar bufora wynosi 100KB, dlatego uzyskane wartości należy przeskalować odpowiednio przez 21 otrzymując wyniki, jak w poprzednim pomiarze: 2 segmenty na odcinku A-B (1000B*21/1000B) oraz 1 segment na C-D (500B*21/1000B).

Podsumowując, na podstawie przeprowadzonych pomiarów, związanych z zachowaniem okna rozgłaszanego przez hosta odbiorczego, uzyskałem następujące rezultaty (patrz także Rys.9.4 oraz Tabela 9.7):

  1. okno startowe rozgłaszane przez hosta odbiorczego wynosi siedem rozmiarów segmentów,

  2. przyrost okna do maksymalnej wartości odbywa się liniowo co dwa segmenty,

  3. maksymalna wartość, jaką może osiągnąć rozgłaszane okno stanowi ok. 70% całkowitego rozmiaru bufora,

  4. po przekroczeniu zapełnienia bufora w 30%, host odbiorczy zaczyna rozgłaszać malejące okno,

  5. spadek rozmiaru okna do wartości zerowej odbywa się liniowo co jeden segment,

  6. wartość zero osiągnięta zostaje po zapełnieniu bufora w około 80%.

0x01 graphic

Rys. 9.4. Punkty pomiarowe - wyniki - wykres

punkt

oś argumentów

oś wartości

A

0

siedem segmentów

B

zmienne

70% rozmiaru bufora

C

30% rozmiaru bufora

D

80% rozmiaru bufora

0

Tabela 9.7. Wartości punktów pomiarowych

10. Szacowanie RTO

10.1 Cel pomiaru

Celem pomiaru było sprawdzenie czy mechanizm szacowania RTO przez algorytm TCP na komputerze nadawczym ma wpływ na osiągane przepustowości, oscylujące wokół 15Mb/s, przy maksymalnej wartości 25Mb/s.

10.2 Sposób przeprowadzenia pomiaru

Algorytm TCP przy szacowaniu RTO korzysta z następującego wzoru:

RTO=A+4*D

Początkowo parametr A=1 oraz D=0,5. Dla każdego następnego pomiaru, następuje ich rekurencyjne szacowanie w oparciu o poniższe wzory:

A = Apop + ­­­0,125 * ( M-Dpop )

D = Dpop + 0,125 * ( |M - Apop| - Dpop )

gdzie:

Apop - poprzednia wartość A

M - aktualne RTT

Dpop - poprzednia wartość D

Algorytm TCP szacuje RTT w oparciu o różnicę czasu obliczoną na podstawie danego segmentu oraz otrzymanego jego potwierdzenia. Aby pomiar został uznany za właściwy, podczas tej przerwy czasowej nie może nastąpić żadna retransmisja. W innym przypadku jako wartość M zostaje przyjęta ta obliczona ostatnio.

Ponieważ wewnętrzny zegar TCP taktowany jest co 500ms, dlatego szacowanie RTT odbywa się z taką właśnie dokładnością (liczba taktów zegara, jaka wystąpiła w danym przedziale czasowym).

W celu uzyskania odpowiednich wartości na podstawie rekurencyjnych wzorów, stworzyłem arkusz kalkulacyjny.

Jedyną wartość jaką musiałem dostarczyć był parametr M, ponieważ pozostałe mogłem wyliczyć na jego podstawie.

Pomiar został wykonany na drodze CERN-CYFRONET dla jednego kierunku, przy zaalokowanym w tym celu kanale pomiędzy Poznaniem a Krakowem.

Podczas całej sesji pomiarowej na hoście nadawczym był uruchomiony program tcpdump, zapisujący do pliku informacje z nagłówków segmentów wysyłanych do CYFRONET-u w ramach danego połączenia.

W Tabeli 10.1 zamieściłem konfigurację obu komputerów.

TCP

KLIENT

SERWER

CERN

CYFRONET

rozmiar danych

1448B

1448B

liczba pakietów

20 000

20 000

MSS

1460B

1460B

window_clamp

-

800KB

no_delay

ON

ON

window_scaling

ON

ON

bufor odbiorczy

200KB

1,5MB

bufor nadawczy

1,5MB

200KB

Tabela 10.1. Konfiguracja klienta i serwera - pomiar TCP

Dane zapisane do pliku przez tcpdump musiałem poddać analizie, aby móc wyszukać i obliczyć potrzebne wartości. W tym celu napisałem aplikację, wykonującą następujące funkcje:

  1. pobranie zawartości pliku z danymi,

  2. wyszukanie wśród nich czasu wysłania danego segmentu oraz odebrania odpowiadającego mu potwierdzenia i zapisanie różnicy(RTT),

  3. anulowanie danego szacowania w przypadku wystąpienia retransmisji,

Blokowy schemat realizujący funkcje opisane w punkcie 2 i 3 zamieściłem w postaci algorytmu (patrz Rys.10.1).

0x01 graphic

Rys.10.1. Algorytm aplikacji analizującej dane do RTO

Idea programu polega na tym, iż początkowo wyszukuję linię zawierającą informacje z pierwszym wysłanym segmentem, zapamiętuję czas jego generacji oraz numer sekwencyjny, a następnie przeglądam kolejne wiersze w wyszukiwaniu ACK potwierdzającego go. Gdy taki zostanie znaleziony, wtedy zapisuję czas jego odbioru, a następnie wyliczam różnice na podstawie zapamiętanych wartości, zapisując ją do pliku. Postępuję tak do momentu przeanalizowania całego pliku.

W całym algorytmie uwzględniłem przypadek, gdy pomiędzy danym segmentem a odpowiadającym mu potwierdzeniem wystąpi retransmisja. W takiej sytuacji przerywam wyszukiwanie ACK i rozpoczynam je od pierwszego segmentu wysłanego po jej zakończeniu.

Fakt wystąpienia retransmisji sprawdzam w następujący sposób. Porównuję pobrany aktualnie numer potwierdzenia z odczytanym poprzednio i jeżeli jest mniejszy, wtedy zapamiętuje jego wartość, kontynuując dalsze odczyty ACK, celem sprawdzenia czy przypadek ten rzeczywiście jest retransmisją. Może bowiem zdarzyć się, iż z jakichkolwiek powodów wysłany segment dotrze w innej kolejności niż oczekuje tego host odbiorczy, który w takim przypadku generuje potwierdzenie z numerem sekwencyjnym mniejszym niż ostatnio wysłany. Nie stanowi to jednak samo w sobie powodu do wystąpienia retransmisji. Jako pewnik rozstrzygający o tym można potraktować fakt otrzymania co najmniej trzech zdublowanych numerów potwierdzających.

Poniżej przedstawiłem algorytm wyszukiwania retransmisji (patrz Rys.10.2).

0x01 graphic

Rys.10.2. Algorytm wyszukiwania retransmisji

Odpowiada mu następujący fragment kodu, realizujący opisane powyżej funkcje:

for (;j!=1;)

{

fseek(fd1,69,SEEK_CUR);

fscanf(fd1,"%c",&sign);

if ((sign=='P') && (retr==0) && (estim==0))

{

k=0;

for (;;)

{

fscanf(fd1,"%c",&sign);

if (sign==':') break;

k++;

}

i=0;

for (;;)

{

fscanf(fd1,"%c",&tekst[i]);

if (tekst[i]=='(') break;

i++;

}

tekst[i]='\0';

seq_new=atoi(tekst);

printf("%d\n",seq_new);

seq_old=seq_new;

estim=1;

fseek(fd1,-70-i-k-2+6,SEEK_CUR);

for (i=0;i<9;i++)

{

fscanf(fd1,"%c",&tekst[i]);

}

tekst[i]='\0';

time_new=atof(tekst);

printf("%f\n",time_new);

time_old=time_new;

}

if ((sign=='.') && (estim==1))

{

fseek(fd1,5,SEEK_CUR);

if (retr==1)

{

i=0;

for (;;)

{

fscanf(fd1,"%c",&tekst[i]);

if (tekst[i]==' ') break;

i++;

}

tekst[i]='\0';

seq_new=atoi(tekst);

printf("%d\n",seq_new);

if (seq_new!=retr_old)

{

estim=0;

retr=0;

puts("koniec retransmisji");

getchar();

}

}

else

{

i=0;

for (;;)

{

fscanf(fd1,"%c",&tekst[i]);

if (tekst[i]==' ') break;

i++;

}

tekst[i]='\0';

seq_new=atoi(tekst);

printf("\n%d - %f\n",seq_new,time_new);

printf("%d - %f\n",seq_old,time_old);

if (retr_old==seq_new)

{

puts("zdublowane ACK");

tripple++;

if (tripple==3)

{

retr=1;

puts("tripple");

}

}

else

{

tripple=1;

}

if ((seq_new >= seq_old) && (seq_old!=0))

{

puts("ACK znalezione");

fseek(fd1,-75+4-i+1,SEEK_CUR);

for (i=0;i<9;i++)

{

fscanf(fd1,"%c",&tekst[i]);

}

tekst[i]='\0';

time_new=atof(tekst);

printf("time_new=%f * %f\n",time_new,time_new-time_old);

fprintf(fd2,"%f\n",time_new-time_old);

fseek(fd2,-8,SEEK_CUR);

fprintf(fd2,",");

fseek(fd2,7,SEEK_CUR);

getchar();

estim=0;

}

retr_old=seq_new;

}

}

for (;;)

{

if (fscanf(fd1,"%c",&sign)==EOF) { j=1; break; }

if (sign=='\n')

{

break;

}

}

}

10.3 Uzyskane wyniki

Poniższe wykresy obrazują dane uzyskane podczas pomiaru (patrz Rys.10.3 oraz Rys.10.4)

0x01 graphic

Rys. 10.3. Szacowanie RTT - wykres

0x01 graphic

Rys. 10.4. Szacowanie RTO - wykres

Na podstawie wykresu RTT można zauważyć, iż wskazania czasu propagacji pakietów w obu kierunkach oscylują wokół 60msec, co potwierdzałoby wcześniejsze wyniki uzyskane przy wykorzystaniu protokołu UDP.

Oczywiście są to rezultaty dla pakietów nie objętych wpływem retransmisji, tzn. pomiędzy ich wygenerowaniem a otrzymaniem potwierdzenia nie został wykorzystany ten mechanizm.

Miejscami czas ten rośnie do 80msec, jednak nie jest to znacząca rozbieżność, mająca jednocześnie sporadyczny charakter.

Przy estymowaniu RTO pobierana jest wartość RTT, szacowana na podstawie 500-milisekundowych taktów zegara TCP. Ponieważ RTT jest niewiększe niż 80msec, dlatego do ostatecznego wzoru będzie podstawiany czas (M) wynoszący 0 lub 500msec.

Ze względu na domyślne startowe wartości, RTO początkowo wynosi ok. 3,5 sekundy, w trakcie dalszych obliczeń systematycznie malejąc, aż do momentu, gdy widoczne stają się oscylacje wartości pomiędzy 0,8sec a 0,3sec. Powodem ich są wspomniane wcześniej niedokładności szacowania RTT (0 lub 500msec).

Algorytm TCP wykorzystuje RTO do zainicjowania retransmisji. Tzn. dla każdego wysłanego pakietu z danymi uruchamiany jest specjalny licznik, zatrzymujący swe działania w momencie otrzymania odpowiadającego mu potwierdzenia. Jeżeli w tym czasie wartość jego przekroczy oszacowane RTO, wówczas wykonywana jest retransmisja danego pakietu. Ma to bardzo duży wpływ na ogólną przepustowość, ponieważ w takiej sytuacji algorytm TCP inicjuje transmisję od tzw. wolnego startu (patrz rozdział 7.6).

Na podstawie otrzymanego wykresu RTO można zauważyć, iż wartość jego nie schodzi poniżej 300msec, co stanowi pięciokrotność szacowanego RTT. Dlatego przy normalnych warunkach transmisji, w jakich wykonywane były pomiary, czasy otrzymywania danych potwierdzeń z całą pewnością nie przekroczyły RTO, co z resztą zostało potwierdzone w kolejnych pomiarach.

Podsumowując, można stwierdzić, iż algorytm szacowania RTO nie ma wpływu na uzyskiwane przepustowości.

11. Charakterystyka ruchu TCP odbieranego w Cyfronecie

11.1 Cel pomiaru

Celem pomiaru było ustalenie charakterystyki ruchu TCP odbieranego w  Cyfronecie, a w szczególności oszacowanie:

  1. rozmiaru przerwy czasowej pomiędzy kolejnymi otrzymywanymi pakietami,

  2. wpływu ilości i miejsca wystąpienia retransmisji na charakterystykę oszacowaną w punkcie pierwszym.

Ponieważ oba powyższe parametry mają bezpośredni wpływ na uzyskiwane przepustowości, dlatego ich bliższa analiza pozwoli lepiej poznać przyczyny, dla których przy użyciu TCP nie można osiągnąć pełnej wydajności.

11.2 Sposób przeprowadzenia pomiaru

Pomiar został wykonany na drodze CERN-CYFRONET dla jednego kierunku, przy zaalokowanym w tym celu kanale pomiędzy Poznaniem a Krakowem.

Podczas całej sesji pomiarowej na hoście odbiorczym był uruchomiony program tcpdump, zapisujący do pliku informacje z nagłówków segmentów, wysyłanych do CYFRONET-u w ramach danego połączenia. Po zakończeniu pomiaru dokonałem ich analizy. Ruch TCP wygenerowałem w oparciu o aplikację testową (patrz rozdział 4).

W Tabeli 11.1 zamieściłem konfigurację obu komputerów.

TCP

KLIENT

SERWER

CERN

CYFRONET

rozmiar danych

1448B

1448B

liczba pakietów

20 000

20 000

MSS

1460B

1460B

window_clamp

-

800KB

no_delay

ON

ON

window_scaling

ON

ON

bufor odbiorczy

200KB

1,5MB

bufor nadawczy

1,5MB

200KB

Tabela 11.1. Konfiguracja klienta i serwera - pomiar TCP

W celu uzyskania właściwych danych do punktu pierwszego, napisałem aplikację analizującą dane sesji TCP otrzymane z programu tcpdump.

Program ten umożliwia oszacowanie wartości przerwy czasowej pomiędzy poszczególnymi pakietami, poprzez wyszukanie w pliku linii odpowiadających odebranym segmentom i odczytanie przypisanego im czasu, który następnie zapisuje do pliku wyjściowego.

Poniżej przedstawiłem algorytm działania tej aplikacji (patrz Rys.11.1)

0x01 graphic

Rys. 11.1. Algorytm analizy przerwy czasowej pomiędzy pakietami

Fragment kodu realizujący ww. operacje wygląda następująco:

for (;j!=1;)

{

// sprawdzenie czy dana linia odpowiada segmentowi z danymi otrzymanymi

fseek(fd1,40,SEEK_CUR);

fscanf(fd1,"%c",&sign);

if (sign=='<')

{

//wczytanie i zapisanie czasu do pliku

fseek(fd1,-41,SEEK_CUR);

for (i=0;i<6;i++)

{

fscanf(fd1,"%c",&sign);

}

for (i=0;i<9;i++)

{

fscanf(fd1,"%c",&sign);

if (sign=='.')

{

fprintf(fd2,"%s",",");

}

else

{

fprintf(fd2,"%c",sign);

}

}

fprintf(fd2,"\n");

for (;;)

{

fscanf(fd1,"%c",&sign);

if (sign==EOF){j=1; break; }

if (sign=='\n')

{

break;

}

}

}

else

{

for (;;)

{

if (fscanf(fd1,"%c",&sign)==EOF) { j=1; break; }

if (sign=='\n')

{

break;

}

}

}

}

Poniżej zamieściłem fragment pliku z informacjami uzyskanymi z programu tcpdump:

18:03:01.508163 eth1 > Cyfronet > Cern : . 1:1(0) ack 19332249 win 24435 <nop,nop,timestamp 227037650 712800967> (DF)

18:03:01.508234 eth1 > Cyfronet > Cern : . 1:1(0) ack 19333697 win 24435 <nop,nop,timestamp 227037650 712800967> (DF)

18:03:01.512711 eth1 < Cern > Cyfronet : P 19333697:19335145(1448) ack 1 win 2920 <nop,nop,timestamp 712800970 227037645> (DF)

18:03:01.512829 eth1 < Cern > Cyfronet : P 19335145:19336593(1448) ack 1 win 2920 <nop,nop,timestamp 712800970 227037645> (DF)

18:03:01.512831 eth1 < Cern > Cyfronet: P 19336593:19338041(1448) ack 1 win 2920 <nop,nop,timestamp 712800970 227037645> (DF)

18:03:01.512862 eth1 > Cyfronet > Cern: . 1:1(0) ack 19335145 win 24435 <nop,nop,timestamp 227037651 712800970> (DF)

18:03:01.512873 eth1 > Cyfronet > Cern : . 1:1(0) ack 19338041 win 24435 <nop,nop,timestamp 227037651 712800970> (DF)

Podczas analizy, wyselekcjonowane i zapisane do pliku czasy wczytałem do arkusza kalkulacyjnego, gdzie obliczyłem występujące między nimi różnice.

Tabela 11.2 pokazuje poszczególne etapy analizy.

lokalizacja danych

plik źródłowy

plik wynikowy aplikacji

arkusz kalkulacyjny

(różnice)

czasy

18:03:01.512711

01,512711

0,000118

18:03:01.512829

01,512829

0,000002

18:03:01.512831

01,512831

Tabela 11.2. Etapy analizy danych do oszacowania przerw czasowych

Wykresy nr 1.1 2.1 3.1 (patrz Rys.11.3, Rys.11.4, Rys.11.5) zostały narysowane na podstawie wartości z trzeciej kolumny powyższej tabeli.

Dla oszacowania retransmisji (punkt drugi), napisałem aplikację analizującą dane sesji TCP z programu tcpdump uruchomionego na hoście odbiorczym, podobną do opisanej poprzednio.

Również wyszukuje w pliku linii, tym razem odpowiadających wysyłanym ACK, a następnie odczytuje i zapisuje potwierdzane numery sekwencyjne.

Algorytm działania jest bardzo podobny do poprzedniego(patrz Rys.11.2).

0x01 graphic

Rys. 11.2. Algorytm analizy retransmisji

Fragment kodu realizujący ww. operacje:

for (;j!=1;)

{

//sprawdzenie czy dana linia odpowiada wysłanemu potwierdzeniu

fseek(fd1,42,SEEK_CUR);

fscanf(fd1,"%c",&sign);

if (sign=='>')

{

//wczytanie i zapisanie do pliku potwierdzanego numeru sekwwencyjnego

fseek(fd1,28,SEEK_CUR);

fscanf(fd1,"%c",&sign);

if (sign!='a')

{

continue;

}

fseek(fd1,3,SEEK_CUR);

for (;;)

{

fscanf(fd1,"%c",&sign);

if (sign==' ') break;

fprintf(fd2,"%c",sign);

}

fprintf(fd2,"\n");

for (;;)

{

fscanf(fd1,"%c",&sign);

if (sign==EOF){ j=1; break; }

if (sign=='\n')

{

break;

}

}

}

else

{

for (;;)

{

if (fscanf(fd1,"%c",&sign)==EOF) { j=1; break; }

if (sign=='\n')

{

break;

}

}

}

Plik z informacjami analizowanymi przez aplikację, uzyskanymi z tcpdump jest taki jak opisany poprzednio.

Wyselekcjonowane i zapisane numery ACK wczytałem następnie do arkusza kalkulacyjnego, obliczając różnice występujące między nimi. Przy poprawnej transmisji powinny wynosić 1448B lub 2896B. W przypadku wystąpienia retransmisji z powodu nieodebrania danego segmentu, host odbiorczy generuje co najmniej trzy ACK o tym samym numerze.

W tej sytuacji co najmniej dwie kolejne różnice będą równe zero. W arkuszu kalkulacyjnym stworzyłem formułę, która potrafi rozróżnić opisane przypadki. Ponieważ głównym celem wykresu jest pokazanie ilości oraz miejsca wystąpień retransmisji, dlatego arkusz kalkulacyjny w przypadku poprawnej transmisji generuje wartość 0, natomiast gdy odkryje co najmniej trzy zdublowane ACK, wówczas taki przypadek flaguje wartością -1.

W Tabeli 11.3 zamieściłem poszczególne etapy analizy numerów potwierdzeń.

lokalizacja danych

plik źródłowy

plik wynikowy aplikacji

arkusz kalkulacyjny

(różnice)

arkusz kalkulacyjny

(flagi)

ACK

ack 19335145

19335145

2896

0

ack 19338041

19338041

2896

0

ack 19340937

19340937

ACK

ack 19335145

26575145

1448

0

ack 26576593

26576593

0

0

ack 26576593

26576593

0

-1

ack 26576593

26576593

Tabela 11.3. Etapy analizy danych do oszacowania retransmisji

Punkty wystąpień retransmisji na wykresach nr 1.1 2.1 3.1 (patrz Rys.11.3, Rys.11.4, Rys.11.5) zostały narysowane na podstawie danych z czwartej kolumny powyższej tabeli.

Wykresy nr 1.2 2.2 3.2 (patrz Rys.11.3, Rys.11.4, Rys.11.5) powstały w wyniku przetworzenia już istniejących danych. Pokazują średnie rozmiary przerwy czasowej pomiędzy kolejnymi otrzymywanymi pakietami, obliczone dla grup pakietów (1.1000,1001.2000... 19001.20000).

Wartości do tych wykresów wygenerowałem w arkuszu kalkulacyjnym, w którym zostały policzone wymagane średnie różnic.

    1. Uzyskane wyniki

0x01 graphic
0x01 graphic

Rys. 11.3. Charakterystyka ruchu odbieranego w Cyfronecie - wykresy serii 1

0x01 graphic
0x01 graphic

Rys. 11.4. Charakterystyka ruchu odbieranego w Cyfronecie - wykresy serii 2

0x01 graphic
0x01 graphic

Rys. 11.5. Charakterystyka ruchu odbieranego w Cyfronecie - wykresy serii 3

Na podstawie wykresów nr 1.2 2.2 3.2 można zauważyć kolejne etapy sesji TCP, włącznie z wpływem na ich przebieg ewentualnych retransmisji.

Transmisja TCP kontrolowana jest przez wiele mechanizmów zapewniających niezawodność dostarczenia danych (patrz rozdział 7.6). Wśród nich bezpośredni wpływ ma kontrola przepływu przy wykorzystaniu okna (liczba danych, które mogą zostać wysłane bez oczekiwania na potwierdzenie). Ostateczny jego rozmiar obliczany jest na hoście nadawczym, na podstawie danych rozgłaszanych przez komputer odbiorczy oraz własnych obliczeń.

Transmisja początkowo zaczyna się od tzw. wolnego startu. Gdy rozmiar okna przekroczy wartość ssthreshold, wówczas realizowany jest algorytm zapobiegający zatorom.

Dla wolnego startu rozmiar okna ulega zdublowaniu co około jeden RTT, natomiast dla drugiej fazy rośnie linowo, nie więcej niż jeden segment na RTT. Maksymalna wartość, jaka może zostać osiągnięta jest równa rozmiarowi okna rozgłoszonego przez hosta odbiorczego, zgodnie ze wzorem:

cur_wnd= min (cwnd , rwnd )

gdzie:

cur_wnd - właściwy rozmiar okna,

cwnd - okno obliczone na hoście nadawczym (slow start oraz algorytm zapobiegający zatorom)

rwnd - okno rozgłaszane przez hosta odbiorczego (na podstawie ilości dostępnego miejsca w buforze)

Schemat poszczególnych etapów byłby identyczny, gdyby nie retransmisje. Wśród nich możemy wyróżnić dwa rodzaje, związane z przyczyną ich powstania:

  1. spowodowane nie otrzymaniem przez hosta nadawczego w danym czasie (RTO) potwierdzenia wysłanych danych,

  2. spowodowane otrzymaniem przez hosta odbiorczego segmentów danych z większymi numerami sekwencyjnymi niż spodziewane. Wówczas wysyłane są ACK z numerem segmentu, który jest wymagany. Jeżeli strona nadawcza otrzyma co najmniej trzy takie zdublowane ACK, wtedy inicjuje retransmisję.

Po zrealizowaniu retransmisji z pierwszego przypadku, host nadawczy rozpoczyna transmisję od tzw. slow start, co powoduje, iż spadek ogólnej przepustowości jest znaczny.

Dla drugiej sytuacji strona nadawcza zmniejsza o połowę cwnd, a ssthreshold ustala na rozmiar cwnd plus jeden segment.

W każdym przypadku następuje spadek ogólnej wydajności, przy czym jest on znacznie większy dla retransmisji spowodowanej przekroczeniem czasu RTO dla danego segmentu.

Dla wykresów 1.2 2.2 3.2 można zauważyć, iż początkowy spadek średniej wartości opóźnień pomiędzy pakietami jest największy (przyrost rozmiaru okna wykładniczy - slow start), następnie maleje liniowo (algorytm związany z zatorami).

Przebieg taki utrzymuje swoje tendencje, aż do osiągnięcia czasu 500usec, który jest jednak zakłócany przez pojawiające się retransmisje.

Na podstawie wykresów można zaobserwować, iż retransmisje te spowodowane są otrzymaniem przez stronę nadawczą co najmniej trzech zdublowanych ACK. W innym przypadku wzrost średnich opóźnień byłby porównywalny do punktu startowego (slow start).

Przy bliższej analizie można zauważyć, iż dla grupy pakietów, w której wystąpiła retransmisja, średnia opóźnień wzrasta o około 450usec, następnie malejąc liniowo z tendencją do osiągnięcia wartości 500usec. Dla większej ilości retransmisji, efekt ulega kumulacji.

Średnia opóźnień pomiędzy pakietami odbieranymi w Cyfronecie wynosi około 500usec. Dla takiej wartości, przy rozmiarze danych 1448B, maksymalna przepustowość, jaką można uzyskać wynosi około 25Mb/s (w przypadku, gdy żaden pakiet nie ulegnie zagubieniu).

Dla osiągnięcia przepustowości 100Mb/s, czas ten powinien wynosić 125usec. Pytanie pojawiające się w tej sytuacji brzmi: dlaczego wartość 500usec jest tą minimalną i jaka jest jej przyczyna?

Poniżej zamieściłem w powiększeniu końcowy wycinek wykresu nr 3.1. ( patrz Rys.11.6 ).

0x01 graphic

Rys.11.6. Końcowy wycinek wykresu 3.1

Fragment ten można potraktować jako stabilny, nieobjęty wpływem retransmisji. Dla tych grup pakietów (18001-19000, 19001-20000), średnie opóźnień oscylują wokół 500usec. Na powiększeniu można zauważyć, iż występują serie, dla których czas wynosi około 125usec (wymagana wartość), jednak co około 60msec pojawiają się piki, pogarszające ogólną średnią. Wraz z kolejnymi otrzymanymi segmentami zmniejsza się liczba pakietów, składających się na dany pik, natomiast rośnie jego wartość.

W kolejnym pomiarze zostało pokazane, iż na pewno przyczyna takiej sytuacji nie tkwi w samej sieci a powinniśmy szukać jej po stronie nadawczej.

Ten sam host generujący pakiety uczestniczył w testach łącza 1Gb/s, w których dla TCP osiągnął rezultat 300Mb/s, dlatego można wykluczyć winę sprzętu.

Pozostaje sam algorytm TCP, decydujący o takim charakterze transmisji.

12. Porównanie charakterystyki ruchu TCP po stronie nadawczej i odbiorczej

12.1 Cel pomiaru

Celem pomiaru było sprawdzenie czy wina za powstałe średnie opóźnienia pomiędzy pakietami (patrz rozdział 11) leży po stronie sieci czy którejś ze stron.

12.2 Sposób przeprowadzenia pomiaru

Pomiar został wykonany na drodze CERN-CYFRONET dla jednego kierunku, przy zaalokowanym w tym celu kanale pomiędzy Poznaniem a Krakowem.

Podczas całej sesji pomiarowej na hoście odbiorczym oraz nadawczym był uruchomiony program tcpdump, zapisujący do pliku informacje z nagłówków segmentów, wysyłanych do CYFRONET-u w ramach danego połączenia. Ruch TCP wygenerowałem w oparciu o aplikację testującą (patrz rozdział 4).

W Tabeli 18.1 zamieściłem konfigurację obu komputerów.

TCP

KLIENT

SERWER

CERN

CYFRONET

rozmiar danych

1448B

1448B

liczba pakietów

20 000

20 000

MSS

1460B

1460B

window_clamp

-

800KB

no_delay

ON

ON

window_scaling

ON

ON

bufor odbiorczy

200KB

1,5MB

bufor nadawczy

1,5MB

200KB

Tabela 12.1. Konfiguracja klienta i serwera - pomiar TCP

W celu uzyskania odpowiednich danych wykonałem takie same czynności jak   w   poprzednim pomiarze a konkretnie w części, związanej z wyselekcjonowaniem czasów otrzymywania pakietów na hoście odbiorczym. Jedyna różnica polegała na tym, iż dokonałem analizy ruchu generowanego po stronie nadawczej.

W ten sposób mogłem narysować wykresy opóźnień dla obu węzłów i następnie dokonać ich porównania.

12.3 Uzyskane wyniki

Na podstawie uzyskanych danych narysowałem dwa wykresy (patrz Rys.12.1).

0x01 graphic
0x01 graphic

Rys.12.1 Wykresy ruchu generowanego w CERN-ie i odbieranego w Cyfronecie

Porównując oba wykresy można zauważyć, iż charakterystyka ruchu generowanego w CERN-ie jest taka sama jak odbieranego w Cyfronecie. Wynika z tego, iż powody powstania średnich opóźnień oscylujących wokół 500usec nie tkwią w sieci a po stronie nadawczej.

13. Podsumowanie

W wyniku przeprowadzonych pomiarów pomiędzy Europejskim Centrum Badań Jądrowych CERN pod Genewa, a Akademickim Centrum Komputerowym CYFRONET w Krakowie oszacowałem parametry określające jakość transmisji danych.

Dla badanej trasy wartości opóźnień w obu kierunkach wyniosły około 32msec, niezależnie od rozmiaru przesyłanych danych, intensywności generowanego ruchu czy kierunku transmisji. Różnice pojawiły się przy szacowaniu ilości pakietów zgubionych. Okazało się, iż trasa nie jest niezawodna, wykazując w tym przypadku asymetryczność. Pod tym względem lepsze rezultaty zostały uzyskane na kierunku CERN-CYFRONET, gdzie tylko dla górnych granic przepustowości zginęło kilka pakietów. Dla mniejszych przepustowości nie zarejestrowano gubienia danych. Na kierunku CYFRONET-CERN wartość ta okazała się znacznie większa. Już dla małych przepustowości można było zaobserwować ginięcie pakietów, przy górnych granicach intensywności generowanego ruchu, stanowiące 5% przesyłanych danych.

Powyższe rezultaty uzyskałem w wyniku testów z wykorzystaniem protokołu UDP.

Wydajność badanej trasy zmierzyłem dla ruchu opartego o UDP oraz TCP. Teoretycznie jej wartość powinna wynosić 100Mb/s (minimalna przepustowość trasy-zaalokowany kanał pomiędzy Krakowem a Poznaniem). Udało się ją osiągnąć wyłącznie dla UDP. Połączone to było z duża ilością gubionych pakietów, szczególnie dla kierunku CYFRONET-CERN.

Dla TCP początkowo otrzymałem wartości oscylujące wokół 15Mb/s. Następnie dokonałem optymalizacji parametrów mających wpływ na ogólną wydajność, jednak zabieg ten pozwolił zwiększyć uzyskiwane rezultaty tylko do 25Mb/s. Dokładniejsza analiza ruchu TCP pokazała, iż problem tkwi w samych algorytmach zaimplementowanych w tym protokole, które przy gubieniu pakietów sięgającym kilku procent oraz wyraźnej asymetryczności trasy reagują drastycznym spadkiem ogólnej wydajności.

Dodatek A - Satelitarny system nawigacyjny GPS

GPS (Global Positioning system) jest globalnym systemem, opartym na satelitarnych sygnałach radiowych, pozwalającym na dokładne określenie położenia, prędkości i czasu w dowolnym miejscu na kuli ziemskiej[9]. Kontrolowany przez Amerykański Departament Obrony zapewnia dwa poziomy dokładności przekazywanych danych, SPS oraz PPS. SPS jest standardowym systemem przeznaczonym dla użytkowników cywilnych, natomiast PPS, kodowanym, dostępnym tylko dla autoryzowanych odbiorców (zastosowania militarne).

Jak większość podobnych systemów, tak i ten źródło swoje ma w badaniach realizowanych na potrzeby wojska. W Laboratorium Fizyki Stosowanej Uniwersytetu Johnsa Hopkinsa pod koniec lat 50-tych prowadzono nasłuch sygnałów nadawanych przez satelitę Sputnik1. W trakcie tych obserwacji zauważono szczególne właściwości częstotliwości badanej fali nośnej wywołane efektem Dopplera, związanym z ruchem satelity względem miejsca, skąd wykonywano obserwacje. Skupiono się więc na analizach uzyskanych danych, zauważając pewne prawidłowości umożliwiające określenie położenia satelity.

Podjęte prace zaowocowały powstaniem w latach 1958-1962 systemu NNSS (Navy Navigation Satellite System), przeznaczonego do dokładnej nawigacji morskiej. W 1967 roku system udostępniono dla użytkowników cywilnych, wykorzystując go dodatkowo w geodezji oraz jako źródło częstotliwości wzorcowej. Posiadał on jednak swoje wady, m.in. niedokładność wyznaczania położenia sięgającą 200 m, długi czas pomiaru wynoszący od 6 do 18 minut oraz konieczność podawania prędkości oraz wysokości nad poziomem morza anteny odbiorczej. Także wachlarz jego zastosowań był początkowo ograniczony.

Cały czas trwały prace mające na celu ulepszenie systemu związane m.in. ze zwiększeniem precyzyjności czy zmniejszeniem ograniczeń, jakim początkowo podlegały odbiorniki GPS. Zwiększano liczbę satelitów nadawczych, ulepszano ich właściwości, układ konstelacyjny, rozwijano metody pomiarowe pozwalające na dokładniejsze i szybsze obliczenia.

Obecnie system składa się z trzech podstawowych segmentów: kosmicznego, kontrolnego oraz użytkowego.

Segment kosmiczny stanowią 24 satelity operacyjne oraz 3 rezerwowe, rozlokowane w taki sposób, aby w przypadku awarii nawet kilku podstawowych, system mógł funkcjonować skutecznie (patrz Rys.A.1). Satelity poruszają się po sześciu orbitach na wysokości 20 000 km nad powierzchnią ziemi, nachylonych do niej pod kątem 55°. Dodatkowo odpowiednie rozmieszczenie sprawia, iż w dowolnym miejscu na ziemi co najmniej cztery z nich są widoczne, co stanowi warunek konieczny do wyznaczenia dokładnego położenia i czasu dla odbiornika GPS (patrz Rys.A.3, Rys.A.4). Każdy satelita emituje sygnały radiowe na częstotliwościach L1 i L2.

0x01 graphic

Rys.A.1. Układ satelitów [9]

Przez około 40% doby z każdego punktu globu ziemskiego można jednocześnie obserwować 8 satelitów, przez 85% doby jest widocznych 7-10 satelitów, a przez mniej niż 1% 5 lub 11-12 satelitów (patrz Rys.A.2).

0x01 graphic

Rys.A.2. Liczba jednocześnie widocznych satelitów w ciągu doby [9]

0x01 graphic

Rys.A.3. Widzialność satelitów z równika [9]

0x01 graphic

Rys.A.4. Widzialność satelitów z bieguna [9]

Segment kontrolny (patrz Rys.A.5) składa się z:

0x01 graphic

Rys.A.5. Rozmieszczenie stacji segmentu kontrolnego [9]

Główna stacja kontrolna gromadzi i analizuje informacje o poruszających się satelitach, dostarczone przez stacje monitorujące. Oblicza aktualne, właściwe orbity satelitów i parametry zegarów, a następnie przesyła je do stacji kontrolnych, mających bezpośrednią łączność z satelitami.

Stacje monitorujące wykonują nieprzerwane obserwacje wszystkich satelitów, rejestrując kolejne pomiary co 1,5s. Wyniki zbierane w zbiory 15minutowe, przesyłane są następnie przez wojskowy system łączności (DSCS) do głównej stacji kontroli.

Stacje kontrolne, przy wykorzystaniu anten telemetrycznych utrzymują bezpośrednią łączność z poruszającymi się satelitami, wysyłając odpowiednie uaktualnienia i poprawki otrzymane z głównej stacji kontrolnej, zapewniające dokładność funkcjonowania całego systemu (patrz Rys.A.6.).

0x01 graphic

Rys.A.6. Łączność pomiędzy satelitami i stacjami kontrolnymi [9]

Segment użytkowników składa się z wielu różnych odbiorników radionawigacyjnych, przystosowanych do odbioru, dekodowania i przetwarzania sygnałów satelitarnych, umożliwiających ustalenie takich parametrów, jak: położenie odbiornika, prędkość, czas, itp. W tym celu muszą określić lokalizację oraz odległość do satelitów.

Odbiorniki GPS pobierają dwa rodzaje zakodowanych parametrów. Pierwsze z nich to tzw. almanac, zawierające szacunkowe informacje o położeniu satelitów. Transmisja ich odbywa się w sposób ciągły a odbiorniki zapamiętują pobrane dane w pamięci. Periodycznie, wraz ze zmianą położenia satelitów, następuję ich aktualizacja. Dzięki temu parametrowi odbiornik może oszacować konstelację segmentu kosmicznego.

Jak wcześniej zostało wspomniane, stacje monitorujące obserwują układ satelitów, określając ich parametry, które następnie zostają wysłane do głównej stacji kontrolnej. Tam następuje obliczenie poprawek i przesłanie precyzyjnych danych do satelitów. Parametry te stanowią drugi rodzaj zakodowanych informacji pobieranych przez odbiorniki (tzw. ephemeris) i pozwalają określić ich dokładne położenie.

W celu wyznaczenia odległości od satelity, odbiornik na początku określa, jaki czas upływa od momentu wygenerowania do pobrania danego sygnału. Procedura jest następująca. Satelita generuje tzw. pseudolosowykod, przyrównywany do zwykłego szumu. Odbiornik pobiera go i wytwarza własny, podobny. Następnie porównuje oba kody i oblicza przesunięcie, jakie musi wykonać, aby je dopasować. Ten parametr czasowy określa potrzebne opóźnienie, które następnie po przemnożeniu przez prędkość światła daje w rezultacie odległość od satelity. W międzyczasie odbiornik może skorygować własny zegar na podstawie precyzyjnego czasu satelity i obliczonego offsetu.

Dodatek B - GEANT

0x01 graphic

Rys.B.1. Struktura sieci GEANT [10]

GEANT jest siecią naukowo-badawczą zarządzaną przez firmę Dante[10], obejmującą swym zasięgiem większość krajów europejskich. Łączy ponad 3000 instytutów z 32 krajów. Zapewnia również komunikację do jej odpowiedników na innych kontynentach (m.in. w Azji, Ameryce Północnej).

Głównym jej celem jest utworzenie platformy badawczej dla poszczególnych instytutów naukowych, ułatwiającej przeprowadzanie nowych pomiarów i projektów, poprzez zapewnienie globalnej łączności.

Wykorzystana technologia umożliwia osiągnięcie na pewnych odcinkach prędkości transmisji sięgających 10Gb/s (patrz Rys.B.1).

Dziewięć połączeń oferuje powyższą przepustowość, natomiast jedenaście 2,5Gb/s. Pozostałe pracują z szybkością 155Mb/s oraz 622Mb/s.

GEANT zapewnia QoS (Quality of Service), poprzez zastosowanie nowych funkcji w oparciu o protokół IP. Stanowi to sprawę priorytetową dla nowych aplikacji oraz implementacji wirtualnych sieci prywatnych, na potrzeby projektów i uczestniczących w nich grup naukowców.

Spis Rysunków

Spis Tabel

Literatura

[1] http://www.atlasexperiment.org

[2] Dobinson, B., Remote real time farms for the ATLAS experiment, Status Report, 2003.

[3] http://www.meinberg.de/english/products

[4] Brezuleanu, M., Ciobotaru, M., and Meirosu, C., GPS Synchronization, Status Report, 2002.

[5] Gay, W., W., Linux gniazda w programowaniu w przykładach, MIKOM, Warszawa 2001.

[6] Stevens, W., R, Unix Network Programming Volume 1, PTR, Upper Saddle River 1998.

[7] Wall, K., Linux Programowanie w przykładach, MIKOM, Warszawa 2000.

[8] Stevens, W., R., TCP/IP Illustrated volume 1, Longman, Addison Wesley 1999.

[9] Lamparski, J., Navstar GPS od teorii do praktyki, UWM, Olsztyn 2001.

[10] http://www.dante.net/geant

21



Wyszukiwarka

Podobne podstrony:
Prezentacja praca dyplom
Praca dyplomowa Strona tytułowa etc
PRACA DYPLOMOWA BHP - ORGANIZACJA PRACY W PSP, TEMATY PRAC DYPLOMOWYCH Z BHP
praca dyplomowa 1 strona wzor, Szkoła, prywatne, Podstawy informatyki
d druku BIBLIOGRAFI1, cykl VII artererapia, Karolina Sierka (praca dyplomowa; terapia pedagogiczna z
Praca dyplomowa(1)
streszczenie panelu, Prace dyplomowe i magisterskie, praca dyplomowa, materiały z internetu
praca dyplomowa BR5VQ5NYN263L77S7YKAVS66LCHECBHKF2E3GEQ
praca dyplomowa informatyka programowanie 7B5PTOE5KXERFXSEJISGCMFJDQ5X6LRRZEBNOJY
praca dyplomowa
praca dyplomowa edycja wbn1 2011
PRACA DYPLOMOWA MAGISTERSKA OCZ SC TYPU LEMMNA
Internet - UE prawo, Studia - IŚ - materiały, Semestr 07, Praca dyplomowa
do druku ROZDZIAŁ III, cykl VII artererapia, Karolina Sierka (praca dyplomowa; terapia pedagogiczna
PRACA DYPLOMOWA SPIS TREŚCI, TEMATY PRAC DYPLOMOWYCH Z BHP
strona tytulowa, WNPiD, moje, praca dyplomowa
inżynierska praca dyplomowa wzorzec
Wytwarzanie biogazu - wysypisak śmieci., Studia - IŚ - materiały, Semestr 07, Praca dyplomowa

więcej podobnych podstron