2.3.4. Remote Procedure Call

Volání služby serveru pomocí zprávy z klienta má obvykle charakter volání procedury, a tak se kód pro manipulaci se zprávami na klientovi a serveru odděluje a automaticky generuje, nápad zhruba kolem roku 1984.

Když se volá normální procedura, uloží se na stack parametry, procedura si je vyzvedne a něco udělá, vrátí výsledky. Když se volá služba na serveru, parametry se uloží do zprávy, server ji přijme a něco udělá, vrátí výsledky. RPC udělá lokální proceduru, která vezme parametry ze stacku, uloží je do zprávy, zavolá server, přijme výsledky a vrátí je volajícímu. A aby i programátoři serveru měli pohodu, udělá se to samé také na druhé straně - říká se tomu client a server stub, případně client stub a server skeleton.

Uložení parametrů do zprávy se říká marshalling, opačně zase unmarshalling. Závisí na typu parametrů, které se předávají.

S předáváním jsou ještě další záludnosti, které nejsou na první pohled zřejmé. Mezi ně patří:

Další problém je error handling. S tím moc chytristiky udělat nejde. Možné varianty selhání jsou známé, je prostě nutné počítat s tím, že RPC může selhat ještě pár jinými způsoby než normální call a ošetřit to v programu.

Při implementaci RPC je důležitá efektivita, stojí na ní celý systém. Kritická cesta při RPC - call stub, prepare msg buffer, marshall params, fill headers, call kernel send, context switch, copy stub buffer to kernel space, fill headers, set up interface - receive interrupt, check packet, find addressee, copy buffer to addressee, wake up addressee, context switch, unmarshall params, prepare stack, call server.

Co trvá dlouho - marshalling, buffer copying (při špatné implementaci header filling). Řeší se obvykle mapováním a scatter and gather network hardware (efektivní jen pro delší zprávy).

Stuby a skeletony je potřeba automaticky generovat. Jako vstup generátoru slouží definice hlaviček procedur, ty jazykové ale nejsou zpravidla dostatečně informativní, takže se definuje nějaký jazyk pro popis hlaviček procedur (IDL), podle kterého se pak jednak generují stuby a skeletony a jednak hlavičky procedur v nějakém programovacím jazyce.

2.3.4.1. Example: Spring Remote Procedure Call

Na právě popsaném principu běží například Spring, kde se procesy volají skrz doors. Při volání door se předává buffer, který může obsahovat data, identifikátor door, out of line data. Předávání je buď consume nebo copy, s jasnou sémantikou. Thread na straně klienta se pozastaví, na straně serveru se vybere thread z thread pool příslušejícího k door, který vykoná kód spojený s door. Interfaces jsou popsané v IDL, překládá se do client a server stubů, pod nimi jsou ještě subcontracts, ignore.

Pro marshalling Spring původně používal buffer fixní velikosti spojený s každým threadem, to se ale ukázalo špatné ze dvou důvodů. Za prvé, většina volání přenášela méně než 128 bajtů dat (90% pod 48 bajtů), a několikakilobajtový buffer byl pak zbytečně velký. Za druhé, buffery se rezervovaly staticky, čímž spotřebovávaly paměť. Jako řešení se udělal stream interface s metodami put_int, put_short, put_char, put_bulk, put_door_identifier, put_aligned (a odpovídajícími get metodami). Stream si by default alokuje buffer 128 bajtů, do kterého od konce ukládá structured data (door identifiers a out of line data) a od začátku unstructured data (všechno ostatní). Structured data se překládají, unstructured kopírují, při zaplnění se alokuje extra overflow buffer.