Serwery kontynuacyjne - przyszłość webu

Opublikowane przez Jarosław Zabiełło Wed, 22 Nov 2006 01:26:00 GMT

Każdy, kto zajmował się kiedykolwiek programowaniem stron internetowych wie, że protokół HTTP jest bezstanowy. Innymi słowy, każde przeładowanie strony internetowej generuje kompletnie niezależne wywołanie serwera i nie ma on możliwości aby powiązać wywołanie z konkretnym klientem. Aby temu zaradzić, wprowadzono prostą sztuczkę. Wprowadzono tzw. mechanizm cookies (dosł. ciasteczek), malutkich plików które serwer może wysyłać do klienta (tam i z powrotem). Ten unikalny identyfikator (sesji) można też trzymać w adresie URL, ale ta metoda jest zdecydowanie odradzana z powodu łatwości nadużyć (łatwo wykraść taki numer i podszyć się pod autora) Od strony klienta jedynym wymaganiem jest aby nie blokował sobie w przeglądarce mechanizmu cookies.

Serwer znając identyfikator sesji, może związać z nim szereg danych, np. aktualną listę zamawianych produktów włożonych do koszyka w sklepie internetowym. Dane te zwykle trzyma się w bazie lub w pamięci operacyjnej. Oczywiście czas życia danych jest ustalany przez serwet i w normalnym wypadku są one cyklicznie kasowane. (Z tym “normalnym” wypadkiem to różnie bywa, bo wiele frameworków tego nie zapewnia i trzeba samemu o to zadbać)

Mechanizm sesji jest dosyć wydajny, bo zapytania wysyłane do serwera mogą być obsługiwane asynchronicznie, czyli bez żadnych blokad w oczekiwaniu na ukończenie obsługi zapytania. Przez lata “stanowość” protokołu HTTP zapewniało się właśnie za pomocą sesji.

Ten mechanizm ma jednak swoje wady. Największą jest złożoność jaką wprowadza po stronie skryptów na serwerze. (I to nie jest wcale taka trywialna sprawa jak to można było zaobserwować u developerów frameworka CherryPy którzy miesiącami nie potrafili napisać stabilnie działającego mechanizmu obsługi sesji.)

Kontynuacje

Kompletnie innym podejściem jest skorzystanie z tzw. mechanizmu kontynuacji. Mechanizm ten podobny jest do gracza, który w dowolnym momencie może zapisać i wczytać stan gry. Kontynuacje zapewniają taki mechanizm zapisu stanu programu aby w dowolnym momencie później go przywrócić. Niektórzy porównują to do maszyny czasu, bo można w dowolnym momencie przywrócić wcześniejszy stan aplikacji.

Zalet z takiego podejścia jest wiele. Weźmy np. sprawę obsługi “nieśmiertelnego” przycisku Back w przeglądarce. Obsługa tego przycisku sprawia spore problemy. Programiści najchętniej w ogóle by go zablokowali. W wypadku kontynuacji ten problem w ogóle nie istnieje. Kliknął ktoś Back aby cofnąć się do poprzedniej strony? Żaden problem. Serwer przywróci cały wcześniejszy stan aplikacji bez żadnego problemu. I to w sposób przezroczysty dla programisty! Programowanie stron webowych staje się znacznie prostsze, niczym tworzenie aplikacji desktopowej włącznie z debugowaniem krok po kroku. Wg różnych prognoz, tak będziemy programować serwisy internetowe za kilka lat!

Sama idea nie jest najwyraźniej jeszcze powszechnie znana, skoro w rozmowie z developerami irlandzkiego Google, zaskoczyłem ich informacją na ten temat. Kto wie, czy Google mocniej nie zainwestuje w Rubiego (aktualnie mocno korzysta z Pythona, który jest podstawą większości ich skryptów).

Smalltalk i Seaside

Smalltalk jest bardzo starym językiem bo jego początki sięgają lat 70-tych. Od zawsze był językiem w pełni obiektowym i dynamicznym. To m.in. Smalltalk pierwszy wymyślił wirtualną maszynę której to ideę później skopiowali twórcy Javy. W Smalltalku napisano najlepszy (w chwili obecnej) na świecie serwer kontynuacyjny – Seaside.

Czy to spowoduje renesans na Smalltalka? Osobiście w to wątpię. Główną wadą Smalltalka jest jego monolityczność i hermentyczność. Uruchamiając środowisko Smalltalak uruchamia się cały, zamknięty świat Smalltalka. Np. nie ma tam dostępu do plików z zewnątrz tak, jak w innych językach. To spowodowało, że język ten, mimo pewnych sukcesów, nigdy nie zdobył sobie powszechnego uznania. I moim zdanie, nigdy już nie zdobędzie, bo w międzyczasie wyrosła mu młoda, obiecująca konkurencja.

Ruby

Ruby jest językiem relatywnie młodym. Tzn. został po raz pierwszy udostępniony publicznie w tym samym roku co Java – 1995. Ale przez większość lat był mało znany poza Japonią (skąd pochodzi jego twórca). Ruby jest także jednym z tych nielicznych języków, które (podobnie jak Smalltalk) posiadają wbudowaną obsługę kontynuacji. Istnieją co prawda różne próby implementacji tego mechanizmu w Javie1, ale tylko Ruby posiada ten mechanizm jako coś naturalnego i nie trzeba stosować żadnych specjalnych sztuczek aby go emulować. Z tego co pamiętam, Seaside pierwotnie był tworzony w Ruby, ale w tamtym okresie, kontynuacje w Ruby były jeszcze niedojrzałe, więc twórcy przerzucili się na Smalltalka. Ruby jednak szybko się rozwija, nabiera dojrzałości i moim zdaniem, ma bardzo duże szanse, aby wyprzedzić pozostałe języki przy tworzeniu serwisów internetowych nowej generacji, serwisów opartych na kontynuacjach.

Przykład kontynuacji.

Poniższy przykład2 pokazuje implementację generatora za pomocą kontynuacji.

class Generator

  def initialize
    do_generation
  end

  def next
    callcc do |here|
      @main_context = here;
       @generator_context.call
    end
  end

   private

   def do_generation
     callcc do |context|
       @generator_context = context;
       return
     end
     generating_loop
   end

   def generate(value)
     callcc do |context|
       @generator_context = context;
       @main_context.call(value)
     end
   end
end

A oto oparty na nim generator ciągu liczb Fibbonacciego:

class FibGenerator < Generator
  def generating_loop
    generate(1)
    a, b = 1, 1
    loop do
      generate(b)
      a, b = b, a+b
    end
  end
end

fib = FibGenerator.new
15.times { print "#{fib.next} " }
#wynik: 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 

1 Np. Riff lub Jetty 6.

2 Przykład z książki “The Ruby Way”, 1ed.

Posted in , ,  | Tagi , , ,  | 23 comments