Serwery oparte o protokół TCP, a więc m.in. serwery www (protokół HTTP) lub przekazywania poczty elektronicznej (protokół SMTP) wykorzystują gniazdka do przesyłania lub odbierania danych. Gdy przykładowo przeglądarka www chce ściągnąć zawartość podanej strony to tworzy tzw. połączenie z serwerem. Do utworzenia takiego połączenia serwer udostępnia właśnie takie gniazdko. Po nawiązaniu komunikacji przeglądarka pyta się serwer o dane wysyłając żądania. Przyjęło się, że taki sposób komunikacji implementuje się za pomocą wątków. Nazwijmy ten model "wątek per połączenie". Jest to prosty i sprawdzony sposób, jednak jak się za chwilę okaże nie do końca efektywny. Jeden rdzeń procesora jest w stanie uruchamiać jedną komendę w jednostce czasu, w związku z czym dla każdego tworzonego połączenia między przeglądarką a serwerem tworzony jest wątek po stronie serwera. Dlatego im więcej użytkowników korzysta właśnie z serwisu tym więcej uruchomionych jest wątków.
W przypadku zapytań o zasoby generowane dynamicznie czyli np. strony HTML serwer musi najpierw uruchomić kod programisty (jakąś akcję, skrypt itp.), a następnie zwrócić do przeglądarki odpowiedź. Nierzadko czas jaki przeglądarka musi spędzić na oczekiwaniu na odpowiedź trwa kilka lub kilkanaście sekund i jest to spowodowane długim czasem uruchamiania właśnie tego kodu. Powodów tak długiego czasu przetwarzania może być wiele, jednak w dużej liczbie przypadków jest to spowodowane oczekiwaniem na tzw. "zewnętrzne zasoby", czyli np. oczekiwanie na zakończenie operacji na dysku twardym, zakończenie wykonywania się zapytania w bazie danych czy wreszcie oczekiwanie na odpowiedź usługi zdalnej. Model "wątek per połączenie", który opisuję zakłada, iż pomimo tego, że w czasie oczekiwania na zewnętrzny zasób kod nie wykonuje żadnej operacji to i tak zajmuje cenne miejsce w pamięci RAM, a nawet spowalnia pracę serwera.
Aby zrozumieć potrzebę wykorzystania serwerów sterowanych zdarzeniami trzeba najpierw wyobrazić sobie sytuacje, w której nasz serwer ma za zadanie obsłużyć bardzo wiele żądań jednocześnie - niech będzie to 1000 żądań w ciągu jednej sekundy. W modelu wątek per połączenie z początku utworzonych zostanie tysiąc wątków. Załóżmy, że kod programisty podczas obsługi żądania uruchamia zewnętrzną usługę - niech to będzie jakaś usługa udostępniania przez Facebook. Niech czas odpowiedzi tych usług wynosi średnio 5 sekund. Wynika z tego, że ów 1000 żądań nie ma szans uruchomić się w ciągu jednej sekundy, ponieważ żądanie się nie zakończy dopóki zewnętrzna usługa nie odpowie. Dlatego po pięciu sekundach liczbą wątków będzie już wynosić 5 tysięcy i mniej więcej na tym poziomie będzie się utrzymywać zakładając, że tysiąc żądań będzie uruchamianych w każdej sekundzie. Wykorzystywanych jest więc 5 tysięcy wątków, pomimo, iż kod ten nie robi nic poza czekaniem na odpowiedź z zewnętrznej usługi. Do obsługi tak dużej ilości wątków potrzeba jest już sporej ilości pamięci RAM, co znacznie obciąża serwer. Poniżej wykres prezentujący wykorzystanie wątków na przestrzeni czasu.
![]() |
| Wykorzystanie liczby wątków na przestrzeni czasu |


Hej Jacku, interesujący tekst. Polinkuj ze sobą wszystkie wpisy z serii. Będzie nam łatwiej nawigować :)
OdpowiedzUsuńDzięki za komentarz :) Dodałem linki między wpisami. Myślę, że zabrakło tu też jakiegoś głównego posta, który linkowałby do wszystkich części w jednym miejscu (do czasu jak go dodam można użyć etykiety: http://blogger.trycatch.pl/search/label/nieblokuj%C4%85ce%20serwery%20sterowane%20zdarzeniami )
UsuńLink raz jeszcze w wygodniejszej formie :)
Usuń