Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [long polling] Krótkie pytanie
Forum PHP.pl > Forum > XML, AJAX
markonix
Powoli zaczynam zapoznawać się z tą technologią bo dużymi krokami zbliża się do mnie konieczność zbudowania komunikatora/czatu o dużej przepustowości.

Zastanawia mnie jednak jedno.
Jak już dobrze zrozumiałem to ta technologia polega na tym, że przeglądarka wysyła żądanie pod podaną stronę (php) i oczekuje na odpowiedź.
Wszystko jest tu dla mnie jasne, zamiast co 3 sekund wysyłać Request HTTP to wysyła go raz i czeka na odpowiedź.

Ale zastanawia mnie co ma się dziać w tym momencie w skrypcie PHP, który np. odpytuje o nowe wiadomości?
Czy tutaj będzie pętla, która co sekundę (sleep) odpytuje bazę o nowe wiadomości?
Jeśli tak to gdzie tu korzyść oprócz zmniejszonej liczby Requestów, które chyba nie są takim obciążaniem jak odpytywanie bazy danych co X sekund?
sowiq
Po czym wnosisz, że 3 zapytania do bazy danych są bardziej kosztowne niż request HTTP? Już pomijając, że request robiłbyś co 3 sekundy, a zapytania do bazy co sekundę, więc opóźnienia byłyby 3 razy mniejsze.

Po pierwsze, jeśli używasz serwera Apache, to na każdy request HTTP odpala on oddzielny proces - jest to dosyć kosztowna operacja. Po drugie, każdy request składa się z nagłówków zapytania i odpowiedzi - zużywasz niepotrzebnie przepustowość.

Wykonanie zapytania MySQL po kolumnach z indeksami przy raz otwartym połączeniu (zwłaszcza jeśli serwer aplikacji i bazy danych to ta sama maszyna) trwa, w zależności od ilości danych, relatywnie krótko. Poza tym zawsze możesz zapisywać wiadomości do bazy danych (jako archiwum), a bieżące wyświetlanie realizować na podstawie memcache.
markonix
Wnoszę to po tym, że po prostu baza jest zwykle wąskim gardłem i trzeba tak robić aby zapytań było jak najmniej.
Po to w końcu się cacheuje zapytania, a wcześniej je optymalizuje.

Samo zapytanie np. przy czacie faktycznie nie jest kosztowne, bardziej chodzi o ilość.

Czyli odpowiedzią na moje pytanie jest, że ta technologia nie służy zmniejszeniu liczby zapytań a jedynie REQUESTów.
Z tej technologii korzysta FB i jakoś to działa, ale nie chce mi się aż wierzyć, że co sekundę jak nie częściej podczas rozmowy serwery odpytują bazę.

Nadal jednak to nie jest prawdziwy real-time - opóźnienie opiera się na sleep chyba, że go nie użyjemy ale jeżeli zapytanie damy bez ograniczeń w pętle to nie uwierzę, że to nie zabije serwera smile.gif
Crozin
PHP jest tu po prostu złą technologią. Zdecydowanie lepiej jest mieć dostęp do całego serwera aplikacji (patrz: Java, C#), gdzie w momencie napisania wiadomości przez jednego klienta (zapytanie INSERT do bazy danych) jesteś wstanie poinformować wszystkie inne wątki (obsługujące inne żądania HTTP/WebSocket) o pojawieniu się nowej wiadomości. Wtedy też wątki te mogą pobrać z bazy danych odpowiednie dane (zapytanie SELECT), bądź w ogóle pomijając bazę danych odczytać wiadomość przekazaną wraz z komunikatem o jej pojawieniu się (w takim przypadku baza danych służy wyłącznie za archiwum konwersacji).

@sowiq: Apache przy nowym żądaniu tworzy nowy wątek do jego obsługi, nie cały proces.
redeemer
@Crozin dobrze prawi. To nie baza danych ma być "spoiwem" pomiędzy wymianą danych między klientami, ale sama aplikacja serwerowa.

Do aplikacji typu czat lepiej chyba użyć XMPP (np. ejabberd/openfire, po stronie klienta: strophejs), cometd czy nawet ape-project.

Myśląc o budowie takiej aplikacji pomyśl też nad "wielozakładkowością". Czy lepiej, żeby dla każdej instancji strony (zakładki/nowego okna) w obrębie przeglądarki było nawiązywane osobne połączenie do serwera, czy może lepiej jak będzie jedno połączenie w obrębie wszystkich instancji, a synchronizacja czatu na wszystkich instancjach (zakładkach) będzie się odbywać np. za pomocą magazynu lokalnego. W przypadku jednego połączenia w obrębie przeglądarki dochodzi jeszcze problem "przerzucania roli" gdy mamy minimum 2 instancje strony i użytkownik zamyka tą z obsługą połączenia.

Można też pójść na łatwiznę i ograniczyć działanie aplikacji tylko do jednej "zakładki", tak jak miała/ma nk smile.gif

PS. I fb i nk działał/działa na bazie protokołu XMPP (FB na zmodyfikowanym ejabberd). Jednak sprawdzane to było grubo ponad 1,5 roku temu.
markonix
Wszystkie te technologie, które wymieniłeś wymagają instalacji serwera na serwerze (oprogramowania) stąd to jest główne ograniczenie dla ich stosowania.
Tu już nie chodzi o to, że człowiekowi nie chce się włączyć puttiego ale o przenośność aplikacji. To tylko się zda gdy tworzymy coś naprawdę dużego i dedykowanego' albo dla siebie. Ale nawet jak dla siebie to gdy przenosimy hosting to musimy pamiętać o instalacji bo wszystko się sypnie smile.gif

Apre-project znam, trafiałem na tę stronę już kilka razy. Widzę jest to silnik typu "push". Ogólnie rozjaśniło mi się już rozróżnienie push/pull.
Strona projektu nie wiedzieć czemu nie działa - tzn wiem, że na startowej były takie ruszające się małpiszony i chyba czat, a teraz mam "Your APE is coming...".

Jeszcze myślę nad magazynem lokalnym. Faktycznie w tym momencie mam pełno ajaxowych zapytań w tradycyjnej formie (ani pull, ani push smile.gif ), które np. odpytują o jakąś tam wartość liczbową - gdy się zmieni jest dźwięk. Niestety nigdy nie myślałem o tym, co powinno się dziać gdy otwarte są dwie czy więcej zakładek bo teraz dźwięk pojawi się X razy z różnym opóźnieniem i zastanawiam się czy właśnie nie wykorzystać tu localStorage? Bo ten ficzer miałeś na myśli?
Crozin
@markonix: Obecnie ceny VPS-ów są na tyle niskie, że spokojnie można z nich korzystać przy średnich czy nawet małych stronach/aplikacjach.
erix
Cytat
Po pierwsze, jeśli używasz serwera Apache, to na każdy request HTTP odpala on oddzielny proces - jest to dosyć kosztowna operacja. Po drugie, każdy request składa się z nagłówków zapytania i odpowiedzi - zużywasz niepotrzebnie przepustowość.

Cytat
@sowiq: Apache przy nowym żądaniu tworzy nowy wątek do jego obsługi, nie cały proces.

Zależy, w jakim trybie jest skonfigurowany. Jest też opcja wątkowania.

Cytat
PS. I fb i nk działał/działa na bazie protokołu XMPP (FB na zmodyfikowanym ejabberd). Jednak sprawdzane to było grubo ponad 1,5 roku temu.

Na NK też jest oparte o ejabberd. Rok szukali programistów do erlanga. tongue.gif

Cytat
Niestety nigdy nie myślałem o tym, co powinno się dziać gdy otwarte są dwie czy więcej zakładek bo teraz dźwięk pojawi się X razy z różnym opóźnieniem i zastanawiam się czy właśnie nie wykorzystać tu localStorage? Bo ten ficzer miałeś na myśli?

Prędzej sessionStorage.
markonix
Cytat(Crozin @ 9.10.2012, 12:35:49 ) *
@markonix: Obecnie ceny VPS-ów są na tyle niskie, że spokojnie można z nich korzystać przy średnich czy nawet małych stronach/aplikacjach.

Odnosisz się do tej przenośności? Oj skrypt z koniecznością instalowania na serwerze oprogramowania nie sprzedałby się na Allegro. Na moje oko to 90% stron postawionych jest na hostingach (w tym darmowych) wink.gif Ale to akurat tak tylko na marginesie skomentowałem. Wiadomo, coś za COŚ.


@redeemer powiem Ci, że niezłą zagadkę zrobiłeś z tym przenoszeniem "serwera" pomiędzy zakładkami.
Jedyne co mi przychodzi na myśl to brak odpowiedzi z zakładki serwerowej przez X czasu to sygnał dla zakładki drugiej, aby ta przejęła role serwera.

sowiq
@markonix, teraz mi się przypomniała pewna przygoda firmy, w której pracowałem. Mieliśmy zrobić chata dla sporego sajtu (kilka mln odsłon dziennie). Pierwszy pomysł to jabber, ale z braku entuzjazmu stanęło na deamonie w PHP i socketach, wtedy jeszcze używanych przez komunikację JavaScript <--> Flash <--> serwer. Wszystko działało bardzo ładnie aż do czasu jak wzrósł ruch. PHP zaczął gdzieś gubić pamięć. Powstał więc drugi deamon, który nadzorował proces PHP i co jakiś czas go restartował. Więc po stronie przeglądarki musiała powstać funkcja nadzorująca połączenie, która w razie potrzeby je ponawiała. I podobnych rzeczy pojawiało się coraz więcej. A finalnie, z tego co pamiętam, i tak zakończyło się na jakimś jabberze.

Więc przemyśl dokładnie, czy chcesz sobie dodawać roboty pchając się od początku w PHP.
erix
Cytat
Oj skrypt z koniecznością instalowania na serwerze oprogramowania nie sprzedałby się na Allegro. Na moje oko to 90% stron postawionych jest na hostingach (w tym darmowych) Ale to akurat tak tylko na marginesie skomentowałem. Wiadomo, coś za COŚ.

Bo nie sprzedaje się skryptów, tylko dostęp do nich. tongue.gif Model SaaS ma się dobrze i klienci są mniej upierdliwi, bo za całą infrastrukturę programową odpowiadasz Ty. [;

Z doświadczenia - stawianie demonów w PHP jest bez sensu. Nie mam pojęcia, z jakiego powodu, po jakimś czasie albo się wysypie, albo w ogóle nie wystartuje na innej maszynie, choć konfiguracja jest bliźniacza. Python takich problemów nie ma, czego już totalnie nie rozumiem... O.o'

A ejabberd + klient Jabbera, to chyba najlepsze, co można w tej chwili zrobić nie pisząc od zera i śpiąc spokojnie, jeśli chodzi o obciążenie. Erlang, to potężny język, zwłaszcza jeśli chodzi o skalowalność. [;
redeemer
Cytat(markonix @ 9.10.2012, 13:12:51 ) *
@redeemer powiem Ci, że niezłą zagadkę zrobiłeś z tym przenoszeniem "serwera" pomiędzy zakładkami.
Jedyne co mi przychodzi na myśl to brak odpowiedzi z zakładki serwerowej przez X czasu to sygnał dla zakładki drugiej, aby ta przejęła role serwera.

Long polling ma to do siebie, że połączenie może wisieć nawet przez 30 sekund. Lepszym rozwiązaniem będzie dodatkowa funkcja wywoływana z pewnym interwałem czasowym, która co parę sekund będzie odświeżała jakąś zmienną typu timestamp w magazynie lokalnym w "głównej" instancji. Inne instancje będą monitorować wartość tej zmiennej i jeżeli jakiś warunek nie będzie spełniony przejmą jego rolę. Tu z kolei pojawia się problem konkurencyjności, bo js nie jest językiem wielowątkowym i nie możemy określić sekcji krytycznej (brak mutexów), w związku z czym teoretycznie podczas zamknięcia głównej instancji jej role może przejąć w tym czasie wiele innych zakładek, które działały wcześniej w tzw. trybie mirror.

Zwykle w serwerach XMPP można włączyć opcję (lub ją sobie dopisać), aby "multisesje" nie były aktywne, w tym wypadku jeżeli wiele instancji tego samego klienta będzie podłączonych do serwera, wszystkie poza jedną dostaną od serwera stosowną wiadomość disconnect, która po obsłużeniu po stronie klienta spowoduje, aby instancja przeszła w tryb "mirror", czyli bez połączenia do serwera.

Nam jakiś czas temu udało się zbudować taką aplikację zintegrowaną z serwisem społecznościowym, gdzie dodatkowo są też reguły, dotyczące komu kto może wysyłać wiadomości. Użyliśmy ejabberd (na początku był to openfire), strophejs (z modyfikacjami), oraz http://www.jstorage.info/. Niestety branch nigdy nie został włączony do gałęzi production, a szkoda.

Jako lekturę mogę polecić, co prawda już nie pierwszej świeżości (2010 rok), ksiażkę autora biblioteki strophejs Professional XMPP Programming with JavaScript and jQuery
markonix
Jeszcze wracając do "prostego" polling.
Jaki czas powinno mieć oczekiwanie na odpowiedź?
Początkowo wydawało mi się czym dłużej tym lepiej bo w końcu chodzi o zmniejszenie liczby requestów.
No ale gdy stworzyłem testowy skrypt to po 45 sekundach otrzymałem error 500.

No i teraz pytanie co z tym zrobić?
- Przechwycić błąd
[JAVASCRIPT] pobierz, plaintext
  1. error : function(XMLHttpRequest, textstatus, error) {
  2. comet();
  3. }
[JAVASCRIPT] pobierz, plaintext

i od nowa oczekiwanie?
- Starać się jak najbardziej zwiększyć czas wykonywania skryptu (albo najlepiej no-limit)?

Te pierwsze wydaje mi się bardziej bezpiecznie ale przykładowo przymierzam się do poprawek w obecnych skryptach gdzie np. teraz wartości odświeżane są co 15 sekund. Wprowadzając omawianą technikę to będzie oszczędność dość mizerna (1 zamiast 3), a gdyby execute_time wynosił np. 10 minut to już gdzieś oszczędność na poziomie 40 requestów i jakoś bardziej działa to na wyobraźnie i motywuje do przeróbek w obecnych skryptach.
redeemer
http://tools.ietf.org/html/rfc6202#page-15 5.5 Timeouts (ale cały dokument jest warty uwagi)


Co ciekawe w drafcie http://tools.ietf.org/html/draft-loreto-ht...onal-07#page-15 jest to bardziej rozwinięte i możemy tam przeczytać dodatkowo:
Cytat
Several experiments have shown success with timeouts as high as 120
seconds, but generally 30 seconds is a safer value. Therefore
vendors of network equipment wishing to be compatible with the HTTP
long polling mechanism are advised to implement a timeout

markonix
Znowu wracam do problemu z long polling.

  1. while ($current == $last_id) {
  2. usleep(6000000);
  3. $current = shout_pro_lastId();
  4. }


Oki, mniej requestów, zapytania są optymalne, ale teraz naszła mnie kolejna myśl co do wydajności takiego rozwiązania, a mianowicie liczba połączeń z bazą.
Przy pracy nad czatem zawiesiłem parę razy serwer - "too many connections". Oczywiście był to wynik błędnych pętli ale ten błąd kieruje uwagę na powyższy problem.
Funkcje z rodziny sleep nie kończą w żaden sposób skryptu, tak więc przyjmując te 30 sekund jeden użytkownik przez 30 sekund zajmuje bazę, albo przynajmniej utrzymuje z nią połączenie. Czy dobrze myślę? Czy utrzymanie połączenia może spowodować jakieś problemy? Czy może przy każdym obrocie pętli zamykać połączenie i otwierać na nowo?
rzymek01
Ciekawym rozwiązaniem jest Tornado. Jest to asynchroniczny framework napisany w Pythonie wprost stworzony do long polling.

W niedawno stworzonej aplikacji typu real-time nie korzystałem z żadnych sleepów... W skrócie był wątek producenta (lub wątki, bez znaczenia), który dodawał do kolejek nowe zdarzenia. W tym samym czasie żądania long-polling czekały na kolejce. Kiedy tylko coś pojawiło się w kolejce, to żądanie było wznawiane i odpowiedź szła do użytkownika.

Może pomyśl w tym kierunku.

Odnośnie pytania, to zastosuj pulę połączeń (patrz np. ADO.NET).

PS. Także nie polecam PHP do tego typu aplikacji. Osobiście stawiam na Pythona, od biedy Javę smile.gif
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.