jAbLoK

blog už dávno nejen o javě

Jak se zbavit HTTP sessions

8 komentářů

V příspěvcích o eBay a AppEngine jsem zmiňoval, že používání HTTP sessions nejde úplně dobře dohromady s požadavky na horizontální škálovatelnost.

Používat sessions je lákavé, umožňují programátora odstínit od bezstavovosti HTTP protokolu. Na druhou stranu, jakmile aplikace přeroste možnosti jednoho stroje, tak začnou komplikovat život, když chcete provozovat load balancing přes cluster aplikačních serverů: duplikovat je napříč servery je patrný overhead, sticky sessions neméně zjevně snižují efektivitu load balanceru.

Jinými slovy: odstiňovat programátory od bezstavovosti HTTP vlastně nemusí být až tak dobrý nápad.

Nejmenší zlo je nakonec sessions ukládat do nějakého relativně persistentního úložiště vně aplikačního serveru – zpoždění sítě a potřebné serializace a deserializace sice mírně brzdí, ale aspoň neovlivňují zbytek clusteru.

Tedy, nejmenší zlo za předpokladu, že sessions používáme.

K čemu vůbec sessions?

K čemu se vlastně HTTP sessions používají? Napadá mě:

  • udržování identity uživatele + kešování osobních dat
  • udržování stavu uživatelského rozhraní (JSF, dívám se vaším směrem…)
  • nákupní košík
  • kešování informací potřebných pro stránkování dat (opravdu to někdo radí)
  • a další – příklady uvítám v komentářích

Pokud mne laskaví čtenáři v komentářích nedoplní něčím nečekaným, dalo by se používání sessions rozdělit do následujících částečně se překrývajících kategorií:

  • autentifikace
  • kešování
  • antipatterny

Antipatterny

Nevýhody používání sessions pro ukládání aktuální pozice při stránkování dat pitvali už před necelými deseti lety členové Usenetové skupiny cz.net.internet (a po nich i před nimi jistě spousta dalších).

Z nějakých záhadných důvodů se jako typický důvod pro sessions uvádí nákupní košík. K tomu mě nenapadá jiný důvod než že jej kdysi kdosi použil v nějakém tutorialu na sessions a od té doby to každý papouškuje: košík by měl být odolný proti výpadku aplikačního serveru, navíc se neaktualizuje ani nezobrazuje tak často, aby musel být nutně kešován – zkrátka i když jeho trvání obvykle nebývá dlouhé, je velmi záhodne jej ukládat do databáze.

Jako antipattern mi osobně přijde i přístup JSF – a to ať už se stav stromu komponent ukládá do session nebo na klientovi. Ale vzhledem k popularitě tohoto frameworku mi asi něco uniká. Doufám.

Kešování

Session může působit dojmem jako bezva struktura pro kešování, aspoň dokud si člověk neuvědomí nevýhody popsané více. A dokud nezačne kešovat data, která mohou být modifikovány v rámci jiných sessions. A když si nevýhody uvědomí, tak nejspíš sáhne po něčem, co bylo pro kešování navrženo a uvedenými nedostatky ve škálovatelnosti netrpí. Třeba memcached. A těch pár zlomků sekundy na zpoždění sítě a (de)serializaci holt obětuje.

Autentifikace

Session se asi nejčastěji používá pro udržování informací o přihlášeném uživateli. Fakticky se ale jedná o speciální případ kešování popsaného níže – pokud víme, že o uživateli potřebujeme znát skutečné jméno, adresu, a základní preference, prostě si je můžeme nasypat do memcached pod těžkouhodnutelným klíčem generovaným podobným mechanismem jako session.

A pokud od autentifikace očekáváme jen ověření identity uživatele, můžeme prostě do cookie nastavit přímo identifikátor uživatele, jen digitálně podepsaný nebo ještě lépe zašifrovaný. Pokud autentifikační služba není izolována na vlastním clusteru, symetrické šifrování by mělo bohatě postačí. Na druhou stranu se v tomto případě se musíme postarat o pár praktických záležitostí okolo správy klíčů a deploymentu.

Obrázek: Možnosti ověření a interpretace authentication tokenu – kešování a kryptografie

Kryptohrátky jsou zbytečným overheadem v tradični aplikaci, kdy většina požadavků je zasílána za účelem vykreslení celé stránky – typicky vždy budete muset znovu zobrazit jméno uživatele a podobně, tudíž si hrábnutí do cache neušetříte.

Naopak pokud si mantru „udržovat stavu na klientovi“ vykládáte po vzoru GMailu tak, že webová aplikace se sestává z pár HTML stránek, kterou uživatel porůznu aktualizuje AJAXem, pak samozřejmě může kryptografické ověřování a interpretace session tokenu přispět ještě o trošku k lepší odezvě a škálovatelnosti.

Pokud někomu ze čtenářů zbudou síly něco napsat, zajímalo by mě:

  • k čemu výše neuvedenému používáte sessions?
  • zkoušeli jste v praxi vytvořit bez použití sessions netriviální víceuživatelskou webovou aplikaci?
  • a pro znalce a fanoušky Java Server Faces – máte po přečtení výše uvedeného dojem, že mi ohledně této technologie něco zásadního uniká? 🙂

Odkazy

Written by Pavel Kolesnikov

26 května, 2008 na 4:18 pm

Zasláno do Scalability

Tagged with , , , ,

8 komentářů

Subscribe to comments with RSS.

  1. Jasne JSF maji vetsi naroky, proto bych pri programovani eBay o jejich pouziti neuvazoval, ale na nejakou intranetovou aplikaci je JSF dobre. Ono to tvoje ukladani objektu do memcached je obdobne jako ukladani do session, mozna nejaky aplikacni server memcached pouziva… Pro jednoduchou aplikaci jsou session pro ulozeni trebas toho prihlaseneho uzivatele dostacujici a jednoduche na naprogramovani. Kdyz potrebujes scalable aplikaci, tak musis nahradit vlastni implementaci kde co, treba tak jak popisujes…

    Cyril

    26 května, 2008 at 9:43 pm

  2. Co se JSF týče, pak session pro ukládání stavu komponent používají proto, protože komponentový strom stránky není statický (oproti např. Tapestry). Pokud přijde nějaký požadavek od klienty je nutné znát jak tento strom komponent vypadal .. proto mají JSF strom v sessioně a je problém je škálovat na víc strojů jinak než pomocí sticky session.

    Jira

    27 května, 2008 at 7:11 am

  3. Ja session vyuzivam mohutne 🙂
    Myslim, ze rict, ze session je vhodna pro nakupni kosik a prihlaseneho uzivatele je dost malo.
    Pokud zacnu tvorit bohatou webovou aplikaci prospikovanou ajaxem, tak session mi pomaha odstinit se od http.
    Tam, kde to jde vyuziji konverace Seamu.
    Takze session hlavne vyuzivam pro „udržování stavu uživatelského rozhraní“.

    Ono i v samotnem JSF je dost pracne a netrivialni minimalizovat session. Fazi JSF je tolik, ze bez cachovani bych volal business logiku X krat (pokud to radne nehackuji a neladim k dokonalosti :0).

    Mozna muj pristup neni uplne idealni, ale vzdy, kdyz jsem se snazil snizovat scope, tak jsem akorat resil, jak zachytit „toto“, jak nevolat vicekrat „tamto“ a jak se vubec dobrat vysledku 🙂

    finc

    27 května, 2008 at 8:53 am

  4. Jira: chápu, že strom komponent se mezi požadavky přenáší z nějakého důvodu a ne pro srandu králíkům. Ale uvažuju takto:

    JSF má dynamický strom komponent. Kvůli tomu jej musí přenášet mezi požadavky. Tudíž je třeba udržovat netriviálně velikou session nebo přenášet s každým požadavkem nemalý balast. Hmm… opravdu je ten dynamický strom komponent taková výhra?

    Pavel Kolesnikov

    27 května, 2008 at 8:53 am

  5. Udržování aktualního stavu aplikace v session je výhodné u velmi složitých editorů, kde je třeba složitějších vicestavových komponent. Udržování stavu je také dobrým nástrojem jak se bráníme pozměňování formulářů na straně klienta – například pokud zobrazuju needitovatelnou komponentu, tak od ní nepřijímám modifikace i když byla stránka pozměněna a komponenta povolena na editaci (stav editavatelnosti je uchován na serveru). Dříve ten stav byl i persistentní, tj. po znovupřihlášení měl uživatel stav jako před odhlášením (samozřejmě s nějakou expirací). Tento stav je modifikován jak normálními tak AJAX požadavky.

    Máme to uděláno ještě trochu složitější: udržujeme cache i session – stav je uchován v cache a serializovan jako pole bytu do session, na ostatních serverech není stav pokaždé deserializován, jen pokud uzivatelův primarní server umře, pak se při přístupu na sekundární vezme ze session pole bytu a deserializací se v cache vytvoří stav. Tj. je to cache s duplikováním reprezenace stavu do session pro pripad vypadku serveru. Použiváme aplikační server Weblogic, který funguje tak, ze uživateli přiřadí v clusteru jeden primární a jeden sekundární server (uchová v cookie) a jeho session z primárního replikuje pouze na sekundární, takže ta replikace ve větším clusteru není až tak hrozná.

    proton

    27 května, 2008 at 10:08 am

  6. Pavle, ja myslim, ze plati zlate pravidlo 80/20. Pro tu majoritu je patlani se s cimkoliv jinym nez HttpSession overhead, ktery jim nic neprinese. Minorita musi posoudit argumenty, ktere v clanku predkladas.

    „Nejmenší zlo je nakonec sessions ukládat do nějakého relativně persistentního úložiště vně aplikačního serveru – zpoždění sítě a potřebné serializace a deserializace sice mírně brzdí, ale aspoň neovlivňují zbytek clusteru.“

    Ja myslim, ze hodne prikladu ukazalo, ze pokud je session napriklad serializovana do databaze, tak je to seriozni uzke hrdlo. Rozhodne bych tedy neradil, aby nekdo zacal prepisovat svoji aplikaci z HttpSession na nejakou vlastni serializaci napr. do databaze z presvedceni, ze mu to pomuze v skalovatelnosti. To myslim pak dopada presne naopak.

    Dagi

    27 května, 2008 at 10:12 am

  7. Session je jedinečné úložiště pro dočasná data. Tzn. taková data, která nepatří do databáze, ale která potřebují žít několik desítek minut. Co mezi taková data zařadit, záleží na aplikaci. Může to být ten nákupní košík a nemusí.
    Co se týče škálovatelnosti session, tak tady záleží na implementaci. Můžu session zapisovat do databáze, clusterovat je pomocí Terracoty nebo si ji všelijak meze servery přeposílat. Lepší server by mi měl umožnit si vybrat.
    Takže to zopakuji: Session je super pro data, která nejsou trvalá a nepatří do databáze. Záleží jen na implementaci jak dobře škáluje.

    Lukas Krecan

    27 května, 2008 at 10:50 am

  8. Dagi: s pravidlem 80/20 (a v tomto případě možná i 95/5) samozřejmě souhlasím. Celé to ublognuti je samozřejmě jen o scénáři, kdy horizontální škálovatelnost potřebuješ. Rozhodně nechodlám Cyrilovi nutit, aby se pohodlí sessions a JSF vzdával pro projekty typu malý intranet.

    (I když samozřejmě i tak může zvážit čistě klientské komponenty a většinu UI hrátek přenést do klientského skriptování. Mj. to bude záviset i na tom, jestli ho levněji vyjdou JSFkáři nebo JavaScriptéři)

    Co se týká serializace do databáze: jo, souhlasím, databáze je úzké hrdlo, aspoň pokud ji taky nedesignuješ rovnou pro horizontální škálovatelnost. Alternativou (IMHO v daném příkladu vhodnější) je třeba zmíněný memcached. A nebo další řešení, která následují po tebou ocitované větě:
    tedy hlavně zamyslet se, jestli session nezneužíváme a pro kešování použít explicitní keš.

    Pavel Kolesnikov

    27 května, 2008 at 11:29 am


Zanechat odpověď

Vyplňte detaily níže nebo klikněte na ikonu pro přihlášení:

Logo WordPress.com

Komentujete pomocí vašeho WordPress.com účtu. Odhlásit /  Změnit )

Google photo

Komentujete pomocí vašeho Google účtu. Odhlásit /  Změnit )

Twitter picture

Komentujete pomocí vašeho Twitter účtu. Odhlásit /  Změnit )

Facebook photo

Komentujete pomocí vašeho Facebook účtu. Odhlásit /  Změnit )

Připojování k %s

%d blogerům se to líbí: