2010. november 28., vasárnap

Log

Ismétlés a tudásnak azannnya. Péntek délután az Egér Miklós Vasművekben beszámolót tartottam a websüketes túrkálásaimról és a servlet 3.0-ról. Nem sok új ahhoz képest amit már egyébként itt is leírtam pár postban és ott is elmondtam:

  1. A Servlet 3.0 zseniális lépés a java szerver oldali technológiában. Na jó ez kicsit túlzás, de végre egy nagyon lényeges újdonság, ami komolyan növeli a java szerverek teherbírását azáltal, hogy egy hosszú és esetleg nem igazán CPU igényes kiszolgálásnak nem kell feltétlenül külön szálat fentartani. Adatbázis műveletek, JMS üzenetre várakozás, de például akár várakozás más erőforrásokra is, pl gondolom nem igazán szeretnél szerver oldalon párhuzamosan 10 db jóminőségű hubble űrteleszkóp képet feldolgozni kicsi heap memóriával. Ugye...
  2. A Servlet 3.0 kifejezetten olyan dolgokra nagyon alkalmas, mint a long poll. Amit ugyebár a szerver push-kén használunk.
  3. A Websocket API, ami már ott van a firefox 4-ben, chrome 7, IE 9 (jajj hát ki legyen mindig a legutolsó) satöbbi, szóval ez az API lehetővé teszi, hogy TCP socket-szerű tartós kapcsolatot építsünk fel a kliens és a http szerver között.
  4. A Websocket API ha egyszer elterjed, komoly átalakítsok vállnak kézenfekvővé a szoftverfejlesztésben. Szerintem a legtöbb esetben maradnak a régi ajax hívások is, de jópár esetben a websocket le fogja helyettesíteni. A long poll biztos hogy menni fog.
  5. Ennél vlószinűleg lényegesebb kihívásokkal kell az üzemeltetés terén szembenézni. A Websocket ugyebár HTTP 101 "Switching Protocol" státusszal kezdődik és innentől az egész kommunikáció nagyon más, mint egy szokásos HTTP kapcsolat során. Kell számítani nehézségekre a proxykon, load ballancereken, stb. Azóta kipróbáltam, hogy apache mod_proxy korrekten kezeli-e ezt a protokolt, de nem ment vele. Aztán lehet az apacs mágusok életre tudják kelteni, de nekem nem ment. Még ki kell próbálnom mod_ajp-vel is, valamiért én inkáb azt használom ha muszáj, nekem az egyszerűbb.
    Viszont a másik kérdés: akarunk apacsot az egész elé? Amikor az kapcsolatonként 1 processzt de legalábbis egy szálat visz, míg a java szerver oldalon már nincs erre szükségünk? Lehet a httpd bottleneck lesz az architektúrában? Illetve most még nem az?
  6. Még mindig kérdés, hogy szükség lesz-e a websocket témogatásához valami külön servlet engine kiegészítéshez, vagy belefér-e a sima servlet API-ba. Szerintem kifejezetten jobb lenne, ha a servlet API fürgén előjönne valami támogatással, én mindenesetre a jetty saját apiját használom. Ebből következőleg a kód nem fut pl tomcaten.
  7. Ilyen módon mire tényleg használatba vesszük a Servlet 3.0 API-t, talán már nem is lesz rá szükségünk sokáig. Ugyanakkor az, hogy nem tartunk külön szálat minden kliens kapcsolatnak, még inkáb fontos lesz ha majd egyszer Websocket klienseket szolgálunk ki.
  8. Ezzel kapcsolatban kicsit szorgoskodtam és dolgozok még mindig egy olyan prototipuson, ami a kliens elől eltakarja hogy long-pollt vagy websocket-et használ. Ennek egy működőképes változata itten-e van. Próbáljátok ki: svn co után mvn jetty:run. Ez a prototipus egyébként egy kicsit elvetemültebb koncepció és télleg csak kisérleti jellegű. Ha egyszer megnő, akkor meg fog érdemelni egy magyarázatot itt, addig még kalapálom és dumálunk róla.
Szóval mindez még nagyon messze van az éles bevetéstől.

2010. november 17., szerda

Sonar eclipse plugin (FYI)

András hívta fel a figyelmem erre a pluginra, igazi frankó cucc :-) Amúgy nem szeretem pluginekkel telezsúfolni az eclipse-t, stabilabb biztosan nem lesz tőle, de ez egy értelmes ötlet: ahol hegesztek, ott nézhetem a hegesztés minőségét is és javíthatok rajta.

Király lenne az open source projectjeimhez egy sonar valahol, otthon is jó lenne bevetni. Az anzix.net-en ment egy, de eltünt.

Valamint még azt akartam kérni, hogy aki ott van a JUM-on, az légyszi írjon már beszámolót, lehetőleg minnél többen. Én még mindig melóban. Köszi...

2010. október 29., péntek

retró

Arra még emlékeztek, hogy valamikor régen CD-n és DVD-n terjesztettek szoftvereket? Pár levitézlett harcost bemutatnék a képről: IBM DB2 és Websphere, Rational, SAP gányolmány nagy mennyiségekben (hogy szerettem a német rövidítéseket az abapban...), Novell féle suse, Sun One appszerver (6 CD!!!) A kupca alján van valahol pár Oracle motyó is, tudom hogy valahol van benne Sybase is. Na meg a hardware-k kidobált windowsos driver CD-i. A microsoft termékek hiányoznak totál szőröstül bőröstül, mert azt itthon nem használok.

Szakmai önéletrajz helyett, mondjuk úgy 5-6 évvel ezelöttig :-)

2010. október 28., csütörtök

ws://

A héten kerítettem időt magamnak egy pár prototipus fejlesztésre és kifejezetten érdekelt a html5 (ezzel kapcsolatban szólt ki ugye nemrég a w3c-s csákó, hogy még sehol sem production quality, ezt egyébként tapasztaltam is) websocket. Amit összetúrtam, az tényleg csak a prototipus építés összegzése, ne vegyétek valami szakértői véleménynek :-)
Szóval nézzük mi ez az egész...

A hiper-szuper interaktív szines-szagos weblapok fejlesztésénél a jó öreg request-response megoldás már nem nyerő. A websocket tulajdonképpen egy socket szerű dolog. Küldözgethetsz rajta mindkét irányba üzeneteket, ahogy tetszik. Azt a problémát akarja megoldani, mint az adobe RTMP nevű szőrös gorillája. Konkrétan az is tud utazni http felett, de hát ezt a dolgot jobb nem eröltetni, ugyanis mocskosul lassú.

Nos hogy a rákba fér bele a socket-szerű működés a http protokolba? Nem egyszerűen. Eredetileg úgy volt, hogy a ws protokol nem a 80-as porton fog utazni, hanem 81-es. Aztán ezt az ötletet elvetették, rettegve a firewalloktól és a proxyktól, most ott tart az ötlet - és úgy tűnik ezen már nem változtatnak - hogy ez is a 80-as porton fog utazni. A wikipédia cikk tök jól leírja, hogy fog ez működni. Nem is tudom használták-e valamire idáig a http 101 státusz kódot.

Browser háború

A wikipédia cikk a mainstream broesereket is felsorolja, csak annyit jegyeznék meg ezzel kapcsolatban, hogy jelenleg a chromium az egyetlen browser, ami kint van mainstream elérhető több oprendszerre web socket támogatással. Annak mennyi a piaci részesedése? Nem sok. A Internet exploiter 9 tartalmaz majd websocket támogatást, ez jelenleg testdrive.
Szóval erről az oldaláról a dolog szerintem jelenleg nem bevethető állapotú.

Szerver háború

Aki a szerver oldalt akarja bütykülni, annak se lesz egyszerű dolga még egy jó ideig, a java servlet ugyanis semmi támogatást nem ad az egészhez. Két dolgot találtam a weben, amit fel lehet használni:

  • jwebsocket hát vele az a baj, hogy a protokolt implementálja kivállóan, csak nem fér rá a http portra mellé. Szóval muszáj neki alternatív portot meghatározni. Nem tudom mekkora gubanc a firewallok használata ebből a szempontból, pl már dolgoztam olyan helyen, ahol nem engedték ki az ismeretlen protokolokat. Pl ssh-val se lehetett kimenni. Hájli szikjúr... volt, amíg fel nem találták a pendrive-ot.
  • A jetty-s srácok csináltak egy nagyon szép kis apit a websocket kezelésére. És még ráadásul működik is, csodaszép és egyszerű. Egy baja van: totál jetty specifikus. Szóval hozzáberhelted az alkalmazásod a jetty containerhez. Amíg ki nem jön valami spec, addig jóban rosszban együt.
Etc háború

Hát az egészet azért bonyolították meg, hogy mehessen a 80-as porton. És megy is, de hogy ez mennyire van tesztelve az infrastruktúra többi részén... ilyenekre gondolok:
  1. proxyk kifejezetten
  2. http load ballancerek
  3. firewall-ok
Szóval hogy ez mind boldog lesz vajon? Annyi már most biztosnak tűnik, hogy a servlet 3.0-nál is jobban át kell majd rendezni az architektúrát.

Kérdések

Ha egyszer ez végre teljesen oké lesz és működik, akkor vajon
  1. Volt-e értelme a servlet 3.0-nak? :) Mert akkor csak úgy áttolnánk minden lassú interakciót websocketen, majd szól a szerver ha kész. (mondjuk a servlet 3.0 már itt van, a websocket meg mint kiderült még sehol)
  2. Ez az ajax hívások túlnyomó részét át fogja venni? Amit cachelünk, azt gondolom jobb lesz mégis a régi módszerrel küldeni.
  3. Nyugdíjba megy az ajax push? Nem fog hiányozni! :-)
  4. Például a socketek kiszolgálását hogyan lehet majd loadballancelni? Egész végig 1 ugyanaz a szerver fogja kiszolgálni a socketet?
Hát ennyit túrtam fel, azt hiszem most még kicsit rugdosom de hagyom érni még egy ideig. Azért ennek a technológiának a bevetéséhez igen alaposan át kell majd forgatnunk pár dolgot, egy ideig attól tartok el fog tartani, és még sehol sem tartunk vele.

2010. október 19., kedd

Az indiánok üldöztetése

Egyik nap apache benchmarkkal méregettem az egyik webappom válaszidejét és terhelhetőségét és hát nem voltam igazán boldog. Gondoltam, hogy már nem sok mindent lehet húzni rajta, sima adatbázis cókmókot pakol bele xml-be oszt jónapot, az egész architektúra a dögunalomig menően szokványos.

A tuningolás egyébként izgalmas téma, ezer dologgal lehet húzni egy ilyen rendszert, adatbázis optimalizálás, cache réteg kidolgozása, a DAO réteg optimalizálása, profile-olás, garbage collector tuningolás, memóriaparaméterezés, jdbc connection pool buhera, threadpool buhera... és mindezen már túl voltam és az egész még mindig nem muzsikált úgy ahogy nekem tetszik. Azért éreztem nyekergésnek az egészet, mert ugyanezen a vason lemértem hogy a default apache installáció statikus html tartalommal mit tud kezdeni. Rendesen odacsűrt a procinak, de 5000 req/sec körül teljesített. Ez nyilván egy unfair összehasonlítás, mert az apacsnak semmi mást nem kellett csinálnia, csak kipumpálnia egy file-t a tcp socketen. Ez adta az ötletet, hogy ha az én rendszeremnek csak ennyit kellene csinálnia, akkor megcsíphetné az apacs tempóját.

És ezt a receptet főztem ki:

  1. Végy egy filtert. Nevezd el ResponseCacheFilternek
  2. Végy egy JCache (ez az oldal kiválló példája egy halott JCR-nek) implementációt, de ha nincs vagy bizonytalan vagy, jó lesz egy HashMap is, lehetőleg legalább az adatokat Ref-fel csomagold hogy OOM-et azért mégse okozzon
  3. Fogd meg a HttpServletResponse-t és gondosan tekerd be egy HttpServletResponseWrapper-be. Itt van néhány trükk amit csinálni kell, de a lényeg hogy írj egy olyan ServletOutputStream-et, ami hasonlóan a apache commons io TeeOutputStream-jéhez (esetleg építhetsz is erre az osztályra) másolatot készít a kiírt adatból. Szerintem célszerű egy ByteArrayOutputStream-et használni ha az eredmény nem véresen nagy. Esetleg csinálhatsz köré egy limitált verziót, ami egy limit után már nem ír (mint pl a CountingInputstream)
  4. A filtered egyszerűen csak dobja tovább a végrehajtást az adatbázisba matató kódnak, ami majd mégtovább dobja az adatbázisból kiberhelt adatokat kiszerializáló kódnak, satöbbi. A végén valahogy a vezérlés visszakerül a filterhez.
  5. No ekkor kapjuk el a HttpServletResponseWrapperünk grabancát és követeljük tőle servlet output stream-re kiírt adatok másolatát, ez egy plain byte tömb ha minden igaz. Egyszerűen csak csináljunk egy kulcsot a request paramétereiből, és az értékként használva a response másolatát dobjuk be a cache-be
  6. A következő requestek beérkezésekor a requestből összebütykölt kulccsal megnézheted, hogy van-e cachelt válasz, ha nincs lásd fenti pontok, ha pedig van, akkor boldogság, mert csak egy byte tömböt kell kidobnod.
  7. Ezt a filtert applikáld rá a tipikusan csakis olvasást végző műveleteidre. Pl getCustomer, getLatestPosts, stb.
  8. Lesz még itt bonyolítás: a módosítást végző kód kell hogy kérni tudja a fenti response cache egyes elemeinek kiürítését. Ide clusteres esetben szerintem egy jms topicon érdemes körbeküldeni egy ID-t vagy hasonlót, ha nincs igény culsterezésre, elég csak direktben törölgetni kulcsokat a cache-ből. (erre is lehet kultúráltnak látszó kódot írni, akármilyen bunkón is hangzik)
  9. Kész! Elő a benchmark eszközzel!
Csak ennyivel még nem sikerült megszorongatni az apacsot, bár a teljesítmény igen látványosan megnőtt, de még most jön egy desszert.

A browserek (söt talán már az internet explorer is) képesek tömörített tartalmat kezelni. Az "Accept-Encoding" headerben küldik meg, hogy ők mit fogadnak el. Na ezt ki lehet használni. Általában azt szokták mondani, hogy hülye dolog generált tartalmat is gzippelni, mert sok időt visz. Talán így van, de ha csak egyszer generáljuk a tartalmat, és az eredményt becacheljük, akkor onnantól már nem kell újra és újra gzipelnünk a generált tartalmat. Ez lényegesen csökkenti  a hálózati forgalmat. Egy gzippelt response törtrésze az eredeti tartalomnak. Példaként a jól ismert JQuery minified 76 K gzippelve csak 26 K. Ez most egy rossz példa volt, mert az alig a harmada, de az én teszt kimeneteim harmincadukra estek össze és ez tényleg sokat dobott rajta.

Ez az egész csak akkor hatásos, ha az alkalmazás az olvasások számához képest ritkán módisítja a kimenetet ÉS a pillanatnyi pontos állapot nem fontosabb, mint a jó válaszidő. A legtöbb webapp tipikusan ilyen szerintem. Az internet ilyen. Egy bank esetében atomkatasztrófával érne fel, de speciel egy blogger cikk esetében nem nagyon érdekel senkit sem, hogy publish után még akár fél másodpercig is a régi tartalom jelenik meg másoknak.

Itt most egy kicsit kénytelen vagyok ködösíteni, mert mégiscsak a konkrét alkalmazáson múlik, de a cucc teljesítménye így vetekedhet, söt verheti is az apache statikus oldalak sebességét -ami mégegyszer nagyon unfair összehasonlítás, hiszen az apacsot nem tuningoltuk és esetleg csinál egy rakás egyebet amit a jetty vagy tomcat nem, és fordítva.
A válaszidőkről még annyit, hogy amikor egy-egy kulcs (vagy egyszerre több is) kiesik a cache-ből TTL, GC vagy a fenti kódolt mechanizmus által, újra a régi és lényegesen lassabbnak mért kódunk lép működésbe és ilyenkor amíg a cache-ben meg nem jelenik újra az eredmény esetleg több kérés is a háttérlogika végrehajtásához kezd, ami például tökönrúgja az adatbázist. Egy mérésben ez meg is fog látszani, tipikus bemélyedések szabályos időközönként.
Már erre is volt megoldásom egyébként, csak még nem építettem bele ebbe a response cache megoldásba, nagyjáből annyi, hogy háttérszálon is frissítheted az eredményt, ha nem borzasztó sürgős és kritikus fontosságú mindig pontos eredményt adni, és addig visszaadhatod a régi eredményt. Persze ha a cache-d nem dobja ki a régi eredményt. Szóval ez egy kicsit gubancosabb történet, de végig lehet járni ha valaki ki akarja kalapálni a csorbákat a performace görbéjén.

Na ennyi, remélem valamennyire tanulságos volt. A francba kedd lett közben, akkor jöjjön még egy ilyen a teljesítmény tuningoláshoz:

Egyik nap azt találom ki
Hogy másnap százon én nyerek
És nő hegyek vesznek körül
De én nem szeretek egyet se
Még párszor győzök
De már csak megszokásból

2010. október 13., szerda

JaSON is EVAL...

Tegnap próbálgattam JQuery 1.4-gyel meghívni egy kézzel hímzett JSON-t gyártó ajax backendet és nagyon furcsa eredményeket kaptam. Egész pontosan a callback metódus nem került meghívásra, és pedig azért, mert nem tudta felparsoloni a json kimenetet. Néztük ketten is, hogy hol lehet a gubanc a kimenetben, és mint kiderült az idézőjelekkel volt a baj. Egyszeres idézőjel nem jó, dupla idézőjel jó.

A dolog egyébként azért volt meglepetés, mert nyilván erre a kézzel hímzett json kimenetre is írtunk validációt és a jávás json parser átengedte simán, mint ahogy a JQuery 1.3 is. Nekem kicsit a régi CORBA idők jutottak eszembe róla. Bár a probléma gyökere más, ami a felszinen van, az mégiscsak rémesen hasonlít :-(

2010. szeptember 23., csütörtök

egy üzenet magamnak

Gyónás következik... Kicsit nehéz volt elmagyaráznom az operátoroknak is és végülis szerintem csak félig lett a vége megértés és a másik felében inkább napirendre térés, de mostanában számos JMS queue ütötte fel a fejét, aminek mindkét végén ugynanaz a webapp áll. JMS-t egyébént arra használja az ember, hogy más szolgáltatásokhoz üzeneteket küldjön és nem mellesleg biztos akar abban lenni hogy nem is alkalmatlankodik a kéréssel és egyszer ki is lesz szolgálva. Nos nekem ilyen nem áll rendelkezésre, nekem sima SOAP és egyéb http backendek vannak. Szóval amikor a webappom kiveszi a kérést a JMS-ből, akkor egy SOAP hívást küld tovább. Ha nem sikerült (pl network outage, server crash valahol, konfigurációs gubancok, satöbbi), akkor bátran és nagy magabiztossággal eldobom az exceptiont a message meg mehet a dead letter queue-ba vagy konfigtól függően újra besorolásra, legközelebb hátha több szerencséje lesz.

Szóval ez nekem olyan eccerű megoldásnak tűnik, JMS-SOAP bridge. Nem lesz ez mindig muszáj, már úton van a CXF-ben is a soap-over-jms cucc, más web service stackokban már talán ott is van.

Csak ennyit akartam mondani, köszönöm a figyelmet.