Obsah Dal¹í Pøedchozí

5 Servery systému Agent

Tato kapitola se podrobnì zabývá serverovými komponentami systému Agent. Nejprve v èásti Architektura serverù systému Agent (5.1) popisuje serverovou èást systému Agent jako celek a poté také to, co mají oba servery spoleèné, tedy jaké koncepty a technologie sdílejí. Dále je v èásti Vyhledávací server (search_svr) (5.2) popsán vyhledávací server systému Agent. Dùle¾itá je zejména kapitola Databázový stroj (5.2.1) popisující implementaci jádra systému Agent - plnotextového vyhledávacího stroje. Kapitola Sí»ový server (net_svr) (5.3) se zabývá specifiky sí»ového serveru systému Agent.

5.1 Architektura serverù systému Agent

Na obrázku 5.1-1 vidíte logický pohled na architekturu serverù systému Agent. Pro jednoduchost je zobrazen pouze jeden vyhledávací a jeden sí»ový server. Z obrázku je patrná modularita návrhu systému, která se samozøejmì promítla i do vlastní implementace.

Obrázek 5.1-1 - architektura serverù Agent
Obrázek 5.1-1 - architektura serverù Agent

V následujících odstavcích probereme nìkteré dùle¾ité prvky implementace. Za prvé je to charakter databázového stroje, ten je koncipován jako knihovna. Neobsahuje tedy ¾ádné øídící objekty - ¾ádná vlastní vlákna výpoètu. Navíc je zcela oddìlen od zbytku vyhledávacího serveru a komunikovat s ním lze pouze skrze pøesnì definovanou mno¾inu objektù tvoøících rozhraní k databázovému stroji. Toto rozhraní tvoøí objektový model databázového stroje a umo¾òuje jeho budoucí vyjmutí a znovupou¾ití v jiném systému. Dal¹í samostatný podsystém tvoøí filtry. I ty jsou zcela nezávislou èástí sytému a øídící objekty serveru s nimi komunikují pouze prostøednictvím objektu FilterManager.

Rovnì¾ komunikaèní vrstva serveru se neprojevila na designu jádra serverù. Naopak rámec (framework) architektury, podrobnì rozebraný v následující kapitole, je koncipován tak, aby bylo mo¾né snadno vymìnit komunikaèní vrstvu za jinou. Toho také bylo vyu¾ito v prùbìhu vývoje systému. O rozhraní sí»ového serveru bylo rozhodnuto hned na poèátku vývoje: nic jiného ne¾ TCP/IP se nejevilo jako smysluplné. Naopak o rozhraní mezi vyhledávacím serverem a sí»ovým serverem dlouho nebylo jasno. Pùvodní zámìr poèítal s vyu¾itím technologie OLE Automation, zalo¾ené na komponentovém modelu COM. Nakonec se v¹ak ukázalo, ¾e tato technologie má jistá omezení týkající se práce s více vlákny v prostøedí Windows 95, která by ohrozila ¹kálovatelnost a výkon vyhledávacího serveru. Proto bylo i pro komunikaci mezi vyhledávacím serverem a sí»ovým serverem zvoleno osvìdèené TCP/IP.

Stejnì jako vìt¹ina serverù na Internetu (HTTP servery, FTP servery) i systém Agent pou¾ívá pro komunikaci se svými klienty textové rozhraní1). Fyzické rozhraní serverù tedy splòuje jednoduchý model typu po¾adavek/odpovìï (request/response) a celá slo¾itost rozhraní se pøesouvá dovnitø serverù. Toto øe¹ení má tu výhodu, ¾e dle specifikace jazyka rozhraní mù¾e kdokoliv v jakémkoliv programovacím jazyce umo¾òujícím komunikaci pøes TCP/IP napsat klienta systému Agent. Nevýhoda v¹ak spoèívá ve slo¾itosti vyhodnocování takového jazyka jak na stranì serveru tak na stranì klienta. Servery systému Agent èelí tomuto problému tím, ¾e interpretaci jazyka a indikaci chybných povelù zaji¹»uje automat vygenerovaný na základì gramatiky uvedené ve speciálním konfiguraèním souboru. To umo¾òuje pru¾né zmìny jazyka i znaèné znovuvyu¾ití parsovacího kódu obìma servery. Zároveò se tím znaènì eliminovala potenciální chybovost, která by hrozila pøi manuálním implementování této funkcionality.

Poznámka 1: Rozhraní serverù není èistì textové. Ka¾dá zpráva, která má být serverem pøijata, i ka¾dá, která je serverem odeslána, obsahuje binární hlavièku o délce deset bajtù. Více o komunikaèní vrstvì se dozvíte v kapitole Konektory (5.1.2).

5.1.1 Rámec architektury

Z povahy problému øe¹eného pøi návrhu architektury serverù systému Agent vyplynulo, ¾e bude nutné pomìrnì masivnì nasadit vícevláknové zpracování (multithreading). Av¹ak implementace aplikací umo¾òujích konkurentní nebo (na víceprocesorových poèítaèích) paralelní zpracování dat s sebou èasto nesou znaènì zvý¹ené nároky na odbornost a obezøetnost implementace a znaèné dodateèné náklady na odladìní systému.

Abychom zabránili tìmto problémùm, bylo tøeba zajistit, aby se problematika více vláken dotýkala pokud mo¾no minimální èásti kódu. To bylo zaji¹tìno na nìkolika úrovních. Pøednì byly u¾ pøi návrhu eliminovány ve¹keré aktivní objekty z databázového jádra. Dále bylo pøedem jasnì deklarováno, které datové struktury budou potenciálnì vyu¾ívány více vlákny najednou a u tìchto datových struktur (týká se to zejména databázového jádra) bylo vy¾adováno zaji¹tìní konzistence s pou¾itím synchronizaèních primitiv operaèního systému. Z výkonnostních ani implementaèních dùvodù v¹ak nebylo vhodné, aby mno¾ina takto o¹etøených objektù obsahovala v¹echny nebo velkou vìt¹inu objektù vyskytujících se v serverech systému Agent.

Proto byla architektura systému navr¾ena tak, aby objekty, které nemusí být nutnì sdíleny, sdíleny nebyly a navíc ani nebyly zasa¾eny synchronizaèním kódem. Naopak tyto objekty ¾ijí v umìle vytvoøeném prostøedí, které se chová jako by bylo souèástí jednoduché jednovláknové aplikace. Ve¹kerou problematiku vícevláknového zpracování a zaji¹tìní synchronizace aktivních objektù si berou na svá bedra tak zvané výkonné objekty jádra. Tyto objekty tvoøí kostru architektury serverù systému Agent a jsou pro oba servery shodné.

Na obrázku 5.1.1-1 vidíte schematické zobrazení konceptu. Ten lze struènì shrnout do následujících nìkolika odstavcù. Konkurenèní zpracování je v serverech systému Agent zaji¹tìno pomocí metody zvané thread pool, tedy skupiny rovnocenných vláken, která jsou vzájemnì zamìnitelná. V¹echna vlákna jsou v systému Agent implementována jako objekty, jejich¾ tøídy dìdí od spoleèného pøedka zvaného Runnable. Vlákna sdru¾ená ve thread poolu jsou instancemi tøídy zvané EaterThread. Tyto objekty nedìlají nic jiného, ne¾ ¾e ètou zprávy ze vstupní fronty zpráv. Ve chvíli kdy pøeètou zprávu, povìøí svou instanci potomka abstraktní tøídy Worker, aby zpracoval po¾adavek, a poté zapí¹í výsledek do výstupní fronty.

Obrázek 5.1.1-1 - schematické zobrazení architektury serveru

V¹echnu vlastní práci tedy vykonají objekty typu Worker. Jak ji¾ bylo uvedeno vý¹e, ka¾dé vlákno ve thread poolu má svého "dìlníka". Ten je inicializován tak, ¾e "vidí" v¹echny potøebné datové struktury, nebo si je umí vytvoøit. Èást tìchto struktur je sdílena mezi vlákny výpoètu (a ty musí být zabezpeèeny) a èást z nich vlastní ka¾dý "dìlník" jako kopii pro svou vlastní potøebu. Ka¾dý "dìlník" tedy ¾ije ve svém vlastním svìtì a neví nic o ostatních ani o tom, ¾e bì¾í v prostøedí s více vlákny.

Je samozøejmé, ¾e v¹echno není tak jednoduché. Jak jsme øekli ji¾ vý¹e jednotlivá vlákna ve thread poolu jsou zamìnitelná. Je tedy jedno, které z vláken zpracuje právì pøíchozí po¾adavek. Aby tento mechanismus správnì fungoval, musí být zaji¹tìno korektní ulo¾ení stavu výpoètu. Jinými slovy, lokální datové struktury mù¾e ka¾dý "dìlník" pou¾ívat pouze pro ulo¾ení doèasného stavu výpoètu. Data jsou tedy platná pouze v rámci vyøizování jednoho po¾adavku. Informace, které mají pøeèkat tuto dobu, aby mohly být pou¾ity pøi zpracování nìjakého následujícího po¾adavku, musí být ulo¾eny ve sdílených datových strukturách dostupných i pro "dìlníky" z jiných vláken. Vlastní "dìlníci" tedy musí být bezstavové objekty.

Synchronizaèní body - øídící objekty

Jaké jsou tedy synchronizaèní body v architektuøe serverù systému Agent? Jednak jsou to zabezpeèená místa ve sdílených datových strukturách a jednak to jsou vstupní fronta po¾adavkù a výstupní fronta odpovìdí. Jeliko¾ pracovní thready jsou zamìnitelné a jejich objekty de facto bezstavové, je mo¾né pru¾nì mìnit jejich poèet. Vstupní a výstupní fronty se zamykají pouze na dobu vlo¾ení a vyjmutí prvku. ©kálovatelnost celého systému je tedy pøímo (a pouze) závislá na propustnosti sdílených datových struktur, v na¹em pøípadì databázového stroje.

5.1.2 Konektory

Do skupiny "konektory" øadíme ty objekty v systému Agent, které mají zajistit komunikaci mezi jednotlivými servery, pøípadnì mezi servery a klienty. Jak ji¾ bylo uvedeno vý¹e, konektory v systému Agent zapouzdøují komunikaci nad protokolem TCP/IP.

Pro potøeby projektu Agent byl stanoven protokol pracující jako nadstavba nad TCP/IP. Aplikace v rámci systému pou¾ívají proudovì orientované (stream oriented) spojení poskytované protokolem TCP/IP. Aplikace v systému Agent v¹ak nepracují s proudy, nýbr¾ s po¾adavky a odpovìïmi (requests/responses). Data tedy teèou ve formì zpráv. Jeliko¾ jsou tyto zprávy asynchronní nesou si svoji identifikaci. Pokud klient posílá po¾adavek na server, oznaèí po¾adavek (pro sebe) unikátním èíslem. Odpovìï na po¾adavek pøijde oznaèena stejným èíslem. Server identifikuje ka¾dou zprávu uspoøádanou dvojicí <identifikace klienta, identifikace zprávy>. Není tedy nutné, aby identifikátory zpráv byly globálnì unikátní.

Celá zpráva, vèetnì identifikace zprávy, po¾adavku i odpovìdi je zapouzdøena do objektového typu. Proto je jádro systému nezávislé na pou¾ité komunikaèní vrstvì. Pokud se zmìní komunikaèní vrstva a zmìní se napøíklad zpùsob identifikace klienta, jádro se o tom vùbec nedozví, proto¾e se o identifikaci zprávy nestará. Jak jste si jistì v¹imli z pøedchozího výkladu a obrázkù, jádro prostì vezme po¾adavek z fronty, vyøídí ho a zase ulo¾í do fronty. Správné mapování odpovìdí ke správným klientùm zaøídí a¾ komunikaèní vrstva, která ète zprávy z fronty odpovìdí. Ta samozøejmì musí obsahu identifikace zprávy rozumìt, ov¹em zajímá se opìt pouze o identifikaci klienta. Interpretace èísla pøiøazeného zprávì je a¾ na klientovi.

Jak vyplývá z pøedchozího odstavce, jediné co musí zpráva posílaná mezi aplikacemi v systému Agent obsahovat je lokálnì unikátní èíslo, které umo¾ní spárovat po¾adavky a odpovìdi. Ve skuteènosti to v¹ak není v¹echno. Spolu se zprávou se zasílá je¹tì délka datového obsahu zprávy. To slou¾í jako bezpeènostní opatøení. Servery systému Agent mají zakódovanou maximální délku zprávy, kterou mohou akceptovat. Pokud je pøi pøijímání zprávy poru¹en formát hlavièky nebo délka zprávy pøekroèí povolenou mez, je serverem vyslána chybová zpráva a klient je okam¾itì odpojen.

Podrobný popis formátu hlavièky naleznete ve zdrojovém souboru genericsocket.h. V pøípadì, ¾e chcete psát klienta systému Agent, není nutné tento formát studovat. Existují toti¾ právì zmiòované tøídy, které zapouzdøují komunikaci se servery systému Agent. Tyto tøídy jsou implementovány pro jazyk C++ a Java. Pro jazyk C++ se jedná o tøídy Agent::GenericSocket a Agent::ClientSocket, pro Javu pak agent.HeaderRW a agent.HeaderSet.


1999-03-05 Jaroslav Gergic