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

Comments

  1. Avatar lopex powiedział about 11 hours later:

    W Ruby 2.0 prawie na pewno nie będzie kontynuacji, a w 1.x są one zaimplementowane w bardzo niewydajny sposób – jakiekolwiek zastosowanie oprócz takich przykładów raczej nie wchodzi w grę. Parrot jest w pełni oparty na kontynuacjach.

  2. Avatar Jarosław Zabiełło powiedział about 12 hours later:

    To pewne informacje czy tylko plotki? Matz to potwierdził? Dlaczego chcą się tego pozbyć? W wypadku Rubiego, Parrot wygląda na pewną konkurencję dla YARP’a...

    Czy to, że Parrot oparty jest na kontynuacjach coś wnosi do języków które ma obsługiwać, czy to tylko wewnętrzna sprawa maszyny wirtualnej Parrota? Czy to coś pomoże w tworzeniu serwerów kontynuacyjnych?

  3. Avatar rsz powiedział about 13 hours later:

    Parrot oparty jest (podobnie jak wiele kompilatorów języków funkcyjnych) na CPS (http://en.wikipedia.org/wiki/Continuation_passing_style) i translacji (transformacji) CPS jako wewnętrznym etapie kompilacji programu, co nie musi oznaczać udostępnienia użytkownikom (aczkolwiek prawie na pewno będzie oznaczać) funkcjonalności kontynuacji. Nota bene, autorzy Parrota zdecydowali się na użycie CPS po wniknięciu w teorię kompilacji języków funkcyjnych – co wskazuje na kierunek, w jakim zmierza świat :)

    Na temat użycia kontynuacji i CPS w implementacji języków programowania zobacz np.

    http://citeseer.ist.psu.edu/flanagan93essence.html

    Poza tym ostatnimi czasy ludzie dochodzą raczej do konsensusu, że nieograniczone kontynuacje nie są właściwym rozwiązaniem ze względu na nieuniknione narzuty wydajnościowe i problemy semantyczne – a to dlatego, że kontynuacje, o ile nie są używane zgodnie ze ściśle ustalonym, raczej sztywnym stylem, są po prostu równoważne instrukcji GOTO, która, jak wiadomo, została dawno temu odrzucona jako zbyt łatwo prowadząca do nieczytelnego, zagmatwanego i trudnego w zrozumieniu/weryfikacji kodu. Są prowadzone aktualnie aktywne prace nad kontynuacjami “ograniczonymi” semantycznie (częściowymi, składalnymi etc), które mają te problemy rozwiązać, ale na razie są w fazie raczej wstępnej i nie wiadomo, czy cokolwiek kiedykolwiek z tego wyjdzie (jak na razie za dużo nierozwiązanych problemów teoretycznych). Bardzo zgrubne wprowadzenie do tematu można znaleźć np. tu:

    http://www.diku.dk/NWPT05/Slides/nwpt05-biernacki.pdf

  4. Avatar rsz powiedział about 13 hours later:

    Poza tym stwierdzenie

    “Serwer przywróci cały wcześniejszy stan aplikacji bez żadnego problemu”

    nie jest do końca prawdziwe, jeśli mówimy o aplikacjach mających stan zewnętrzny – np. pliki, baza danych. To nie jest taka magiczna różdżka, która zwalnia programistę z myślenia o tym.

    No i ciekawi mnie jeszcze, skąd wziąłeś to stwierdzenie:

    “Wg różnych prognoz, tak będziemy programować serwisy internetowe za kilka lat!”

    Jeszcze jedno: “Sama idea nie jest najwyraźniej jeszcze powszechnie znana”; dokładniej byłoby powiedzieć – była powszechnie znana, ale została zapomniana. Np. w lispach/schemach techniki kontynuacyjne mają swoją historię dłuższą, niż pewnie sam Smalltalk.

    Poza tym to nie twórcy smalltalka wymyślili ideę maszyny wirtualnej, zob.

    http://cs.gmu.edu/cne/itcore/virtualmachine/history.htm

    Dalej czytamy: “nie ma tam dostępu do plików z zewnątrz” – to jakiś żart, prawda? Dla VisualWorks masz tu:

    http://www.cincomsmalltalk.com/tutorials/version7/tutorial1/weblogstats3.htm

    dla GNU tu:

    http://www.gnu.org/software/smalltalk/gst-manual/gst_108.html

    a dla Squeak’a tu:

    http://minnow.cc.gatech.edu/squeak/uploads/SqueakClassesRef.html#StreamClasses

    Poza tym, jak sobie wyobrażasz działający, napisany w Smalltalku webserver bez dostępu do warstwy systemu plików???

    Nie zaszkodzi trochę doczytać przed wyrażaniem takich skrajnych opinii…

  5. Avatar Jarosław Zabiełło powiedział about 13 hours later:

    Co do tych prognoz, to tak różnie mówią w sieci i niektórych książkach. Bruce Tate zdaje się o tym coś pisał. Myślisz, że Seaside to ślepa uliczka? To prawda, że taki styl pracy jest zasobożerny, ale znacznie upraszcza pracę dla programisty aplikacji webowej.

    Co do owych nieszczęsnych plików Smalltalku, to nie zrozumiałeś. Chodziło mi o dostęp do środowiska Smalltalku przez zewnętrzne aplikacje a nie odwrotnie. Smalltalk jest całym środowiskiem a nie tylko jedną z aplikacji uruchomioną w systemie operacyjnym.

    Czy sobie wyobrażam Smalltalka bez dostępu do zewn. systemu plików? A co w tym trudnego do wyobrażenia? Nigdy nie widziałeś Zope? Wszystkie jego wew. elementy widziane z klienta jako foldery, obrazki czy pliki tekstowe są obiektami siedzącymi w obiektowej bazie danych.

  6. Avatar rsz powiedział about 13 hours later:

    Tak, myślę, że aplikacje na większą skalę oparte o czyste kontynuacje to ślepa uliczka. A szczególnie dla aplikacji serwerowych, gdzie masz warstwę kodu na warstwie, duże narzuty pamięciowe etc. A odkładanie kontynuacji na później przy dużym obciążeniu serwera może szybko się wymknąć spod kontroli.

    “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 brzmiało tak, jakbyś ze środowiska Smalltalka nie miał dostępu do plików na zewnątrz. Ale z tego, co piszesz, miałeś coś innego na myśli. Ale ja teraz to już nie mam pojęcia, o co Ci chodzi.

    A Zope ma przecież dostęp do plików – ZODB jest w końcu oparta na plikach, więc musi on je czytać, zapisywać… Chyba znowu czegoś nie rozumiem.

  7. Avatar Jarosław Zabiełło powiedział about 13 hours later:

    Jakieś plotki rozsiewasz. Wg Chada Fowlera (tego od książki Rails Recipes) kontynuacje mają być zaimplementowane w Ruby 2: “Matz and Koichi are still planning to implement continuations for Ruby 2.0.”

    Mają być też zaimplementowane w JRuby. :)

  8. Avatar Jarosław Zabiełło powiedział about 14 hours later:

    Wenętrznie to Zope korzysta z plików, ale mi chodzi o co innego. Tworząc aplikację w Zope pracujesz na obiektach, które nie są dostępne z zewnątrz. Sprawiają one wrażenie folderów, plików, ale to wszystko są obiekty. Oczywiście, można zmusić Zope aby dodany do aplikacji obrazek leżał sobie gdzieś w filesystemie, ale to jest tylko dodatkowa opcja. Normalnie Zope trzyma to wewnetrznie i za cholerę się do tego nie dostaniesz z poziomu shella :) Musisz to zrobić poprzez Zope i to, co on raczy udostępnić.

    W pewnym sensie Zope jest tu monolityczny podobnie jak Smalltalk.

  9. Avatar rsz powiedział about 14 hours later:

    Odnośnie plików: to jest, jak rozumiem, przytyk odnośnie Seaside’a, a nie Smalltalka, tak samo jak to, że Zope jest “podobnie monolityczny” nie jest przytykiem do Pythona.

    “tylko Ruby posiada ten mechanizm jako coś naturalnego i nie trzeba stosować żadnych specjalnych sztuczek aby go emulować” – wiesz, że to nieprawda, zresztą zdanie wcześniej piszesz coś z tym sprzecznego.

    BTW, przeczytaj to: http://smallthought.com/avi/?p=4

    “Bruce states in both the article and the book that I had written a continuations-based web framework in Ruby before moving my development to Squeak when Ruby’s continuations proved unstable. That’s not actually correct; the framework that I wrote in Ruby … didn’t make use of continuations”. Znowu wychodzi Twoja wiara w Bruce’a-lamera ;)

    Do tego jeszcze jedna rzecz: Seaside na 99% nie był pierwszym webserwerem kontynuacyjnym; prawdopodobnie pierwszy był soft Grahama (Viaweb, potem Yahoo) napisany, a jakże, w lispie.

  10. Avatar rsz powiedział about 14 hours later:

    BTW Bryant tutaj wyraźnie pisze, że Seaside jest napisany na podstawie wcześniejszych prac:

    ”...on top of the basic continuation style describe by Quiennec and later papers”

  11. Avatar Jarosław Zabiełło powiedział about 15 hours later:

    Trochę piszesz nie na temat (polemizujesz ze swoimi wyobrażeniami a nie z treścią artykułu). Gdzie ja napisałem, że Seaside był pierwszym serwerem kontynuacyjnym???

    Co do owej nieszczęsnej monolityczności, to chodziło mi o smalltalkowy image (który zresztą trochę przypomina mi “image” Zope’a) Zdaje się, że Smalltalk zawsze pracuje w ten sposób, ma swój image który tworzy cały jego świat.

  12. Avatar rsz powiedział about 15 hours later:

    A ja nie wiem, coś mi się przewidziało chyba z tym byciem pierwszym; no, jak by nie było, to warto wiedzieć, że nie był :)

    Dalej nie kumam, o co Ci chodzi z monolitycznością – co to jest “cały jego świat”? Skoro ma dostęp do plików z FSa i sieci, to chyba nie jest jednak cały świat.

  13. Avatar lopex powiedział about 17 hours later:

    “And then Matz and Koichi dropped the bomb: Ruby 2.0 would support neither continuations nor green threads.”

    to było na konferencji KaiGi na poczatku października i wywołało niemałą burzę. Potem Headius postanowił na dobre zrezygnować z kontytuacji w JRubym: http://headius.blogspot.com/2006/10/another-year-another-interpreter.html Ostatnio (2 tyg temu?) Matz powiedział że jeśli czas pozwoli to możliwe że będą kontynuacje (a biorąc pod uwagę tempo prac raczej w to wątpię)

    rsz: CPS to żadna magia – to tylko przekazywanie ekstra funkcji – a że można się łatwo pogubić to fakt – wystarczy napisać foldr w haskellu na kontynuacjach

  14. Avatar rsz powiedział 1 day later:

    lopex: no wiesz, kwestia gustu, pisanie z dużą ilośćią goto to też niby nie magia, ale…

  15. Avatar sprae powiedział 2 days later:

    Znowu smierdzi to jakims hype. Duzo latwiejsze w realizacji byloby serializowanie obiektow sesji uzytkownika (na czas nieokreslony) np. do bazy, albo skorzystanie z taskletow (na krotkie okresy przechowywania sesji). Rozwiazania takie pozwalaja na dynamiczne rozsiewanie sesji na grupie serwerow.

  16. Avatar rsz powiedział 2 days later:

    sprae: O – to prawda. Migracja kontynuacji między serwerami na klasterze nie jest zasadniczo możliwa. Gdyby jeszcze taki Ruby miał dobrze zaimplementowane wątki, to by się dało przerzucać nimi między wątkami w celu rozkładania obciążenia na prockach wielordzeniowych.

    BTW, da się w Ruby’m migrować kontynuacje między wątkami?

  17. Avatar lopex powiedział 2 days later:

    niestety:

    `call’: continuation called across threads (RuntimeError)

    i niestety:

    Marshal.dump(callcc{|c|c})

    `dump’: no marshal_dump is defined for class Continuation (TypeError)

    Ale obie te rzeczy nie są niemożliwe do wykonania…

  18. Avatar lopex powiedział 2 days later:
    w pierwszym miało być: [Thread.new{callcc{|$c|}},Thread.new{$c.call}].each{|t|t.join}
  19. Avatar Adamh powiedział 5 days later:

    sprae – zgadzam sie z tym, ze kwestia kontynuacji jest ostatnimi czasy podnoszona zbyt czesto jako “ogromny plus”.
    Widze zalety tego podejscia ale zbyt czesto chyba pomija sie wady. Mysle, ze zrzucanie odpowiednich danych do sesji po czym ich przywracanie praktycznie rozwiazuje problem. Plusem takiego rozwiazania (przy rozsadnym podejsciu) jest abstrakcja od problemow z bazami i plikami wspomniana przez rsz (zrzucanie tylko identyfikatorow).
    Oczywiscie cos za cos… czas procesora i obciazenie bazy za pamiec i zlozonosc kodu (w zalozonych warunkach).

  20. Avatar jps.kni.pk.edu.pl powiedział 6 days later:

    Hej,

    Kontynuacje są fajne, aplikacje napisane przy pomocy Seaside są mega i robią niesamowite wrażenie (dabbledb.com), ale jestem przekonany że w znacznej większości aplikacji webowych w zupełności można poradzić sobie bez tych bajerów, które są dostępne przy pomocy kontynuacji. Blogi, przeszukiwarki, kalendarze, sklepy internetowe – to wszystko da się zrobić całkiem elegancko bez Seaside i działa znakomicie.

    Co do renesansu na Smalltalka – wiodące komercyjne środowisko (VisualWorks) jest cholernie drogie (procent od zysku uzyskany przy pomocy produktu napisanego w VW) i wydaje mi się, że trzeba będzie poczekać aż firma, która je dostarcza zmieni trochę swój model biznesowy.

  21. Avatar jps powiedział 6 days later:

    Zapomniałeś napisać o jednej, świetnej rzeczy, która jest w Seaside, a nie ma jej chyba w żadnym innym frameworku—tworzenie aplikacji odbywa się przez przeglądarkę.

  22. Avatar Jarosław Zabiełło powiedział 6 days later:

    Pythonowy Zope też to potrafi.

  23. Avatar Artur powiedział about 1 month later:

    Czy taki stan aplikacji nie jest robiony np: w Prado? http://www.pradosoft.com/docs/manual/System.Web.UI/IPostBackEventHandler.html

(leave url/email »)

   Pomoc języka formatowania Obejrzyj komentarz