Vyšlo v týdeníku Computerworld č. 1/94 v roce 1994
Vytištěno z adresy: http://www.earchiv.cz/a94/a401c110.php3

RPC II.

V minulém dílu jsme se začali podrobněji zabývat mechanismem volání vzdálených procedur (RPC, Remote Procedure Call), a to v kontextu implementace protokolu NFS pro transparentní sdílení souborů v sítích. Tento všeobecně použitelný mechanismus byl totiž poprvé ve významnějším měřítku použit právě pro implementaci protokolu NFS. Minule jsme se seznámili s jeho celkovou filosofií, a dnes již dojde řada na to, jakým konkrétním způsobem tento obecný mechanismus implementovala a standardizovala firma Sun Microsystems.

Úvodem je vhodné si zdůraznit vztah firmy Sun Microsystems k mechanismu RPC a jeho standardizaci - platí zde přesně totéž, co jsme si v 75. dílu říkali již v souvislosti s protokolem NFS. Samotné volání vzdálených procedur můžeme chápat jako obecnou myšlenku, postup či techniku, kterou může kdokoli implementovat podle svých vlastních představ. Firma Sun Microsystems tak učinila, své konkrétní řešení zveřejnila, toto se ujalo a stalo se všeobecně uznávaným standardem v rámci rodiny protokolů TCP/IP (kodifikovaným ve formě dokumentu RFC, viz 75. díl). Pokud se tedy v dalším budeme odvolávat na mechanismus RPC resp. na standard RPC, budeme tím mít na mysli jednu konkrétní implementaci, resp. jeden konkrétní standard, pocházející od firmy Sun Microsystems.

Identifikátory vzdálených procedur

Pro správné pochopení způsobu, jakým je mechanismu RPC implementován, je vhodné začít s následující představou:

každá vzdálená procedura má přiřazen jednoznačný číselný identifikátor, a její vzdálené volání (tj. volání na straně klienta) má obecně tvar
CALL ( <číslo_vzdálené_procedury> )

Praktická realizace této jednoduché myšlenky ovšem vyžaduje zavést vhodný řád do přidělování takovýchto číselných identifikátorů - aby byla zachována konzistence číslování procedur a jejich identifikátory byly skutečně jednoznačné (tedy aby se nikdy nemohlo stát, že dvě různé vzdálené procedury dostanou přiděleny stejné identifikátory). K tomu je ovšem nutná existence jediného centrálního subjektu, který bude přidělování těchto identifikátorů vhodně koordinovat. Této role se podujala právě firma Sun Microsystems.

Aby firma Sun Microsystems nemusela přidělovat jednoznačný identifikátor pro každou jednotlivou vzdálenou proceduru (což by bylo organizačně neúnosné), rozhodla se pro použití takových identifikátorů, které se skládají ze tří složek:

  • z tzv. čísla programu (program number), které souhrnně identifikuje skupinu procedur, zajišťujících určitou službu. Například všechny vzdálené procedury, které jsou používány v rámci implementace protokolu NFS, tvoří jednu takovouto skupinu, a mají tudíž přiřazeno jedno číslo programu (pro NFS konkrétně 10003).
  • z čísla procedury (procedure number), které jednoznačně identifikuje příslušnou proceduru v rámci její skupiny, a
  • z čísla verze (version number).
Logika, která stojí za tímto rozdělením identifikátorů na tři složky, je vcelku zřejmá: firmě Sun jako globálnímu koordinátorovi stačí pečovat pouze o jednoznačnost první složky. Kdokoli, kdo se rozhodne implementovat pomocí mechanismu RPC nějakou novou službu, si od firmy Sun může vyžádat jednoznačné číslo programu. Jednotlivým procedurám, které pak pro zajištění své služby vytvoří, již přiděluje druhou složku (číslo procedury) sám. Konečně třetí složka vychází vstříc postupnému vývoji jednotlivých služeb, který dává postupně vznikat novým a novým verzím. Díky této složce identifikátoru vzdálené procedury je pak možné průběžně implementovat nejnovější verze, ale současně s tím zabezpečit i zpětnou kompatibilitu a podporovat i verze předchozí.

Jeden parametr stačí

V zájmu snazší implementace zavedla firma Sun konvenci, že všechny vzdálené procedury mají právě jeden vstupní parametr, a právě jeden výstupní parametr (resp. vrací jediný výstup). Není ale tato konvence příliš omezující? Nikoli - pokud by bylo zapotřebí předat více parametrů, tyto se vhodně "zabalí" (přesněji: vytvoří se z nich vhodná datová struktura), a jako jediný vstupní parametr bude vzdálené proceduře předán ukazatel na tuto datovou strukturu, která samozřejmě musí být v rámci vzdáleného volání přenesena na server. K jejímu správnému využití je dále nutné, aby obě strany (tj. klient i server) byly předem dohodnuty na formátu této datové struktury a významu jejích jednotlivých částí. To se ale dá vcelku snadno zařídit (viz dále).

XDR - eXternal Data Representation

Poněkud složitější je ale to, aby obě strany také správně interpretovaly každou jednotlivou část vstupních a výstupních dat vzdálených procedur. Budou-li například srozuměny s tím, že obsah dvou bytů má představovat celé číslo bez znaménka, mohou jej stále ještě interpretovat různě - jedna strana může považovat za vyšší ten z obou bytů, který druhá strana naopak považuje za nižší.

Právě naznačený problém správné interpretace přenášených dat má dvě principiální řešení: první spočívá v tom, že každá zúčastněná strana bude předem znát konvence, které používá kterákoli druhá strana. Pak je možné při přenosu dat provést potřebné konverze nejvýše jednou - ať již u odesilatele, nebo u příjemce (případně je vůbec neprovádět, pokud obě strany používají přesně stejné konvence). Alternativním řešením je zavést jeden společný mezitvar, a veškerá data pak vždy přenášet v něm. To sice znamená provádět nezbytné konverze dvakrát (na straně příjemce i na straně odesilatele), ale současně to znamená i to, že každá strana vystačí vždy jen s jednou sadou konverzních prostředků, a nemusí se jakkoli přizpůsobovat případným novým konvencím druhých stran. No a právě toto druhé řešení zvolila firma Sun pro implementaci svého mechanismu RPC.

Konkrétní realizací této volby je pak standard XDR (eXternal Data Representation), který byl opět zveřejněn, je všeobecně uznáván jako standard v rámci rodiny protokolů TCP/IP, a je kodifikován formou dokumentu RFC.

Standard XDR tedy definuje jednotný způsob reprezentace přenášených dat, nezávislý na konkrétní architektuře jejich odesilatele i příjemce. Kromě toho je součástí XDR také jazyk pro nezávislý popis těchto dat. Po stránce implementační souvisí s tímto standardem také konkrétní konverzní rutiny, které mají nejčastěji formu knihovních rutin, a jsou obvykle označovány jak XDR filtry.

Volání vzdálených procedur na straně klienta

Nyní se můžeme opět vrátit k naší první představě volání vzdálených procedur - jakmile je dokážeme jednoznačně identifikovat pomocí vhodného identifikátoru (složeného z čísla programu, čísla verze a čísla procedury), může nám k jejich volání (na straně klienta) stačit vlastně jediný prostředek - systémová rutina, pojmenovaná příznačně callrpc. Ta má celkem osm parametrů:

  • identifikaci uzlu, na kterém má být vzdálená procedura provedena
  • číslo programu (program number) vzdálené procedury
  • číslo verze (version number) vzdálené procedury
  • číslo vzdálené procedury v rámci její skupiny (procedure number)
  • vstupní parametr vzdálené procedury
  • XDR filtr vstupního parametru (který definuje konverzní rutinu pro převod vstupního parametru do přenosového tvaru)
  • výstupní parametr vzdálené procedury
  • XDR filtr výstupního parametru
Na straně klienta lze vystačit jen s tímto jediným prostředkem, pomocí kterého lze volat libovolnou vzdálenou proceduru. Jak tomu ale bude na straně serveru, kde jsou jsou tyto vzdálené procedury skutečně prováděny?

Registrace vzdálených procedur

Na straně serveru musí vždy existovat někdo, kdo má přehled o službách poskytovaných formou vzdálených procedur - konkrétně o všech vzdálených procedurách, které je možné na daném serveru volat. Tím, kdo tento přehled má, je tzv. RPC dispečer (RPC library dispatcher), který je jednak příjemcem všech žádostí klientů o volání vzdálených procedur, a jednak skutečně volá ty lokální rutiny, které vzdálené procedury implementují (a vůči klientům proto vystupuje v roli spojky serveru, viz minulý díl). Každá lokální procedura, která chce implementovat některou vzdálenou proceduru, se musí u tohoto dispečera registrovat - přitom mu musí sdělit nejen to, o kterou vzdálenou proceduru se jedná, ale i konkrétní způsob svého volání, což vzhledem ke konvenci o jednom vstupním parametru a jednom výstupním parametru vzdálených procedur znamená v podstatě sdělení o tom, které konverzní rutiny má dispečer použít pro konverzi těchto parametrů z/do přenosového tvaru (neboť to musí být právě RPC dispečer, kdo potřebnou konverzi iniciuje).

Konkrétním prostředkem, kterým se lokální procedura registruje u RPC dispečera, je systémová rutina registerrpc s následujícími parametry:

  • číslo programu (program number) vzdálené procedury
  • číslo verze (version number) vzdálené procedury
  • číslo vzdálené procedury v rámci její skupiny (procedure number)
  • vstupní bod lokální procedury, která implementuje vzdálenou proceduru
  • vstupní parametr vzdálené procedury
  • XDR filtr vstupního parametru
  • výstupní parametr vzdálené procedury
  • XDR filtr výstupního parametru

Tři úrovně RPC

Právě naznačený způsob využití mechanismu RPC (na úrovni systémových rutin callrpc a registerrpc) není zdaleka jediný možný.

Mechanismus RPC lze obvykle využívat na třech různých úrovních, přičemž ta, kterou jsme až dosud předpokládali, představuje tu prostřední. Je charakteristická tím, že na této úrovni je nutné si uvědomovat existenci distribuovaného prostředí (tj. existenci vzdálených uzlů), a vyžaduje také znalost konkrétních vzdálených procedur (které je nutně explicitně určovat). Vše ostatní je ale podřízeno snaze o maximální jednoduchost využití celého mechanismu volání vzdálených procedur.

To ale nemusí být vždy výhodné. Při seriózní tvorbě aplikací, které mechanismus RPC využívají, může být velmi nevýhodné, že na této úrovni není možné nijak ovlivnit celou řadu konkrétních aspektů - například to, jakým konkrétní transportní mechanismus je využíván pro skutečný přenos v síti (zda jde např. o nespolehlivou datagramovou službu protokolu UDP, nebo o spolehlivou spojovanou službu protokolu TCP), jaké časové limity (timeout-y) jsou používány, jak je řešena otázka chyb, ověřování přístupových práv a totožnosti (authentication) apod.

Standard RPC je řešen nezávisle na transportním protokolu (aby mohl být implementován nad různými protokoly), a nesnaží se sám zavádět jakoukoli dodatečnou spolehlivost (ošetřováním chyb). Aplikace, která mechanismus RPC využívá, si proto musí uvědomovat, jaký transportní mechanismus je pro implementaci RPC použit, a sama si z toho vyvodit příslušné důsledky (mj. z hlediska spolehlivosti). Pokud potřebuje nějak zasáhnout do způsobu, jakým RPC transportní prostředky využívá, pak k tomu musí využít zmíněnou nejnižší úroveň práce s mechanismem RPC (což v podstatě znamená realizovat prostředky typu callrpc pomocí prostředků nižší úrovně).

Práce s mechanismem RPC na této nejnižší úrovni jej již značně netriviální, a je míněna především pro odborníky, kteří vytváří nové systémové prostředky a služby. Jejich náročný úkol přitom mohou usnadnit různé nástroje, mezi které patří zejména překladač rpcgen, vyvinutý firmou Sun. Jeho hlavním úkolem je překlenout rozdíl mezi střední a nejnižší úrovní práce s mechanismem RPC, zbavit programátory maxima "špinavé práce", a umožnit jim soustředit se na to, co je pro jejich aplikaci podstatné. Na základě obecnějšího popisu ve zvláštním RPC jazyku (velmi blízkému k jazyku C) totiž překladač rpcgen generuje to, co by jinak bylo třeba explicitně naprogramovat na nejnižší úrovni (ve formě zdrojových textů jazyka C).

Naproti tomu na nejvyšší úrovni je celý mechanismus RPC obvykle "zabalen" takovým způsobem, že jeho samotná podstata již nemusí být vůbec patrná. Prostředky, které jsou na této úrovni k dispozici, již nejsou typu "volej tu a tu vzdálenou proceduru", a vůbec nepracují s čísly programů, procedur a verzí. Místo toho jde o lokální procedury, které vesměs přímo odpovídají jednotlivým vzdáleným procedurám (stylem 1:1), a také již nepotřebují dodržovat konvence o jediném vstupním a jediném výstupním parametru. Mají formu zdrojových knihoven, a mohou být přímo začleněny do zdrojových tvarů nejrůznějších aplikací, psaných ve vyšších programovacích jazycích (například v jazyku C). Vzhledem k tomu je pak tato nejvyšší úroveň určena pro méně náročné aplikační programování, které je ale možné prakticky i bez jakéhokoli tušení o existenci mechanismu RPC.