Moje rozumienie odpytywania HTTP, długiego odpytywania, przesyłania strumieniowego HTTP i WebSockets

123

Przeczytałem wiele postów w SO iw Internecie dotyczących słów kluczowych w tytule mojego pytania i wiele się z nich nauczyłem. Niektóre z pytań, które czytam, dotyczą konkretnych wyzwań wdrożeniowych, inne dotyczą ogólnych pojęć. Chcę się tylko upewnić, że zrozumiałem wszystkie koncepcje i powody, dla których wynaleziono technologię X zamiast technologii Y i tak dalej. Więc oto idzie:

Sondowanie HTTP: zasadniczo AJAX, przy użyciu XmlHttpRequest.

Http Long Polling: AJAX, ale serwer wstrzymuje odpowiedź, chyba że serwer ma aktualizację, gdy tylko serwer ma aktualizację, wysyła ją, a następnie klient może wysłać kolejne żądanie. Wadą są dodatkowe dane nagłówka, które muszą być przesyłane tam iz powrotem, powodując dodatkowe obciążenie.

Strumieniowanie HTTP: Podobny do długiego odpytywania, ale serwer odpowiada nagłówkiem „Transfer Encoding: chunked”, a zatem nie musimy inicjować nowego żądania za każdym razem, gdy serwer wysyła jakieś dane (i dlatego zapisuje dodatkowy nagłówek narzutu). Wadą jest to, że musimy „zrozumieć” i wymyślić strukturę danych, aby rozróżnić wiele fragmentów wysyłanych przez serwer.

Aplet Java, Flash, Silverlight: zapewniają możliwość łączenia się z serwerami gniazd przez tcp / ip, ale ponieważ są to wtyczki, programiści nie chcą na nich polegać.

WebSockets: są to nowe API, które próbuje rozwiązać wady powyższych metod w następujący sposób:

  • Jedyną zaletą WebSockets w porównaniu z wtyczkami, takimi jak aplety Java, Flash czy Silverlight jest to, że WebSockets są natywnie wbudowane w przeglądarki i nie polegają na wtyczkach.
  • Jedyną zaletą WebSockets w porównaniu do przesyłania strumieniowego HTTP jest to, że nie trzeba się wysilać, aby „zrozumieć” i przeanalizować otrzymane dane.
  • Jedyną zaletą WebSockets w porównaniu z Long Polling jest eliminacja dodatkowego rozmiaru nagłówków oraz otwieranie i zamykanie połączenia gniazda na żądanie.

Czy są jakieś inne istotne różnice, których mi brakuje? Przepraszam, jeśli ponownie zadaję lub łączę wiele pytań już na SO w jedno pytanie, ale chcę po prostu nadać doskonały sens wszystkim informacjom, które są dostępne w SO i sieci, dotyczące tych koncepcji.

Dzięki!

Software Guy
źródło
4
Wydarzenia wysyłane przez serwer mogą być również warte obejrzenia, gdy nie potrzebujesz komunikacji dwukierunkowej.
leggetter
1
To naprawdę przydatne pytanie. Myślę, że potencjalnie byłoby bardziej przydatne, gdyby istniała jedna odpowiedź, do której mogłoby się przyczynić wielu autorów.
leggetter
@leggetter Dzięki Phil, dzięki za wskazówkę dotyczącą zdarzeń wysłanych przez serwer. Jestem zainteresowany poznaniem scenariuszy komunikacji dwukierunkowej. dzięki.
Software Guy
1
W przypadku przesyłania strumieniowego HTTP i długiego odpytywania potrzebne jest drugie połączenie do komunikacji dwukierunkowej. Jedno dłuższe połączenie dla serwera -> komunikacja „push” klienta i drugie krótkotrwałe połączenie dla klienta -> komunikacja z serwerem. To drugie połączenie służy do wykonywania takich czynności, jak konfigurowanie i zmiana subskrypcji danych. Tak więc EventSource może być używany w rozwiązaniu dwukierunkowym i w rzeczywistości jest standardowym rozwiązaniem zrodzonym z HTTP Streaming i Long-Polling.
leggetter
1
Możesz również sprawdzić tę klasyfikację technik, które napisałem: stackoverflow.com/questions/12078550/ ...
Alessandro Alinone

Odpowiedzi:

92

Jest więcej różnic niż te, które zidentyfikowałeś.

Duplex / kierunkowe:

  • Jednokierunkowe: ankieta HTTP, długa ankieta, przesyłanie strumieniowe.
  • Bi-direcitonal: WebSockets, sieć wtyczek

W kolejności rosnącego opóźnienia (przybliżona):

  • WebSockets
  • Sieć wtyczek
  • Przesyłanie strumieniowe HTTP
  • Długie sondowanie HTTP
  • Odpytywanie HTTP

CORS (obsługa wielu źródeł):

  • WebSockets: tak
  • Sieć wtyczek: Flash przez żądanie zasad (brak pewności co do innych)
  • HTTP * (niektóre najnowsze wsparcie)

Natywne dane binarne (tablice typowane, obiekty blob):

  • WebSockets: tak
  • Sieć wtyczek: nie z Flash (wymaga kodowania adresu URL w interfejsie ExternalInterface)
  • HTTP *: ostatnia propozycja włączenia obsługi typu binarnego

Szerokość pasma przy malejącej wydajności:

  • Sieć wtyczek: gniazda Flash są nieprzetworzone, z wyjątkiem początkowego żądania zasad
  • WebSockets: uzgadnianie konfiguracji połączenia i kilka bajtów na ramkę
  • Streaming HTTP (ponowne wykorzystanie połączenia z serwerem)
  • HTTP long-poll: połączenie dla każdej wiadomości
  • Sonda HTTP: połączenie dla każdej wiadomości + brak wiadomości z danymi

Obsługa urządzeń mobilnych:

Złożoność użycia JavaScript (od najprostszych do najbardziej skomplikowanych). Trzeba przyznać, że miary złożoności są nieco subiektywne.

  • WebSockets
  • Sonda HTTP
  • Sieć wtyczek
  • Długa ankieta HTTP, przesyłanie strumieniowe

Należy również zauważyć, że istnieje propozycja W3C dotycząca standaryzacji przesyłania strumieniowego HTTP o nazwie Zdarzenia wysyłane przez serwer . Obecnie jest dość wcześnie w swojej ewolucji i został zaprojektowany w celu zapewnienia standardowego interfejsu API JavaScript z porównywalną prostotą do WebSockets.

kanaka
źródło
1
Wielkie dzięki za miłą odpowiedź Kanaka. Czy możesz mi powiedzieć, dlaczego / w jaki sposób przesyłanie strumieniowe HTTP ma większe opóźnienia niż gniazda sieciowe? może na prostym przykładzie? wielkie dzięki.
Software Guy
2
@SoftwareGuy. Wiele powodów. W najnowszych przeglądarkach można użyć procedury obsługi zdarzeń XMLHTTPRequest onprogress, aby otrzymywać powiadomienia o danych. Ale specyfikacja mówi, że 50 ms to najmniejszy interwał powiadomień. W przeciwnym razie musisz sondować w celu uzyskania danych odpowiedzi. Ponadto wysyłki klienta ustanawiają nowe połączenie HTTP i znacznie zwiększają opóźnienie w obie strony. Ponadto wiele serwerów internetowych przerywa połączenia HTTP po około 30 sekundach, co oznacza, że ​​często trzeba ponownie nawiązywać połączenie push z serwerem. Widziałem opóźnienia w obie strony WebSocket 5-10 ms w sieci lokalnej. Opóźnienie przesyłania strumieniowego HTTP prawdopodobnie wyniesie 50 ms +.
kanaka,
Wielkie dzięki za szczegółową odpowiedź :)
Software Guy
1
@leggetter Dzięki Phil, masz na myśli, że wysyłanie danych z klienta na serwer za pośrednictwem przesyłania strumieniowego HTTP spowoduje narzut? czy wysyłanie danych do serwera jest możliwe nawet przez streaming http bez otwierania nowego połączenia? Dzięki.
Software Guy,
1
@Nathan brzmi jak dobry projekt pracy magisterskiej! Z pewnością odpytywanie spowoduje, że system będzie bardziej zajęty niż model sterowany zdarzeniami, ale to, co dokładnie mogłoby oznaczać oszczędności energii, wymagałoby dość obszernych testów empirycznych w różnych skalach.
kanaka
13

Kilka świetnych odpowiedzi od innych, które obejmują wiele zagadnień. Oto trochę więcej.

Jedyną zaletą WebSockets w porównaniu z wtyczkami, takimi jak aplety Java, Flash czy Silverlight jest to, że WebSockets są natywnie wbudowane w przeglądarki i nie polegają na wtyczkach.

Jeśli przez to masz na myśli, że możesz użyć apletów Java, Flash lub Silverlight do ustanowienia połączenia przez gniazdo, to tak, to jest możliwe. Jednak nie widzisz tego zbyt często w prawdziwym świecie ze względu na ograniczenia.

Na przykład pośrednicy mogą i wyłączają ten ruch. Standard WebSocket został zaprojektowany tak, aby był kompatybilny z istniejącą infrastrukturą HTTP, dzięki czemu jest znacznie mniej podatny na ingerencję pośredników, takich jak zapory i serwery proxy.

Co więcej, WebSocket może używać portów 80 i 443 bez konieczności stosowania dedykowanych portów, również dzięki projektowi protokołu, który jest możliwie jak najbardziej kompatybilny z istniejącą infrastrukturą HTTP.

Te alternatywy gniazd (Java, Flash i Silverlight) są trudne w bezpiecznym użyciu w architekturze między źródłami. Dlatego ludzie, którzy często próbują ich używać w różnych miejscach, będą tolerować niepewność, zamiast podejmować wysiłki, aby robić to bezpiecznie.

Mogą również wymagać otwarcia dodatkowych „niestandardowych” portów (coś, czego administratorzy nie lubią robić) lub plików zasad, którymi trzeba zarządzać.

Krótko mówiąc, używanie Java, Flash lub Silverlight do łączenia się z gniazdami jest na tyle problematyczne, że nie widać go zbyt często w poważnych architekturach. Flash i Java mają taką możliwość od prawdopodobnie co najmniej 10 lat, a jednak nie są one powszechne.

Standard WebSocket mógł zacząć od nowego podejścia, mając na uwadze te ograniczenia i miejmy nadzieję, że wyciągnął z nich pewne wnioski.

Niektóre implementacje WebSocket używają Flasha (lub prawdopodobnie Silverlight i / lub Java) jako rozwiązania zastępczego, gdy nie można ustanowić łączności WebSocket (na przykład podczas uruchamiania w starej przeglądarce lub gdy przeszkadza pośrednik).

Chociaż jakaś strategia awaryjna w takich sytuacjach jest sprytna, a nawet konieczna, większość tych, którzy używają Flasha i innych, będzie cierpieć z powodu opisanych powyżej wad. Nie musi tak być - istnieją obejścia umożliwiające uzyskanie bezpiecznych połączeń obsługujących różne źródła przy użyciu Flash, Silverlight itp. - ale większość implementacji tego nie zrobi, ponieważ nie jest to łatwe.

Na przykład, jeśli polegasz na protokole WebSocket jako połączenia między źródłami, to zadziała dobrze. Ale jeśli następnie uruchomisz w starej przeglądarce lub włączysz zaporę ogniową / serwer proxy i polegasz na Flash, powiedzmy, jako rozwiązaniu awaryjnym, trudno będzie ci wykonać to samo połączenie między źródłami. Chyba że nie zależy ci na bezpieczeństwie, oczywiście.

Oznacza to, że trudno jest mieć jedną zunifikowaną architekturę, która działa dla połączeń natywnych i obcych, chyba że jesteś przygotowany na włożenie sporo pracy lub skorzystanie z frameworka, który dobrze to zrobił. W idealnej architekturze nie zauważyłbyś, czy połączenia były natywne, czy nie; Twoje ustawienia bezpieczeństwa będą działać w obu przypadkach; Twoje ustawienia klastrowania nadal będą działać; twoje planowanie zdolności nadal by się utrzymało; i tak dalej.

Jedyną zaletą WebSockets w porównaniu do przesyłania strumieniowego HTTP jest to, że nie trzeba się wysilać, aby „zrozumieć” i przeanalizować otrzymane dane.

Nie jest to tak proste, jak otwarcie strumienia HTTP i zatrzymanie się podczas przepływu danych przez minuty, godziny lub dłużej. Różni klienci zachowują się inaczej i musisz sobie z tym poradzić. Na przykład niektórzy klienci będą buforować dane i nie udostępniać ich do aplikacji, dopóki nie zostanie osiągnięty pewien próg. Co gorsza, niektórzy nie przekazują danych do aplikacji, dopóki połączenie nie zostanie zamknięte.

Więc jeśli wysyłasz wiele wiadomości do klienta, możliwe jest, że aplikacja kliencka nie otrzyma danych, dopóki na przykład nie otrzyma danych o wartości 50 wiadomości. To nie jest zbyt w czasie rzeczywistym.

Chociaż przesyłanie strumieniowe HTTP może być realną alternatywą, gdy protokół WebSocket nie jest dostępny, nie jest to panaceum. Wymaga dobrego zrozumienia, aby działać w sposób niezawodny na pustkowiach sieci w rzeczywistych warunkach.

Czy są jakieś inne istotne różnice, których mi brakuje?

Jest jeszcze jedna rzecz, o której nikt jeszcze nie wspomniał, więc poruszę to.

Protokół WebSocket został zaprojektowany jako warstwa transportowa dla protokołów wyższego poziomu. Chociaż możesz wysyłać wiadomości JSON lub inne rzeczy bezpośrednio przez połączenie WebSocket, może również przenosić standardowe lub niestandardowe protokoły.

Na przykład możesz zrobić AMQP lub XMPP przez WebSocket, tak jak ludzie już to zrobili. Tak więc klient może odbierać komunikaty od brokera AMQP, tak jakby był bezpośrednio połączony z samym brokerem (aw niektórych przypadkach tak jest).

Lub jeśli masz istniejący serwer z jakimś niestandardowym protokołem, możesz przetransportować go przez WebSocket, rozszerzając w ten sposób ten serwer zaplecza na Internet. Często istniejąca aplikacja, która została zablokowana w przedsiębiorstwie, może rozszerzyć swój zasięg za pomocą WebSocket, bez konieczności zmiany jakiejkolwiek infrastruktury zaplecza.

(Oczywiście chciałbyś móc to wszystko zrobić bezpiecznie, więc skontaktuj się z dostawcą lub dostawcą WebSocket).

Niektórzy określają WebSocket jako TCP dla sieci Web. Ponieważ tak jak TCP transportuje protokoły wyższego poziomu, tak samo jest z WebSocket, ale w sposób zgodny z infrastrukturą sieci Web.

Więc podczas gdy wysyłanie wiadomości JSON (lub cokolwiek innego) bezpośrednio przez WebSocket jest zawsze możliwe, należy również wziąć pod uwagę istniejące protokoły. Ponieważ w przypadku wielu rzeczy, które chcesz zrobić, prawdopodobnie został już wymyślony protokół, aby to zrobić.

Przepraszam, jeśli ponownie zadaję lub łączę wiele pytań już na SO w jedno pytanie, ale chcę po prostu nadać doskonały sens wszystkim informacjom, które są dostępne w SO i sieci, dotyczące tych koncepcji.

To było świetne pytanie, a wszystkie odpowiedzi były bardzo pouczające!

Robin Zimmermann
źródło
Wielkie dzięki Robin za doskonałą pomoc i informacje. Jeśli mogę zapytać o jedną dodatkową rzecz: natknąłem się gdzieś w artykule, który mówi, że strumieniowanie http może być również buforowane przez serwery proxy, podczas gdy gniazda sieciowe nie. co to znaczy?
Software Guy
Ponieważ StackOverflow ogranicza rozmiar komentarzy w odpowiedziach, poniżej podałem moją odpowiedź: stackoverflow.com/questions/12555043/…
Robin Zimmermann
@RobinZimmermann, twoja odpowiedź jest moją ulubioną. +1 za naprawdę dobrą szczegółową odpowiedź.
krzywa
10

Jeśli mogę zapytać o jedną dodatkową rzecz: natknąłem się gdzieś w artykule, który mówi, że strumieniowanie http może być również buforowane przez serwery proxy, podczas gdy gniazda sieciowe nie. co to znaczy?

(StackOverflow ogranicza rozmiar odpowiedzi na komentarze, więc musiałem odpowiedzieć tutaj, a nie w tekście).

Trafne spostrzeżenie. Aby to zrozumieć, pomyśl o tradycyjnym scenariuszu HTTP ... Wyobraź sobie, że przeglądarka otworzyła stronę internetową, więc żąda , powiedzmy, http://example.com . Serwer odpowiada za pomocą protokołu HTTP zawierającego kod HTML strony. Wtedy przeglądarka widzi, że na stronie są zasoby, więc zaczyna żądać plików CSS, plików JavaScript i oczywiście obrazów. Wszystkie są plikami statycznymi, które będą takie same dla wszystkich żądających ich klientów.

Niektóre serwery proxy będą buforować zasoby statyczne, aby kolejne żądania od innych klientów mogły pobierać te zasoby statyczne z serwera proxy, zamiast konieczności powrotu do centralnego serwera internetowego, aby je uzyskać. To jest buforowanie i jest to świetna strategia odciążania żądań i przetwarzania z usług centralnych.

Tak więc klient nr 1 żąda , powiedzmy, http://example.com/images/logo.gif . Żądanie to przechodzi przez proxy aż do centralnego serwera WWW, który wyświetla logo.gif. Gdy logo.gif przechodzi przez proxy, serwer proxy zapisze ten obraz i skojarzy go z adresem http://example.com/images/logo.gif .

Gdy pojawia się klient nr 2 i żąda również http://example.com/images/logo.gif , serwer proxy może zwrócić obraz i nie jest wymagana żadna komunikacja z powrotem do serwera WWW w centrum. Daje to szybszą reakcję użytkownikowi końcowemu, co zawsze jest świetne, ale oznacza również, że środek jest mniej obciążony. Może to przełożyć się na niższe koszty sprzętu, niższe koszty sieci itp. Więc to dobrze.

Problem pojawia się, gdy logo.gif jest aktualizowane na serwerze WWW. Serwer proxy będzie nadal obsługiwał stary obraz, nie wiedząc, że istnieje nowy obraz. Prowadzi to do całej sprawy związanej z wygaśnięciem, tak że proxy będzie buforować obraz tylko przez krótki czas, zanim "wygaśnie", a następne żądanie przechodzi przez proxy do serwera WWW, który następnie odświeża pamięć podręczną proxy. Istnieją również bardziej zaawansowane rozwiązania, w których serwer centralny może wypychać do znanych pamięci podręcznych i tak dalej, a sprawy mogą stać się dość wyrafinowane.

Jak to się ma do twojego pytania?

Zapytałeś o przesyłanie strumieniowe HTTP, gdzie serwer przesyła strumieniowo HTTP do klienta. Jednak przesyłanie strumieniowe HTTP jest takie samo jak zwykły HTTP, z wyjątkiem tego, że nie przestajesz wysyłać danych. Jeśli serwer sieciowy obsługuje obraz, wysyła HTTP do klienta, który ostatecznie się kończy: wysłałeś cały obraz. A jeśli chcesz wysłać dane, to jest dokładnie to samo, ale serwer po prostu wysyła przez naprawdę długi czas (jak na przykład gigantyczny obraz) lub nawet nigdy się nie kończy.

Z punktu widzenia proxy nie może odróżnić HTTP dla statycznego zasobu, takiego jak obraz, od danych z przesyłania strumieniowego HTTP. W obu przypadkach klient wysłał żądanie do serwera. Pełnomocnik zapamiętał to żądanie, a także odpowiedź. Następnym razem, gdy pojawi się to żądanie, serwer proxy podaje tę samą odpowiedź.

Więc jeśli twój klient zażądał, powiedzmy, ceny akcji i otrzymał odpowiedź, następny klient może wysłać to samo żądanie i uzyskać dane z pamięci podręcznej. Prawdopodobnie nie to, czego chcesz! Jeśli chcesz uzyskać ceny akcji, chcesz otrzymywać najnowsze dane, prawda?

Więc to jest problem.

To prawda, istnieją sztuczki i obejścia, które pozwalają poradzić sobie z takimi problemami. Oczywiście możesz sprawić, by przesyłanie strumieniowe HTTP działało, ponieważ jest obecnie używane. To wszystko jest przejrzyste dla użytkownika końcowego, ale ludzie, którzy opracowują i utrzymują te architektury, muszą przeskoczyć przez przeszkody i zapłacić cenę. Powoduje to nadmiernie skomplikowaną architekturę, co oznacza więcej konserwacji, więcej sprzętu, większą złożoność i większe koszty. Oznacza to również, że programiści często muszą dbać o coś, czego nie powinni, kiedy powinni po prostu skupić się na aplikacji, GUI i logice biznesowej - nie powinni martwić się o podstawową komunikację.

Robin Zimmermann
źródło
1
doskonały szczegół Robin, wielkie dzięki! doceniam twoją dokładną odpowiedź. Nauczyłem się już tak wiele od wszystkich wspaniałych ludzi! :)
Software Guy
4

HTTP ogranicza liczbę połączeń, które klient może mieć z serwerem do 2 (chociaż można to złagodzić za pomocą subdomen), a IE jest znane z tego, że chętnie wymusza to. Firefox i Chrome pozwalają na więcej (chociaż nie pamiętam z czubka głowy dokładnie, ile). To może nie wydawać się dużym problemem, ale jeśli używasz stale jednego połączenia do aktualizacji w czasie rzeczywistym, wszystkie inne żądania muszą przepływać przez drugie połączenie HTTP. Jest też kwestia większej liczby otwartych połączeń od klientów, co powoduje większe obciążenie serwera.

WebSockets są protokołami opartymi na TCP i jako takie nie cierpią z powodu tego limitu połączeń na poziomie HTTP (ale oczywiście obsługa przeglądarek nie jest jednolita).

TheJuice
źródło
dziękuję sokowi, więc poza podkreśloną przez Państwa kwestią wielu jednoczesnych połączeń, czy reszta moich przypuszczeń dotyczących gniazd sieciowych jest poprawna?
Software Guy,