2010-05-14 5 views
36

Mam zaprojektować serwer, który musi obsługiwać miliony klientów, które są jednocześnie połączone z serwerem za pośrednictwem protokołu TCP.Jak zatrzymać milion jednoczesnych połączeń TCP?

Ruch danych między serwerem a klientami będzie niewielki, dlatego problemy z przepustowością mogą zostać zignorowane.

Jednym z ważnych wymagań jest to, że gdy serwer musi wysłać dane do dowolnego klienta, powinien użyć istniejącego połączenia TCP zamiast otwierania nowego połączenia w kierunku klienta (ponieważ klient może znajdować się za zaporą).

Czy ktoś wie, jak to zrobić, a jaki sprzęt/oprogramowanie jest potrzebne (przy najniższym koszcie)?

+2

Czy to musi być protokół TCP? Jeśli ruch jest niewielki, koszt śledzenia wszystkich połączeń może być nieuzasadniony wysoki. A czy mógłbyś trochę wyjaśnić, co zrobi serwer? Milion aktywnych połączeń, które nie są aktywnie używane, wydaje mi się podejrzany. – VladV

Odpowiedz

19

Jakie systemy operacyjne rozważasz w tym celu?

Jeśli używasz systemu operacyjnego Windows i używasz czegoś później niż Vista, nie powinieneś mieć problemu z wieloma tysiącami połączeń na jednym komputerze. Uruchomiłem testy (tutaj: http://www.lenholgate.com/blog/2005/11/windows-tcpip-server-performance.html) z niską specyfikacją systemu Windows Server 2003 i łatwo osiągnąłem ponad 70 000 aktywnych połączeń TCP. Niektóre limity zasobów, które mają wpływ na liczbę możliwych połączeń, zostały znacznie podniesione w systemie Vista (patrz tutaj: http://www.lenholgate.com/blog/2005/11/windows-tcpip-server-performance.html), więc możesz prawdopodobnie osiągnąć swój cel za pomocą małej grupy komputerów. Nie wiem, czego potrzebujesz przed tymi, którzy kierują połączeniami.

System Windows udostępnia obiekt o nazwie Porty ukończenia operacji wejścia/wyjścia (zobacz: http://msdn.microsoft.com/en-us/magazine/cc302334.aspx), które umożliwiają obsługę wielu tysięcy równoczesnych połączeń przy użyciu bardzo niewielu wątków (wczytałem wczoraj testy z 5000 połączeń przesyłających łącze do serwera za pomocą 2 wątki do przetwarzania I/O ...). Zatem podstawowa architektura jest bardzo skalowalna.

Jeśli chcesz uruchomić kilka testów, to mam na swoim blogu kilka darmowych narzędzi, które pozwalają ci na wyrzucenie prostego serwera echa za pomocą wielu tysięcy połączeń (1) i (2) i trochę darmowego kodu, którego możesz użyć na początek (3)

Druga część twojego pytania, z twoich komentarzy, jest trudniejsza. Jeśli adres IP klienta ciągle się zmienia i nie ma nic między Tobą a nim, który zapewnia NAT w celu uzyskania spójnego adresu IP, wtedy ich połączenia bez wątpienia zostaną przerwane i trzeba będzie je przywrócić. Jeśli klienci wykryją to połączenie, oderwij się, gdy ich adres IP ulegnie zmianie, wtedy mogą ponownie połączyć się z serwerem, jeśli tego nie zrobi, sugerowałbym, aby klienci musieli odpytywać serwer co jakiś czas, aby wykryć utratę połączenia i na nowo połączyć. Nie ma tu nic, co mógłby zrobić serwer, ponieważ nie jest w stanie przewidzieć nowego adresu IP i odkryje, że stare połączenie nie powiodło się podczas próby wysłania danych.

I pamiętaj, że twoje problemy dopiero zaczynają, gdy pojawi się system skalowania do tego poziomu ...

+1

Twój EchoServerTest jest OK, ale jak możemy przetestować połączenia ponad 64k? Klient ma limit portów 64k – onmyway133

+1

Wiele komputerów klienckich. Musisz to teraz zrobić ręcznie, ponieważ nie znalazłem potrzeby napisania testowania sieciowego klienta, który można uruchomić z pojedynczego komputera z niewolnikami na innych komputerach (jest na mojej liście rzeczy do zrobienia ...). –

+1

W systemie Linux można również użyć aliasów adresów IP na komputerze klienckim; każdy alias IP da ci dodatkowe 65 000 klientów. –

11

Ten problem jest związany z tak zwanym problemem o nazwie C10K. Strona C10K zawiera listę wielu dobrych zasobów do rozwiązania problemów, które napotkasz, próbując zezwolić tysiącom klientów na połączenie się z tym samym serwerem.

+0

dzięki za odpowiedź. ale osobiście nie uważam, że to ten sam problem. Chcę wiedzieć, jak utrzymywać stałe połączenia klientów podłączonych do sieci 1M, NIE akceptować żądań połączeń ani nie wykrywać zmiany statusu połączenia. dzięki mimo to. – cow

+0

@cow: Nie ma nic szczególnie trudnego w utrzymywaniu klientów w kontakcie - co sprawia, że ​​myślisz, że będzie? To daleko od najtrudniejszej części problemu. – caf

+0

co jeśli klienci znajdują się w sieci, w której ich adresy IP mogą być często zmieniane. Na przykład mam telefon T-Mobile G1. Zauważyłem, że adres IP mojego telefonu często się zmienia.nawet jeśli telefon ma połączenie TCP z jakimś serwerem poza siecią T-Moble, gdy nie ma danych przepływających przez połączenie, szansa, że ​​adres IP telefonu zostanie zmieniony, jest duża; po zmianie adresu IP każde połączenie TCP jest zepsute. właśnie dlatego mam problem. – cow

-4

EDIT: Jak wspomniano w komentarzach poniżej, moje oryginalne twierdzenie, że istnieje granica 64K na podstawie liczby portów jest błędne, jednak nie jest limit 32K od liczby gniazdo obsługuje, więc moja sugerowany projekt jest ważny.

Przy typowym projekcie serwera TCP/IP masz ograniczoną liczbę jednoczesnych otwartych połączeń, jakie możesz mieć. Serwer ma jeden port nasłuchujący, a gdy klient się z nim łączy, serwer wykonuje połączenie akceptujące i tworzy nowe gniazdo na losowym porcie dla pozostałej części połączenia.

Aby obsłużyć więcej niż 64K jednoczesnych połączeń, myślę, że musisz użyć UDP zamiast tego. Potrzebujesz tylko jednego portu, aby serwer mógł nasłuchiwać, i musisz zarządzać połączeniami za pomocą 32-bitowego identyfikatora klienta w danych pakietowych, zamiast mieć osobny port dla każdego klienta. 32-bitowy identyfikator klienta może być adresem IP klienta, a klient może nasłuchiwać na znanym porcie UDP dla wiadomości przychodzących z serwera. Ten port będzie jedynym, który musi być otwarty na zaporze.

W ten sposób jedynym ograniczeniem jest szybkość obsługi wiadomości UDP i odpowiedzi na nie. Mając miliony klientów, nawet niewielki ruch może spowodować duże skoki, a jeśli nie odczytasz pakietów wystarczająco szybko, twoja kolejka wejściowa wypełni się i zaczniesz upuszczać pakiety. Strona Greg C10K wskazuje na strategie na to.

+1

Wiele połączeń klientów z serwerem nie korzysta z dodatkowych portów * serwera *. Nadal będą ograniczenia techniczne, ale nie jest to liczba portów. Połączenia są identyfikowane po stronie serwera przy użyciu unikatowej 4-tki (serwer_ip, port_serwera, numer_klienta, port_klienta). Być może myślisz o * uchwytach * gniazd, w których pojawia się gniazdo serwera, które odradza więcej uchwytów gniazd za pomocą wywołania 'accept()'. –

+0

Hmm. Tak, myślę, że masz rację. http://linux.die.net/man/2/accept mówi, że akceptacja zakończy się niepowodzeniem, jeśli zabraknie deskryptorów plików, a nie portów. Zajrzałem do kodu źródłowego jądra Linuksa i z tego co wiem, maksymalna liczba plików jest przekazywana jako int. To prawdopodobnie ogranicza cię do deskryptorów plików 32K, ale będzie się różnić w zależności od platformy. Nie mam racji, jeśli chodzi o szczegóły, dlaczego TCP jest ograniczony, ale myślę, że jest nadal ograniczony i UDP jest wykonalną alternatywą. – DougWebb

+0

dzięki za uwagi od was obu. Widziałem stronę c10k kilka tygodni temu. pamiętam, że sugeruje to epoll(). chciałbym móc go używać z UDP. Jakkolwiek, jak wiem, epoll nie ma znaczenia dla serwera UDP, który ma tylko jedno gniazdo do odbioru, czy mam rację? Pilność szybkiego odczytywania pakietów jest ważna. jednak nie mogę wymyślić lepszego sposobu, aby czytać szybciej niż przy użyciu dedykowanego wątku do odczytu pakietów z gniazda UDP i umieścić je w kolejce do wątków roboczych do konsumpcji. czy mógłbyś doradzić lepsze metody? Z góry bardzo dziękuję. – cow

4

Po pewnym czasie natknąłem się na APE Project . Wydaje się, że marzenie się spełniło. Mogą obsługiwać do 100 000 równoczesnych klientów w jednym węźle. Rozłóż je na 10 lub 20 węzłach i możesz obsłużyć miliony. Idealny do zastosowań RESTful. Może chcieć zagłębić się we wspólną przestrzeń nazw. Wadą jest to, że jest to samodzielny serwer, jako uzupełnienie serwera WWW. Ten serwer to oczywiście Open Source, więc wszelkie koszty związane są ze sprzętem/usługodawcą internetowym.

+0

dzięki za informacje. ale moja aplikacja nie jest oparta na sieci. Jak mogę wykorzystać APE? – cow

+0

Możesz używać APE bez przeglądarki. Wykorzystują domyślny protokół (możesz stworzyć własny: http://www.ape-project.org/wiki/index.php/Protocol) Możesz napisać własną bibliotekę, aby zarządzać połączeniami z wybranym językiem, używając ich " Schemat APE Javascript "jako odniesienie. – Vic

+0

dzięki jeszcze raz. Sprawdzę protokół, aby sprawdzić, czy dobrze jest zastąpić mój własny kodowany binarnie protokół APE. – cow

0

Nie można używać UDP. Jeśli klient wyśle ​​żądanie i nie odpowiesz natychmiast, router zapomni o odwrotnej trasie w 30 sekund lub mniej, więc twój serwer nigdy nie będzie w stanie odpowiedzieć klientowi.

TCP jest jedyną opcją, która również da ci ból głowy. Większość routerów zapomni o trasie i/lub zrzuci połączenie po kilku minutach, więc twój kod klienta/serwera będzie musiał wysyłać "keep alives" dość często.

Polecam skonfigurować "sniffer", aby zobaczyć, jak firmy telekomunikacyjne pozostają w kontakcie ze smartfonem pod kątem technologii "push". Skopiuj wszystko, co robią, ponieważ te rzeczy działa!

0

Jak wspomniał Greg, problem, który opisujesz, to C10K (lub raczej "C1M" w twoim przypadku) Niedawno stworzyłem prosty serwer TCP echo na platformie linux, który bardzo dobrze skaluje się z liczbą sesji (tylko testowane do 200 000) za pomocą kolejki epoll. Na BSD masz coś podobnego o nazwie kqueue. Jeśli chcesz, możesz sprawdzić numer code. Mam nadzieję, że to pomoże i powodzenia!