Tuesday, November 15, 2005

Sposób na automatyczne aktualizacje w Rich Internet Applications

Ostatnimi czasy bardzo intensywnie zajmuję się tworzeniem Rich Internet Applications. Większość tych programów pisałem w ActionScript 2.0. Od tygodnia jednak zajmuję się pisaniem małych aplikacji w RubyOnRails z wykorzystaniem bibliotek javascriptowych do asynchronicznych wywołań (czyli do AJAXa).

Podstawowym problemem każdego programisty aplikacji WWW jest napisanie czegoś co nie będzie generować dużego ruchu w sieci. Pisząc RIA nie można się przed tym uchronić. Niestety model HTTP nie jest zbyt odpowiedni do tego typu aplikacji - o wszelkich zmianach w bazie danych klient dowiaduje się dopiero po wysłaniu żądania.

Przykładowo mamy prostą grę www, w której ruchy jednego gracza są obserwowane przez drugiego. Załóżmy, że gracz 1 co kilkanaście sekund dokonuje ruchu. Natomiast gracz 2 chciałby od razu widzieć co się wydarzyło. Teraz pojawia się problem - aby coś takiego uzyskać trzeba na przykład w odstępie 2 sekund wysyłać zapytania typu GET do serwera, aby sprawdzić czy ruch w ogóle nastąpił. Zakładając, że prawie puste zapytanie typu GET + odpowiedź serwera pochlania około 4kB (razem w obie strony) mamy więc 2kB/s dla jednego gracza. Jeśli dysponujemy łączem powiedzmy 1Mbit(~128kB), to jesteśmy w stanie obsłużyć naraz zaledwie 64 użytkowników (!). Trzeba jednak pamiętać, że możemy mieć nawet 2 sekundy poślizgu z aktualnością danych.

Bardzo dużo nad tym problemem myślałem i przychodziły mi do głowy jedynie rozwiązania polegające na tworzeniu własnych trwałych połączeń w obie strony. Jednakże dzisiejsze firewalle czy serwery proxy na to nie pozwolą... Trzeba więc trzymać się protokołu HTTP...

Wpadłem jednak na rozwiązanie problemu :D Nie wiem czy jest odpowiednie i czy na pewno będzie działać. Wiem jednak, że jest najlepsze z moich dotychczasowych rozwiązań... :D

Trik polega na tworzeniu nasłuchiwaczy. Nasłuchiwaczem jest po prostu każdy klient, który chce dowiedzieć się o zmianach wybranej częsci bazy danych. Klient łączy się z serwerem, podczas gdy serwer nie odsyła mu od razu odpowiedzi.... Połączenie więc "wisi" do momentu gdy któryś z graczy zmieni jakieś dane w bazie. Gdy wiszący wątek otrzyma taką informację - generuje odpowiedź serwera, po czym kończy wykonywanie żądania. Nasłuchiwacz dostaje więc info, od razu gdy dane zostały zmienione. Po czymś takim nasłuchiwacz ponownie łączy się z bazą danych, gdyż chce znów nasłuchiwać zmian.

Rozwiązanie jest przede wszystkim idealne, z uwagi na to że działa przez HTTP. Jedynym problemem są timeouty. Na przykład serwery proxy mogą czekać określoną ilość sekund na odpowiedź, po czym się rozłączają. Wtedy klient musi coś takiego przechwycić i połączyć się ponownie (oczywiscie po stronie serwera wiszący wątek musi takze zostać usunięty).

Co myślicie o tym rowiązaniu? Czy nie ma żadnych innych przeciwskazań aby użyć takiego techniki?

6 comments:

Anonymous said...

Rozwiązanie nie jest nowe. Niektóre projekty już z niego od dawna korzystają (np. http://www.millstone.org/ - akurat w chwili pisania tego komentarza nie działa ich strona z przykładami, ale jak zacznie działać to looknij) .

--
pozdrawiam
Piotr Maj

Anonymous said...

Tak, a mozna sie wogole nie rozlaczac, bo przeciez czesciej to serwer wie, ze trzeba poinformowac klienty, a nie inmy klient. Rozwiazanie rzeczywiscie nie jest nowe i nazywa sie html streaming i bylo od zawsze stosowane np. w chat'ach.

Unknown said...

Hmmm... oczywscie, że lepiej by bylo gdyby połączenie nie było w ogole rozłączane. Jednak przeszkodą są np. serwery proxy, które mają określony timeout.

Anonymous said...

Wydaje mi sie, ze takie rozwiazanie jest dobre w szachach ale nie w jakiejs dynamicznej gierce poniewaz w przypadku gdy wielu graczy sie porusza masz ten sam problem : listener wysyla mase danych do wielu klientow.

pozdrawiam
Albert

Unknown said...

Oczywiście... jednak nie znam lepszego sposobu aby "przedrzeć" się przez firewalle :D

Anonymous said...

sprawdziłem i działa. Napisałem jakieś 6 miesięcy temu aplikcję do prowadzenia rozmowy (chat) na WWW. Aby rozwiązanie było wydajne i wygodne w użyciu należało go oprzeć właśnie o mechaizm push. Była to niewielka część więkaszego projektu (Call Center). System działa produkcyjnie (Serwer w Anglii, klienci w Polsce) i nie ma do tej pory zastrzeżeń :).

Bardzo ciekawe rozwiązanie w tym zakresie oferuje www.lightstreamer.com

--
Daniel