Tehnologia RPC. Proceduri de la distanță: apelarea procedurilor de la distanță, definiție și caracteristici. Cum funcţionează asta

) Conceptul de apel de procedură de la distanță

Ideea unui apel de procedură de la distanță (RPC) este de a extinde mecanismul bine-cunoscut și înțeles pentru transferul de control și date într-un program care rulează pe o singură mașină pentru a transfera controlul și datele printr-o rețea. Instrumentele de apelare a procedurilor de la distanță sunt concepute pentru a facilita organizarea calculului distribuit. Cea mai mare eficiență a utilizării RPC este atinsă în acele aplicații în care există o comunicare interactivă între componentele de la distanță cu timpi de răspuns rapid și o cantitate relativ mică de date transferate. Astfel de aplicații sunt numite RPC-oriented.

Caracteristici apelurile de procedură locală sunt:

Asimetria, adică una dintre părțile care interacționează este inițiatorul; Sincronicitatea, adică executarea procedurii de apelare se oprește din momentul emiterii cererii și se reia numai după revenirea procedurii apelate.

Implementarea apelurilor de la distanță este mult mai complicată decât implementarea apelurilor de procedură locală. Pentru început, deoarece procedurile de apelare și apelare sunt executate pe mașini diferite, acestea au spații de adrese diferite, iar acest lucru creează probleme la transmiterea parametrilor și a rezultatelor, mai ales dacă mașinile nu sunt identice. Deoarece RPC nu se poate baza pe memoria partajată, aceasta înseamnă că parametrii RPC nu trebuie să conțină pointeri către locații de memorie non-stiva și că valorile parametrilor trebuie copiate de pe un computer pe altul. Următoarea diferență între RPC și un apel local este că folosește neapărat sistemul de comunicare de bază, dar acest lucru nu ar trebui să fie vizibil în mod explicit nici în definirea procedurilor, nici în procedurile în sine. Depărtarea introduce probleme suplimentare. Execuția programului apelant și a procedurii locale apelate pe aceeași mașină este implementată într-un singur proces. Dar implementarea RPC implică cel puțin două procese - câte unul pe fiecare mașină. Dacă una dintre ele se blochează, pot apărea următoarele situații: dacă procedura de apelare se blochează, procedurile apelate de la distanță vor deveni „orfane”, iar dacă procedurile de la distanță se blochează, procedurile de apelare vor deveni „părinți orfani”, așteptând în zadar un răspuns de la procedurile de la distanță.

În plus, există o serie de probleme asociate cu eterogenitatea limbajelor de programare și a mediilor de operare: structurile de date și structurile de apel de procedură acceptate în niciun limbaj de programare nu sunt acceptate în același mod în toate celelalte limbaje.

Acestea și alte probleme sunt rezolvate de tehnologia RPC răspândită, care stă la baza multor sisteme de operare distribuite.

Operații RPC de bază

Pentru a înțelege cum funcționează RPC, să luăm în considerare mai întâi efectuarea unui apel de procedură locală pe o mașină obișnuită care rulează offline. Să fie acesta, de exemplu, un apel de sistem

Count=read(fd,buf,nbytes);

unde fd este un număr întreg,
buf - matrice de caractere,
nbytes este un număr întreg.

Pentru a efectua un apel, procedura de apelare împinge parametrii în stiva la ordine inversă(Figura 3.1). După ce apelul de citire este executat, plasează valoarea returnată într-un registru, mută adresa de returnare și returnează controlul procedurii de apelare, care preia parametrii din stivă, returnându-l la starea initiala. Rețineți că în limbajul C, parametrii pot fi apelați fie prin referință (după nume), fie prin valoare (după valoare). În raport cu procedura apelată, parametrii de valoare sunt variabile locale inițializate. Procedura apelată le poate modifica fără a afecta valorile inițiale ale acestor variabile în procedura de apelare.

Dacă un pointer către o variabilă este transmis procedurii apelate, atunci modificarea valorii acestei variabile de către procedura apelată implică modificarea valorii acestei variabile pentru procedura apelată. Acest fapt este foarte semnificativ pentru RPC.

Există, de asemenea, un alt mecanism de transmitere a parametrilor care nu este utilizat în C. Se numește call-by-copy/restore, care necesită apelantului să copieze variabilele în stivă ca valori și apoi să le copieze înapoi după ce apelul este efectuat prin valorile originale ale procedurii de apelare.

Decizia despre ce mecanism de trecere a parametrilor să fie utilizat este luată de dezvoltatorii limbajului. Uneori depinde de tipul de date transferate. În C, de exemplu, numerele întregi și alte date scalare sunt întotdeauna transmise după valoare, iar tablourile sunt întotdeauna transmise prin referință.

Orez. 3.1. a) Stiva dinainte de executarea apelului de citire;
b) Stiva în timpul executării procedurii;
c) Stiva după revenirea la programul de apelare

Ideea din spatele RPC este de a face un apel de procedură la distanță să arate cât mai asemănător cu un apel de procedură locală. Cu alte cuvinte, faceți RPC transparent: procedura de apelare nu trebuie să știe că procedura apelată este pe o altă mașină și invers.

RPC realizează transparență în felul următor. Când procedura apelată este de fapt la distanță, o altă versiune a procedurii, numită client stub, este plasată în bibliotecă în locul procedurii locale. La fel ca procedura originală, stub-ul este apelat folosind o secvență de apelare (ca în Figura 3.1) și apare o întrerupere la accesarea nucleului. Numai că, spre deosebire de procedura inițială, nu plasează parametri în registre și nu solicită date de la kernel, în schimb generează un mesaj pentru a fi trimis către kernel-ul mașinii la distanță;

Etapele de execuție RPC

Interacțiunea componentelor software la efectuarea unui apel de procedură la distanță este ilustrată în Figura 3.2. După ce stub-ul clientului a fost apelat de către programul client, prima sa sarcină este să umple buffer-ul cu mesajul trimis. În unele sisteme, stub-ul clientului are un singur buffer cu lungime fixă ​​care este umplut de la bun început cu fiecare cerere nouă. În alte sisteme, buffer-ul de mesaje este un grup de buffere pentru câmpurile individuale de mesaje, dintre care unele sunt deja pline. Această metodă este potrivită în special pentru cazurile în care pachetul are un format format dintr-un număr mare de câmpuri, dar valorile multora dintre aceste câmpuri nu se schimbă de la apel la apel.

Parametrii trebuie apoi convertiți în formatul corespunzător și inserați în bufferul de mesaje. În acest moment, mesajul este gata pentru a fi trimis, astfel încât întreruperea apelului nucleului este executată.

Orez. 3.2. Apel de procedură de la distanță

Când nucleul capătă controlul, schimbă contextele, salvează registrele procesorului și harta de memorie (manere de pagină) și instalează o nouă hartă de memorie care va fi folosită pentru a rula în modul kernel. Deoarece nucleul și contextele utilizatorului sunt diferite, nucleul trebuie să copieze mesajul exact în propriul spațiu de adrese, astfel încât să-l poată accesa, să-și amintească adresa de destinație (și eventual alte câmpuri de antet) și să-l transmită interfeței de rețea. Acest lucru completează munca din partea clientului. Cronometrul de transmisie este pornit, iar nucleul poate fie să interogheze ciclic pentru un răspuns, fie să transmită controlul către planificator, care va selecta un alt proces de rulat. În primul caz, execuția interogării este accelerată, dar multiprogramarea este absentă.

Pe partea de server, biții de intrare sunt plasați de hardware-ul receptor fie în buffer-ul încorporat, fie în RAM. Când toate informațiile au fost primite, este generată o întrerupere. Managerul de întrerupere verifică corectitudinea pachetelor de date și determină la ce stub ar trebui trimis. Dacă niciunul dintre stub-uri nu așteaptă acest pachet, handler-ul trebuie fie să-l tamponeze, fie să-l arunce cu totul. Dacă există un talon în așteptare, mesajul este copiat pe acesta. În final, se efectuează o comutare de context, în urma căreia se restabilesc registrele și harta memoriei, luând valorile pe care le aveau în momentul în care stub-ul a efectuat apelul de recepție.

Acum, ștuțul serverului începe să funcționeze. Dezambalează parametrii și îi împinge în mod corespunzător pe stivă. Când totul este gata, se efectuează un apel către server. După executarea procedurii, serverul transmite rezultatele către client. Pentru a face acest lucru, efectuați toți pașii descriși mai sus, numai în ordine inversă.

Figura 3.3 arată secvența comenzilor care trebuie executate pentru fiecare apel RPC, iar Figura 3.4 arată ce procent din timpul total de execuție RPC este cheltuit pentru fiecare dintre cei 14 pași descriși. Cercetarea a fost efectuată pe un multiprocesor statie de lucru DEC Firefly și, deși prezența a cinci procesoare a afectat în mod necesar rezultatele măsurătorilor, histograma prezentată în figură oferă o idee generală a procesului de execuție RPC.

Orez. 3.3. Pași pentru a efectua o procedură RPC

Orez. 3.4. Distribuția timpului între 14 etape ale execuției RPC

1. Apelarea unui ciot

2. Pregătiți un tampon

3. Parametrii pachetului

4. Completați câmpul titlu

5. Calculați suma de control din mesaj

6. Întreruperea nucleului

7. Coada de pachete pentru execuție

8. Transmiterea unui mesaj către controler prin magistrala QBUS

9. Timp de transfer Rețele Ethernet

10. Primiți pachetul de la controler

11. Procedura de manipulare a întreruperii

12. Calcul suma de control

13. Schimbarea contextului în spațiul utilizatorului

14. Efectuarea unui server stub

Legătura dinamică

Să luăm în considerare modul în care clientul specifică locația serverului. O metodă de a rezolva această problemă este utilizarea directă adresa de rețea server în programul client. Dezavantajul acestei abordări este inflexibilitatea sa extremă: la mutarea unui server, la creșterea numărului de servere sau la schimbarea interfeței în toate acestea și multe alte cazuri, este necesar să se recompileze toate programele care au folosit o adresă de server codificată. Pentru a evita toate aceste probleme, unele sisteme distribuite folosesc ceea ce se numește legătură dinamică.

Punctul de plecare pentru legarea dinamică este definiția formală (specificația) a serverului. Specificația conține numele serverului de fișiere, numărul versiunii și o listă de proceduri de service furnizate de acest server clienților (Figura 3.5). Pentru fiecare procedură, este dată o descriere a parametrilor acesteia, indicând dacă este acest parametru intrare sau ieșire în raport cu serverul. Unii parametri pot fi atât de intrare cât și de ieșire - de exemplu, o matrice care este trimisă de client către server, modificată acolo și apoi returnată înapoi la client (operație de copiere/restaurare).

Orez. 3.5. Specificația serverului RPC

Specificația formală a serverului este utilizată ca intrare în programul generator de stub, care creează atât stub-uri client, cât și server. Acestea sunt apoi plasate în bibliotecile corespunzătoare. Când un program utilizator (client) apelează orice procedură definită în specificația serverului, procedura stub corespunzătoare este asociată cu codul binar al programului. De asemenea, atunci când un server este compilat, cioturile de server îi sunt asociate.

Când serverul pornește, prima sa acțiune este să-și transfere interfața serverului program special, numit liant Acest proces, cunoscut sub numele de proces de înregistrare a serverului, implică transmiterea de către server a numelui său, a numărului de versiune, a identificatorului unic și a descriptorului locației serverului. Descriptorul este independent de sistem și poate fi IP, Ethernet, X.500 , sau o altă adresă În plus, poate conține și alte informații, de exemplu legate de autentificare.

Când un client apelează una dintre procedurile de la distanță pentru prima dată, de exemplu, citire, stub-ul clientului vede că nu este încă conectat la server și trimite un mesaj programului de legătură cu o solicitare de a importa interfața dorită. versiunea serverului dorit. Dacă un astfel de server există, atunci Binder transmite descriptorul și identificatorul unic stub-ului clientului.

Când trimiteți un mesaj cu o solicitare, stub-ul clientului folosește un descriptor ca adresă. Mesajul conține parametri și un identificator unic pe care nucleul serverului îl folosește pentru a direcționa mesajul primit către serverul dorit, dacă există mai mulți dintre aceștia pe această mașină.

Această metodă de import/export de interfețe este foarte flexibilă. De exemplu, pot exista mai multe servere care acceptă aceeași interfață, iar clienții sunt distribuiți aleatoriu pe servere. În cadrul acestei metode, devine posibilă interogarea periodică a serverelor, analizarea performanței acestora și, în caz de defecțiune, oprire automată, ceea ce mărește toleranța generală la erori a sistemului. Această metodă poate suporta și autentificarea clientului. De exemplu, serverul poate determina că poate fi utilizat numai de clienți dintr-o anumită listă.

Cu toate acestea, legarea dinamică are dezavantaje, cum ar fi supraîncărcarea suplimentară (timp) pentru exportul și importul de interfețe. Amploarea acestor costuri poate fi semnificativă, deoarece multe procese client există pentru o perioadă scurtă de timp, iar de fiecare dată când procesul începe, procedura de import a interfeței trebuie efectuată din nou. În plus, în sistemele mari distribuite, programul de liant poate deveni un blocaj, iar crearea mai multor programe cu un scop similar crește, de asemenea, suprasarcina de creare și sincronizare a proceselor.

Semantica RPC în caz de eșecuri

În mod ideal, RPC ar trebui să funcționeze corect chiar și în cazul unor defecțiuni. Luați în considerare următoarele clase de eșec:

Clientul nu poate localiza serverul, de exemplu, dacă serverul dorit eșuează sau pentru că programul client a fost compilat cu mult timp în urmă și utilizat versiunea veche interfata serverului. În acest caz, ca răspuns la solicitarea clientului, se primește un mesaj care conține un cod de eroare. Solicitarea de la client către server a fost pierdută. Cea mai simplă soluție este prin anumit timp repeta cererea. Mesajul de răspuns de la server către client a fost pierdut. Această opțiune este mai complicată decât cea anterioară, deoarece unele proceduri nu sunt idempotente. O procedură idempotentă este o procedură a cărei cerere de execuție poate fi repetată de mai multe ori fără a modifica rezultatul. Un exemplu de astfel de procedură ar fi citirea unui fișier. Dar procedura de retragere a unei anumite sume dintr-un cont bancar nu este idempotentă, iar dacă răspunsul este pierdut, o solicitare repetată poate schimba semnificativ starea contului clientului. O soluție posibilă este de a face toate procedurile idempotente. Cu toate acestea, în practică, acest lucru nu este întotdeauna posibil, așa că poate fi utilizată o altă metodă - numerotarea secvențială a tuturor solicitărilor de către nucleul clientului. Nucleul serverului își amintește numărul celei mai recente solicitări de la fiecare client și, la primirea fiecărei cereri, analizează dacă această solicitare este primară sau repetată. Serverul s-a prăbușit după ce a primit cererea. Proprietatea idempotity este de asemenea importantă aici, dar, din păcate, abordarea cu numerotarea interogărilor nu poate fi aplicată. In acest caz conteaza

    Java RMI ca tip de apel de procedură de la distanță, independent de rețea, pașii principali de lucru cu acesta și scopul său. Comparație între programele Java distribuite și nedistribuite. Arhitectură Java RMI, stub și schelet, referință la distanță și straturi de transport.

    Pre-compilarea interogărilor SQL la locul de execuție. Folosind instrucțiunea prepareStatement. Utilizați sintaxa definiției apelului pentru a obține valoarea returnată a unei proceduri sau funcție. Crearea instrucțiunilor pentru prelevare la cerere.

    Scopul și schema de lucru. Compozitie si instalare. Specificația procedurii pachetului http.

    Procedurile și funcțiile pot fi definite ca unități de program închise care implementează un anumit algoritm. De fapt, o procedură sau o funcție este aproape un program.

    Configurare automată TCP/IP, configurare dinamică folosind BOOTP. Adrese IP de solicitare/răspuns, pierderea și formatarea mesajelor, fazele BOOTP. Protocolul DHCP este o extensie a protocolului BOOTP. Distribuirea și atribuirea adreselor IP.

    Am întâlnit deja conceptul de recursivitate: relațiile de recurență sunt destul de comune în expresiile matematice. Recursiunea în definiție constă în faptul că conceptul care se definește este definit prin acest concept însuși.

    1. Introducere 2 2. Prezentare generală a tehnologiei COM 2 2.1. Compoziția unui obiect COM 3 2.2. Interfețe 4 2.3. Proprietățile obiectelor COM 6 2.4. Servere COM 6 2.5. Mecanismul de repartizare 7

    Studiul esenței, principiului de funcționare și scopului principal al bazelor de date la distanță. Model telecomanda date (model server de fișiere). Tipuri de paralelism. Un declanșator este un mecanism de urmărire a evenimentelor speciale care sunt asociate cu starea bazei de date.

    Pachete metamodel, fapte și securitate. Modelul conceptual al clientului. Un exemplu de funcționare a unei arhitecturi distribuite. Complexitatea implementării.

    Conceptul dll. Să ne amintim procesul de programare în DOS. Convertirea textului sursă în cod mașină a implicat două procese: compilare și legare. În timpul conectării, nu numai declarațiile de funcții și proceduri, ci și codul lor complet au fost plasate în codul programului.

    Funcții pentru lucrul cu protocolul TCP/IP, Socket, Bind, ascultare și acceptare. Descriptor de fișier. Procesele de comunicare. Primirea datelor. Citirea de pe o priză. Scrieți la o priză. Închiderea prizei. Textul programului care creează un server Web în sistemul de operare QNX.

    Accesul utilizatorilor rețelei la mesajele electronice stocate pe server. Descrierea programului, autentificare simplă, autentificare APOP și AUTH. Implementare functii, manual de utilizare, algoritmi de operare program, interfata grafica.

    Principiul de funcționare al operatorilor principali ai limbajului de programare Turbo-Paskal: operator de atribuire, selecție de caz, salt necondiționat, buclă, captură, compus. Descrierea formală și apelul unei funcții și proceduri. Cerințe pentru lista parametrilor actuali.

    Principiul de funcționare și scopul servlet-urilor Java, importanța acestora în creșterea funcționalității serverelor Web și îmbunătățirea programării acestora, avantajele și dezavantajele utilizării. Modalități de a apela servlet-uri din browser și din pagină. Scrieți și citiți atributele sesiunii.

    Arhitectura sistemului de operare Windows NT. Structura sistemului de operare bazată pe microkernel. Subsisteme protejate ale Windows NT.

    Primitive de transmitere a mesajelor de bază în sistemele distribuite. Metode de adresare. Primitive blocante și neblocante. Primitive tamponate și non-tampon.

    Server de aplicații. Partea clientului.

    În urmă cu doi ani, AJAX era o noutate (și cuvântul AJAX în sine nu fusese încă inventat). Acum, aplicațiile web ale căror pagini sunt actualizate din mers sunt la ordinea zilei. Dimpotrivă: este greu de imaginat unele servicii fără AJAX.

    Sintaxă pentru descrierea și apelarea unei proceduri. Opțiuni. Un exemplu de descriere a procedurii și apel. Tipuri de parametri. Program.

Remote Procedure Call RPC Conceptul de Remote Procedure Call Ideea din spatele Remote Procedure Call (RPC) este de a extinde mecanismul bine-cunoscut și înțeles pentru transferul de control și date într-un program care rulează pe o singură mașină pentru a transfera controlul și datele printr-o rețea. Instrumentele de apel de la distanță sunt concepute pentru a facilita organizarea calculului distribuit Cea mai mare eficiență a utilizării RPC este atinsă în acele aplicații în care există o comunicare interactivă între componentele de la distanță cu timpi de răspuns scurti și o cantitate relativ mică de date transferate.

Astfel de aplicații sunt numite RPC-oriented. Trăsăturile caracteristice ale procedurilor locale de apelare sunt Asimetria, adică una dintre părțile care interacționează este inițiatorul Sincronicitatea, adică executarea procedurii de apelare se oprește din momentul emiterii cererii și se reia numai după revenirea din procedura apelată. Implementarea apelurilor la distanță este mult mai complicată decât implementarea apelurilor către procedurile locale.

Pentru început, deoarece procedurile de apelare și apelare sunt executate pe mașini diferite, acestea au spații de adrese diferite, iar acest lucru creează probleme la transmiterea parametrilor și a rezultatelor, mai ales dacă mașinile nu sunt identice, deoarece RPC nu se poate baza pe memoria partajată că parametrii RPC nu trebuie să conțină pointeri către locații de memorie care nu sunt stive și că valorile parametrilor ar trebui copiate de pe un computer pe altul.

Următoarea diferență între RPC și un apel local este că folosește neapărat sistemul de comunicare de bază, dar acest lucru nu ar trebui să fie vizibil în mod explicit nici în definirea procedurilor, nici în procedurile în sine. Depărtarea introduce probleme suplimentare. Execuția programului apelant și a procedurii locale apelate pe aceeași mașină este implementată în cadrul unui singur proces Dar implementarea RPC implică cel puțin două procese - câte unul în fiecare mașină.

În cazul în care una dintre ele se blochează, pot apărea următoarele situații: dacă procedura de apelare se blochează, procedurile apelate de la distanță vor deveni orfane, iar dacă procedurile de la distanță se blochează, procedurile de apelare vor deveni părinți orfani, care vor aștepta în zadar un răspuns. din procedurile de la distanță, există o serie de probleme asociate cu eterogenitatea limbajelor de programare și a mediilor de operare, structurile de date și structurile de apeluri de proceduri acceptate în niciun limbaj de programare nu sunt acceptate în același mod în toate celelalte. limbi.

Acestea și alte probleme sunt rezolvate de tehnologia RPC răspândită, care stă la baza multor sisteme de operare distribuite. Operații RPC de bază Pentru a înțelege cum funcționează RPC, să luăm în considerare mai întâi efectuarea unui apel de procedură local pe o mașină obișnuită care rulează autonom Să fie, de exemplu, numărul apelurilor de sistem read fd,buf,nbytes unde fd este un număr întreg, buf este un tablou. de caractere, nbytes este un număr întreg.

Pentru a efectua apelul, procedura de apelare împinge parametrii pe stivă în ordinea inversă a Figura 3.1. După ce apelul de citire este executat, plasează valoarea returnată într-un registru, mută adresa de returnare și returnează controlul la procedura de apelare, care scoate parametrii din stivă, revenind la starea sa inițială. Rețineți că în parametrii C poate fi apelat prin referință sau după nume sau după valoare. În raport cu procedura apelată, parametrii de valoare sunt variabile locale inițializate.

Procedura apelată le poate modifica fără a afecta valorile inițiale ale acestor variabile în procedura de apelare. Dacă un pointer către o variabilă este transmis procedurii apelate, atunci modificarea valorii acestei variabile prin procedura apelată implică modificarea valorii acestei variabile pentru procedura apelată. Acest fapt este foarte semnificativ pentru RPC. Există, de asemenea, un alt mecanism de transmitere a parametrilor care nu este utilizat în C. Se numește restaurare call-by-copy și implică ca programul apelant să copieze variabilele în stivă ca valori, iar apoi să le copieze înapoi după ce apelul este efectuat peste originalul. valorile procedurii de apelare.

Decizia despre ce mecanism de trecere a parametrilor să fie utilizat este luată de dezvoltatorii limbajului. Uneori, aceasta depinde de tipul de date transmise, de exemplu, numerele întregi și alte date scalare sunt transmise întotdeauna după valoare, iar tablourile sunt întotdeauna transmise prin referință.

Orez. 3.1. a Stiva înainte de executarea apelului de citire b Stiva în timpul execuției procedurii c Stiva după revenirea la programul apelant Ideea din spatele RPC este de a face ca un apel către o procedură de la distanță să arate cât mai asemănător cu un apel către un procedura locala. Cu alte cuvinte, pentru a face RPC transparent, procedura de apelare nu trebuie să știe că procedura apelată este pe o altă mașină și invers, RPC obține transparență în felul următor.

Când procedura apelată este de fapt la distanță, în loc de procedura locală, o altă versiune a procedurii, numită client stub, este plasată în bibliotecă. Similar cu procedura inițială, stub-ul este apelat folosind secvența de apelare ca în Figura 3.1 și apare o întrerupere la accesarea nucleului. Numai că, spre deosebire de procedura inițială, nu plasează parametri în registre și nu solicită date de la kernel, în schimb generează un mesaj pentru a fi trimis către kernel-ul mașinii la distanță; Etapele execuției RPC Interacțiunea componentelor software la efectuarea unui apel de procedură la distanță este ilustrată în Figura 3.2. După ce stub-ul clientului a fost apelat de către programul client, prima sa sarcină este să umple buffer-ul cu mesajul trimis.

În unele sisteme, stub-ul clientului are un singur buffer cu lungime fixă ​​care este umplut de la bun început cu fiecare cerere nouă. În alte sisteme, buffer-ul de mesaje este un grup de buffere pentru câmpurile individuale de mesaje, dintre care unele sunt deja pline.

Această metodă este potrivită în special pentru cazurile în care pachetul are un format format dintr-un număr mare de câmpuri, dar valorile multora dintre aceste câmpuri nu se schimbă de la apel la apel. Parametrii trebuie apoi convertiți în formatul corespunzător și inserați în bufferul de mesaje. În acest moment, mesajul este gata pentru a fi trimis, astfel încât întreruperea apelului de kernel este executată. Orez. 3.2. Apel de procedură de la distanță Când nucleul câștigă controlul, schimbă contextele, salvează registrele procesorului și mânerele paginilor hărți de memorie, setează hartă nouă memorie care va fi folosită pentru a rula în modul kernel. Deoarece nucleul și contextele utilizatorului sunt diferite, nucleul trebuie să copieze mesajul exact în propriul spațiu de adrese, astfel încât să-l poată accesa, să-și amintească adresa de destinație și eventual alte câmpuri de antet și trebuie să-l transmită interfeței de rețea.

Acest lucru completează munca din partea clientului.

Cronometrul de transmisie este pornit, iar nucleul poate fie să interogheze ciclic pentru un răspuns, fie să transmită controlul către planificator, care va selecta un alt proces de rulat. În primul caz, execuția interogării este accelerată, dar multiprogramarea este absentă. Pe partea de server, biții de intrare sunt plasați de hardware-ul de recepție fie în buffer-ul încorporat, fie în RAM Când toate informațiile au fost primite, este generată o întrerupere.

Handler-ul de întrerupere verifică datele pachetului pentru validitate și determină la care stub să-l transmită. Dacă niciun stub nu așteaptă pachetul, handler-ul de întrerupere trebuie fie să-l tamponeze, fie să-l renunțe complet. Dacă există un talon în așteptare, mesajul este copiat pe acesta. În final, se efectuează o comutare de context, în urma căreia se restabilesc registrele și harta memoriei, luând valorile pe care le aveau în momentul în care stub-ul a efectuat apelul de recepție.

Acum, ștuțul serverului începe să funcționeze. Dezambalează parametrii și îi împinge în mod corespunzător pe stivă. Când totul este gata, se efectuează un apel către server. După finalizarea procedurii, serverul transmite rezultatele către client Pentru a face acest lucru, toți pașii descriși mai sus sunt efectuate, doar în ordine inversă. Figura 3.3 arată secvența comenzilor care trebuie executate pentru fiecare apel RPC, iar Figura 3.4 arată ce procent din timpul total de execuție RPC este cheltuit pentru fiecare dintre cei 14 pași descriși.

Testele au fost efectuate pe o stație de lucru cu mai multe procesoare DEC Firefly și, în timp ce prezența a cinci procesoare a afectat în mod necesar rezultatele măsurătorilor, histograma prezentată în figură oferă o idee generală a procesului de execuție RPC. Orez. 3.3. Etapele procedurii RPC Fig. 3.4. Distribuția timpului între 14 etape ale execuției RPC 1. Apelarea unui stub 2. Pregătirea unui buffer 3. Parametrii pachetului 4. Completați câmpul antet 5. Calculați suma de control din mesaj 6. Întreruperea nucleului 7. Puneți pachetul în coadă pentru execuție 8. Transferați mesajul către controler prin intermediul magistralei QBUS 9. Timp de transfer prin rețeaua Ethernet 10. Primirea unui pachet de la controler 11. Procedura de gestionare a întreruperilor 12. Calculul sumei de control 13. Comutarea contextului în spațiul utilizator 14. Efectuarea unui stub de server Legarea dinamică Să luăm în considerare întrebarea cum specifică clientul locația serverului.

O metodă de a rezolva această problemă este utilizarea directă a adresei de rețea a serverului în programul client.

Dezavantajul acestei abordări este că este extrem de inflexibilă la mutarea serverului, la creșterea numărului de servere sau la schimbarea interfeței în toate acestea și în multe alte cazuri, este necesar să se recompileze toate programele care au folosit setarea hard a serverului; adresa Pentru a evita toate aceste probleme, în Unele sisteme distribuite folosesc ceea ce se numește legătură dinamică.

Punctul de plecare pentru legarea dinamică este definirea formală a specificației serverului. Specificația conține numele serverului de fișiere, numărul versiunii și o listă de proceduri de service furnizate de acest server clienților (Figura 3.5). Pentru fiecare procedură, este dată o descriere a parametrilor acesteia, indicând dacă acest parametru este de intrare sau de ieșire în raport cu serverul. Unii parametri pot fi atât de intrare cât și de ieșire - de exemplu, o matrice care este trimisă de client către server este modificată. acolo și apoi a revenit la operațiunea client copiere restaurare . Orez. 3.5. Specificația serverului RPC Specificația serverului formal este utilizată ca intrare în programul generator de stub, care creează atât stub-uri client, cât și server.

Acestea sunt apoi plasate în bibliotecile corespunzătoare. Când obicei program client apelează orice procedură definită în specificația serverului, procedura stub corespunzătoare este asociată cu codul binar al programului.

De asemenea, atunci când un server este compilat, cioturile de server îi sunt asociate. Când serverul pornește, prima sa acțiune este să-și transfere interfața serverului într-un program special numit binder. Acest proces, cunoscut sub numele de proces de înregistrare a serverului, implică transmiterea de către server a numelui său, a numărului de versiune, a identificatorului unic și a unui descriptor al locației serverului. Descriptorul este independent de sistem și poate fi un IP, Ethernet, X.500 sau ceva altă adresă.

În plus, poate conține și alte informații, de exemplu legate de autentificare. Când un client apelează una dintre procedurile de la distanță pentru prima dată, de exemplu, citire, stub-ul clientului vede că nu este încă conectat la server și trimite un mesaj programului de legătură cu o solicitare de importare a interfeței versiunea dorită a serverului dorit Dacă un astfel de server există, binder trimite descriptorul și identificatorul unic pentru stub-ul clientului.

Când trimiteți un mesaj cu o solicitare, stub-ul clientului folosește un descriptor ca adresă. Mesajul conține parametri și un identificator unic pe care nucleul serverului îl folosește pentru a direcționa mesajul primit către serverul dorit, dacă există mai mulți dintre aceștia pe această mașină. Această metodă de import și export de interfețe este foarte flexibilă. De exemplu, pot exista mai multe servere care acceptă aceeași interfață, iar clienții sunt distribuiți aleatoriu între servere.

În cadrul acestei metode, devine posibilă interogarea periodică a serverelor, analizarea performanței acestora și, în caz de defecțiune, oprirea automată, ceea ce crește toleranța generală la erori a sistemului. Această metodă poate suporta și autentificarea clientului. De exemplu, serverul poate determina că poate fi utilizat doar de clienți dintr-o listă specifică.

Amploarea acestor costuri poate fi semnificativă, deoarece multe procese client există pentru o perioadă scurtă de timp, iar de fiecare dată când procesul începe, procedura de import a interfeței trebuie efectuată din nou. În plus, în sistemele mari distribuite, programul de liant poate deveni un blocaj, iar crearea mai multor programe cu același scop crește, de asemenea, suprasarcina de creare și sincronizare a semanticii RPC în cazul unor defecțiuni. În mod ideal, RPC ar trebui să funcționeze corect în acest eveniment a eșecurilor.

Luați în considerare următoarele clase de eșec: 1. Clientul nu poate localiza serverul, de exemplu, dacă serverul dorit eșuează sau pentru că programul client a fost compilat cu mult timp în urmă și a folosit o versiune veche a interfeței serverului. În acest caz, ca răspuns la solicitarea clientului, se primește un mesaj care conține un cod de eroare. 2. Solicitarea de la client către server a fost pierdută. Cea mai simplă soluție este să repetați cererea după un anumit timp. 3. Mesajul de răspuns de la server către client este pierdut.

Această opțiune este mai complicată decât cea anterioară, deoarece unele proceduri nu sunt idempotente. O procedură idempotentă este o procedură a cărei cerere de execuție poate fi repetată de mai multe ori fără a modifica rezultatul. Un exemplu de astfel de procedură este citirea unui fișier, dar procedura de retragere a unei anumite sume dintr-un cont bancar nu este idempotentă, iar dacă răspunsul este pierdut, o solicitare repetată poate schimba semnificativ starea contului clientului.

O soluție posibilă este de a face toate procedurile idempotente. Cu toate acestea, în practică, acest lucru nu este întotdeauna posibil, așa că poate fi utilizată o altă metodă - numerotarea secvențială a tuturor solicitărilor de către nucleul clientului. Nucleul serverului își amintește numărul celei mai recente solicitări de la fiecare client și, la primirea fiecărei cereri, analizează dacă această solicitare este primară sau repetată. 4. Serverul s-a prăbușit după primirea cererii Proprietatea idempotity este de asemenea importantă aici, dar, din păcate, abordarea cu numerotarea cererii nu poate fi aplicată.

În acest caz, contează când a avut loc defecțiunea - înainte sau după operație. Dar nucleul clientului nu poate recunoaște aceste situații, știe doar că timpul de răspuns a expirat. Există trei abordări ale acestei probleme: Așteptați până când serverul repornește și încercați din nou operația. Această abordare vă asigură că RPC-ul este finalizat cel puțin o dată și, eventual, mai multe. Raportați imediat eroarea către aplicație.

Această abordare asigură că RPC este executat cel mult o dată. A treia abordare nu garantează nimic. Când serverul eșuează, clientului nu i se oferă suport. RPC poate fie să nu fie executat deloc, fie poate fi executat de mai multe ori. În orice caz, această metodă este foarte ușor de implementat. Niciuna dintre aceste abordări nu este foarte atractivă Iar opțiunea ideală, care ar garanta exact o execuție RPC, în cazul general nu poate fi implementată din motive de principiu.

Să fie, de exemplu, o operație de la distanță imprimarea unui text, care include încărcarea tamponului imprimantei și setarea unui bit într-un registru de control al imprimantei, ca urmare a pornirii imprimantei după ce bitul de control este setat. Momentul eșecului determină în întregime procedura de recuperare, dar clientul nu poate afla despre momentul eșecului.

Pe scurt, posibilitatea unui accident de server schimbă radical natura RPC și reflectă în mod clar diferența dintre un sistem centralizat și unul distribuit. În primul caz, o blocare a serverului duce la o blocare a clientului, iar recuperarea este imposibilă. În al doilea caz, este posibil și necesar să se efectueze acțiuni de recuperare a sistemului. 1. Clientul s-a blocat după trimiterea cererii. În acest caz, calculele sunt efectuate pe rezultate la care nimeni nu se așteaptă. Astfel de calcule se numesc calcule orfane. Prezența orfanilor poate provoca diverse probleme timp pierdut CPU, blocarea resurselor, înlocuirea răspunsului la cererea curentă cu un răspuns la o solicitare care a fost emisă de computerul client înainte ca sistemul să fie repornit.

Cum să te descurci cu orfanii? Luați în considerare 4 solutii posibile. Distrugere. Înainte ca stub-ul clientului să trimită un mesaj RPC, acesta face o notă în jurnal care indică ce va face în continuare. Jurnalul este stocat pe disc sau altă memorie tolerantă la erori.

După accident, sistemul este repornit, jurnalul este analizat și orfanii sunt eliminați. Dezavantajele acestei abordări includ, în primul rând, supraîncărcarea crescută asociată cu scrierea fiecărui RPC pe disc și, în al doilea rând, posibila ineficiență din cauza apariției orfanilor din a doua generație generate de apelurile RPC emise de orfanii din prima generație. Reîncarnarea În acest caz, toate problemele sunt rezolvate fără a utiliza înregistrarea pe disc. Metoda constă în împărțirea timpului în perioade numerotate secvenţial. Când clientul repornește, acesta transmite un mesaj către toate mașinile pentru a anunța începutul unei noi perioade.

După primirea acestui mesaj, toate calculele de la distanță sunt eliminate. Desigur, dacă rețeaua este segmentată, atunci unii orfani pot supraviețui. Reîncarnarea soft este similară cu cazul precedent, cu excepția faptului că nu toate calculele șterse sunt găsite și distruse, ci doar calculele clientului de repornire. Expirare Fiecare cerere are o perioadă standard de timp T în care trebuie finalizată.

Dacă cererea nu este finalizată în timpul alocat, se alocă un cuantum suplimentar. Deși acest lucru necesită muncă suplimentară, dar dacă după un accident de client, serverul așteaptă un interval T înainte de a reporni clientul, atunci toți orfanii sunt neapărat distruși în practică, nici una dintre aceste abordări nu este de dorit, distrugerea orfanilor poate înrăutăți situația. De exemplu, să presupunem că un orfan a blocat unul sau mai multe fișiere de bază de date.

Dacă orfanul este distrus brusc, atunci aceste încuietori vor rămâne, în plus, orfanii distruși pot rămâne în picioare în diferite cozi de sistem, în viitor pot provoca execuția de noi procese etc.

Ce vom face cu materialul primit:

Dacă acest material ți-a fost util, îl poți salva pe pagina ta de pe rețelele sociale:

Programele care comunică printr-o rețea au nevoie de un mecanism de comunicare. La nivelul inferior, la sosirea pachetelor, un semnal este trimis și procesat de un program de procesare a semnalului de rețea. La nivel superior funcționează mecanismul de întâlnire, adoptat în limbajul Ada. NFS folosește un mecanism de apel de procedură la distanță (RPC) în care clientul comunică cu serverul (vezi Figura 1). Conform acestui proces, clientul apelează mai întâi o procedură care trimite o cerere către server. La sosirea unui pachet de solicitare, serverul își apelează procedura de deschidere, efectuează serviciul solicitat, trimite un răspuns și controlul revine clientului.

Interfața RPC poate fi gândită ca fiind formată din trei straturi:

Nivelul superior este complet transparent. Un program la acest nivel poate conține, de exemplu, un apel la procedura rnusers(), care returnează numărul de utilizatori de pe mașina de la distanță. Nu trebuie să știți despre utilizarea mecanismului RPC, deoarece efectuați apelul în program.

Nivelul de mijloc este destinat celor mai comune aplicații. Apelurile RPC la acest nivel sunt gestionate de subrutinele registerrpc() și callrpc(): registerrpc() primește cod la nivelul întregului sistem, iar callrpc() execută un apel de procedură la distanță. Apelul rnusers() este implementat folosind aceste două rutine.

Nivelul inferior este utilizat pentru sarcini mai complexe care modifică valorile implicite ale parametrilor procedurii. La acest nivel, puteți manipula în mod explicit socket-urile utilizate pentru transmiterea mesajelor RPC.

De obicei, ar trebui să utilizați nivel superiorși evitați utilizarea nivelurilor mai mici decât dacă este absolut necesar.

Deși în acest tutorial luăm în considerare doar interfața C, apelurile la procedurile de la distanță pot fi făcute din orice limbă. Funcționarea mecanismului RPC pentru organizarea comunicării între procese pe diferite mașini nu este diferită de funcționarea sa pe o singură mașină.

RPC (Remote Procedure Call) este o interfață între utilizatori la distanțăși anumite programe gazdă care sunt lansate la cererea acestor utilizatori. Serviciul RPC al oricărei gazde, de regulă, oferă clienților un set de programe. Fiecare dintre aceste programe constă, la rândul său, din una sau mai multe proceduri de la distanță. De exemplu, un serviciu de la distanță sistem de fișiere NFS, care este construit pe apeluri RPC, poate consta doar din două programe: de exemplu, un program interacționează cu programe de nivel înalt. interfețe cu utilizatorul, iar celălalt cu funcții I/O de nivel scăzut.

Fiecare apel de procedură la distanță implică două părți: clientul activ, care trimite cererea de apel de procedură către server și serverul, care trimite răspunsul către client.

Nota. Vă rugăm să rețineți că termenii „client” și „server” în acest caz se referă la o anumită tranzacție software(proces sau program) poate funcționa atât ca client, cât și ca server. De exemplu, un program care oferă un serviciu de procedură la distanță poate fi în același timp un client pentru lucrul cu un sistem de fișiere din rețea.

Protocolul RPC este construit pe un model de apel de procedură la distanță, similar cu mecanismul de apel de procedură local. Când apelați o procedură locală, plasați argumente într-o locație specifică din memorie, pe stivă sau în variabilele de mediu și transferați controlul procesului către adresa specifica. Odată ce lucrarea este finalizată, citiți rezultatele la o anumită adresă și continuați cu procesul.

Când lucrați cu o procedură de la distanță, principala diferență este că apelul funcției de la distanță este gestionat de două procese: un proces client și un proces server.

Procesul client trimite un mesaj către server, care include parametrii procedurii apelate și așteaptă un mesaj de răspuns cu rezultatele muncii sale. Când se primește un răspuns, rezultatul este citit și procesul continuă. Pe partea de server, procesul de gestionare a apelurilor este în stare de așteptare, iar când sosește un mesaj, citește parametrii procedurii, îl execută, trimite un răspuns și devine în stare de așteptare pentru următorul apel.

Protocolul RPC nu impune nicio cerință privind comunicațiile suplimentare între procese și nu necesită sincronizarea funcțiilor efectuate, adică apelurile pot fi asincrone și independente reciproc, astfel încât clientul să poată efectua alte proceduri în așteptarea unui răspuns. Serverul RPC poate aloca un proces separat sau o mașină virtuală pentru fiecare funcție, prin urmare, fără a aștepta finalizarea solicitărilor anterioare, le poate accepta imediat pe următoarele.

Cu toate acestea, există câteva diferențe importante între apelurile de procedură locale și cele de la distanță:

1. Gestionarea erorilor.În orice caz, clientul ar trebui să primească notificarea erorilor care apar la apelarea procedurilor de la distanță pe server sau rețea.

2. Variabile globale. Deoarece serverul nu are acces la spațiul de adrese al clientului, apelurile de procedură la distanță nu pot utiliza parametri ascunși sub formă de variabile globale.

3. Performanţă. Viteza de executare a procedurilor de la distanță este de obicei cu unul sau două ordine de mărime mai mică decât viteza de executare a procedurilor locale similare.

4. Autentificare. Deoarece apelurile de procedură de la distanță au loc prin rețea, trebuie utilizate mecanisme de autentificare a clientului.

Principiile construcției protocolului.

Protocolul RPC poate folosi mai multe protocoale de transport diferite. Responsabilitățile protocolului RPC sunt doar de a furniza standarde și de a interpreta transmiterea mesajelor. Fiabilitatea și fiabilitatea transmiterii mesajelor este asigurată în întregime de stratul de transport.

Cu toate acestea, RPC poate controla selecția și unele funcții ale protocolului de transport. Ca exemplu de interacțiune dintre RPC și protocolul de transport, luați în considerare procedura de atribuire a unui port RPC pentru ca un proces de aplicație să ruleze prin RPC - Portmapper.

Această funcție atribuie dinamic (la cerere) o conexiune RPC unui anumit port. Funcţie Portmapper este folosit destul de des deoarece setul de porturi de transport rezervat RPC este limitat, iar numărul de procese care pot rula potențial simultan este foarte mare. Portmapper, de exemplu, este apelat atunci când se selectează porturile pentru interacțiunea dintre client și serverul de sistem NFS.

Serviciu Portmapper folosește un mecanism de difuzare a mesajelor RPC către un anumit port - III. Clientul trimite un mesaj de difuzare a cererii de port către acest port serviciu specific RPC. Serviciu Portmapper procesează mesajul fiscal, determină adresa serviciului RPC local și trimite un răspuns clientului. Serviciul RPC Portmapper poate funcționa atât cu protocoalele TCP, cât și cu UDP.

RPC poate funcționa cu diverse protocoale de transport, dar nu le dublează niciodată funcțiile, adică dacă RPC rulează peste TCP, toate preocupările legate de fiabilitatea și validitatea conexiunii RPC sunt atribuite TCP. Cu toate acestea, dacă RPC este instalat peste UDP, acesta poate oferi funcționalitate nativă suplimentară de livrare a mesajelor.

Nota. Sarcinile aplicației pot considera protocolul RPC ca o procedură specifică pentru apelarea unei funcții prin rețeaua JSR (Jump Subroutine Instruction).

Pentru ca protocolul RPC să funcționeze, trebuie îndeplinite următoarele condiții:

1. Identificarea unică a tuturor procedurilor apelate de la distanță pe o anumită gazdă. Cererile RPC conțin trei câmpuri de identificare - numărul programului de la distanță (serviciu), numărul versiunii programului la distanță și numărul procedurii de la distanță a programului specificat. Numărul programului este atribuit de producătorul serviciului, numărul procedurii indică funcția specifică a acestui serviciu

2. Identificarea versiunii protocolului RPC. Mesajele RPC conțin un câmp pentru versiunea protocolului RPC. Este folosit pentru a coordona formatele parametrilor trecuți atunci când clientul lucrează cu diferite versiuni de RPC.

3. Furnizarea de mecanisme pentru autentificarea clientului pe server. Protocolul RPC oferă o procedură de autentificare a clientului la serviciu și, dacă este necesar, de fiecare dată când se face o cerere sau se trimite un răspuns către client. În plus, RPC permite utilizarea diferitelor mecanisme de securitate suplimentare.

RPC poate folosi patru tipuri de mecanisme de autentificare:

AUTH_NULL - nu este necesară autentificarea

AUTH_UNIX - autentificare conform standardului UNIX

AUTH_SHORT - Autentificare standard UNIX cu propria sa structură de codificare

AUTH_DES - autentificare conform standardului DES

4. Identificarea mesajelor de răspuns la solicitările corespunzătoare. Mesajele de răspuns RPC conțin identificatorul cererii din care au fost construite. Acest identificator poate fi numit identificatorul tranzacției de apel RPC. Acest mecanism este necesar în special atunci când se lucrează în modul asincron și când se efectuează o secvență de mai multe apeluri RPC.

5. Identificarea erorilor de protocol. Toate erorile de rețea sau server au identificatori unici, prin care fiecare dintre participanții la conexiune poate determina cauza defecțiunii.

Structuri de mesaje de protocol

Când se trimit mesaje RPC printr-un protocol de transport, mai multe mesaje RPC pot fi localizate într-un singur pachet de transport. Pentru a separa un mesaj de altul, se folosește un marcator de înregistrare (RM - Record Marker). Fiecare mesaj RPC este „marcat” cu exact un RM.

Un mesaj RPC poate consta din mai multe fragmente. Fiecare fragment este format din patru octeți de antet și date (de la 0 la 2**31-1). Primul bit al antetului indică dacă fragmentul este ultimul, iar restul de 31 de biți indică lungimea pachetului de date.

Structura RPC este descrisă formal în limbajul de descriere și reprezentare a formatelor de date - XDR cu completări privind descrierea procedurilor. Ați putea spune chiar că limbajul de descriere RPC este o extensie a XDR, completată de lucrul cu proceduri.

Structura pachetului RPC arată astfel:

struct rpc_msg (

unsigned int xid;

comutator de unire (msg_type mtype) (

call_body cbody;

răspuns body rbody;

unde xid este identificatorul tranzacției curente, call_body este pachetul de solicitare, reply_body este pachetul de răspuns. Structura cererii arată cam așa:

struct call body (

unsigned int rpcvers;

unsigned int prog;

unsigned int vers;

unsigned int proc;

opac_auth cred;

opaque_auth verf;

/* parametrii procedurii */

Structura de răspuns (reply_body) poate conține fie o structură de eroare (caz în care conține codul de eroare), fie o structură de procesare a cererii cu succes (caz în care conține datele returnate).

Interfață software de nivel înalt.

Utilizarea subrutinelor într-un program este o modalitate tradițională de a structura o sarcină și de a o face mai clară. Rutinele utilizate cel mai frecvent sunt colectate în biblioteci unde pot fi folosite de diverse programe. În acest caz despre care vorbim despre un apel local (local), adică atât obiectele care apelează, cât și obiectele apelate funcționează în cadrul aceluiași program pe același computer.

În cazul unui apel de la distanță, un proces care rulează pe un computer pornește un proces computer la distanță(adică rulează de fapt codul de procedură pe computerul de la distanță). Evident, un apel de procedură la distanță diferă semnificativ de unul local tradițional, dar din punctul de vedere al unui programator, astfel de diferențe sunt practic absente, adică arhitectura unui apel de procedură la distanță vă permite să simulați un apel de procedură locală.

Cu toate acestea, dacă în cazul unui apel local programul trece parametrii procedurii apelate și primește rezultatul muncii prin stiva sau zonele de memorie partajată, atunci în cazul unui apel la distanță transferul parametrilor se transformă în transmiterea de o cerere prin rețea, iar rezultatul lucrării este în răspunsul primit.

Această abordare este o posibilă bază pentru crearea de aplicații distribuite, și deși multe sisteme moderne nu utilizați acest mecanism, conceptele și termenii de bază sunt păstrați în multe cazuri. Când descriem mecanismul RPC, vom numi în mod tradițional procesul de apelare client, iar procesul de la distanță care implementează procedura un server.

Un apel de procedură de la distanță implică următorii pași:

1. Programul client efectuează un apel local către o procedură numită stub. În acest caz, clientul „pare” că apelând stub-ul, el apelează de fapt procedura serverului. Într-adevăr, clientul trece parametrii necesari stub-ului și returnează rezultatul. Cu toate acestea, lucrurile nu sunt chiar așa cum își imaginează clientul. Sarcina stub-ului este să accepte argumentele destinate procedurii de la distanță, eventual să le convertească într-un format standard și să formuleze o cerere de rețea. Împachetarea argumentelor și crearea cererii de rețea se numește marshalling.

2. Cererea de rețea este transmisă prin rețea către sistemul de la distanță. Pentru a face acest lucru, stub-ul folosește apeluri adecvate, de exemplu, cele discutate în secțiunile anterioare. Rețineți că pot fi utilizate diverse protocoale de transport și nu numai familia TCP/IP.

3. Pe gazda la distanță, totul se întâmplă în ordine inversă. Stub-ul serverului ascultă o solicitare și, la primire, preia parametrii - argumentele apelului de procedură. Unmarshalling poate implica transformări necesare (de exemplu, modificări ale ordinii octeților).

4. Stub-ul efectuează un apel către procedura serverului real căreia îi este adresată cererea clientului, trecându-i argumentele primite prin rețea.

5. După finalizarea procedurii, controlul revine în stub-ul serverului, trecându-i parametrii necesari. La fel ca ciotul clientului; Stub-ul serverului convertește valorile returnate de procedură, generând un mesaj de răspuns al rețelei care este transmis prin rețea către sistemul de la care a venit cererea.

6. sistem de operare transmite mesajul primit stub-ului clientului, care, după transformarea necesară, transmite valorile (care sunt valorile returnate de procedura de la distanță) clientului, care tratează acest lucru ca pe o întoarcere normală din procedură.

Astfel, din punctul de vedere al clientului, efectuează un apel către o procedură de la distanță ca și pentru una locală. Același lucru se poate spune despre server: o procedură este apelată într-un mod standard, un anumit obiect (server stub) apelează o procedură locală și primește valorile returnate de acesta. Clientul tratează stub-ul ca pe o procedură de server apelabilă, iar serverul tratează propriul stub ca pe un client.

Astfel, stub-urile formează nucleul sistemului RPC, responsabil pentru toate aspectele generării și transmiterii mesajelor între client și serverul de la distanță (procedură), deși atât clientul, cât și serverul cred că apelurile au loc local. Acesta este conceptul de bază al RPC - pentru a ascunde complet natura distribuită (de rețea) a interacțiunii în codul stub. Avantajele acestei abordări sunt evidente: atât clientul, cât și serverul sunt independente de implementarea rețelei, ambele operează într-un anumit nivel distribuit. mașină virtuală, iar apelurile de procedură au o interfață standard.

Trecerea parametrilor

Transmiterea parametrilor de valoare nu cauzează dificultăți deosebite. În acest caz, stub-ul clientului plasează valoarea parametrului în cererea de rețea, eventual efectuând conversii la forma standard (de exemplu, inversând ordinea octeților). Situația este mult mai complicată cu trecerea de pointeri, când parametrul reprezintă adresa datelor, și nu valoarea acesteia. Transmiterea adresei în cerere nu are sens, deoarece procedura de la distanță este executată într-un spațiu de adrese complet diferit. Cel mai mult solutie simpla, folosit în RPC, este de a interzice clienților să treacă alți parametri decât valorii, deși acest lucru, desigur, impune restricții serioase.

Legare

Înainte ca un client să poată apela o procedură la distanță, aceasta trebuie să fie asociată cu un sistem la distanță care găzduiește serverul necesar. Astfel, sarcina obligatorie se împarte în două:

Găsirea unei gazde la distanță cu serverul necesar

Găsirea procesului de server necesar pe o anumită gazdă

Pentru a găsi gazda pot fi folosite diverse abordări. O posibilă opțiune este crearea unui fel de director centralizat în care gazdele își fac publicitate serverelor și în care clientul, dacă dorește, poate selecta adresa gazdă și procedura care sunt potrivite pentru el.

Fiecare procedură RPC este identificată în mod unic printr-un număr de program și de procedură. Numărul programului identifică un grup de proceduri la distanță, fiecare având propriul număr. Fiecărui program i se atribuie, de asemenea, un număr de versiune, astfel încât, dacă faceți modificări minore programului (de exemplu, adăugarea unei proceduri), nu este nevoie să-i schimbați numărul. De obicei, mai multe proceduri similare din punct de vedere funcțional sunt implementate într-un singur modul software, care, atunci când este lansat, devine serverul acestor proceduri și care este identificat prin numărul programului.

Astfel, atunci când un client dorește să apeleze o procedură de la distanță, trebuie să cunoască programul, versiunea și numerele de procedură care furnizează serviciul necesar.

Pentru a transmite o solicitare, clientul trebuie să cunoască și adresa rețelei gazdă și numărul portului asociat programului server care oferă procedurile necesare. Pentru aceasta este folosit demonul portmap(IM) (numit rpcbind(IM) pe unele sisteme). Daemonul rulează pe gazda care furnizează serviciul de procedură la distanță și utilizează un număr de port binecunoscut. Când un proces de server este inițializat, acesta își înregistrează procedurile și numerele de port în portmap(IM). Acum, când un client trebuie să cunoască numărul portului pentru a apela o anumită procedură, acesta trimite o solicitare către serverul portmap(IM), care, la rândul său, fie returnează numărul portului, fie redirecționează cererea direct către serverul de procedură la distanță și, după executând-o, returnează un răspuns clientului. În orice caz, dacă procedura necesară există, clientul primește numărul portului procedurii de la serverul portmap(IM), iar cererile suplimentare pot fi făcute direct pe acest port.

Gestionarea situațiilor speciale (excepție)

Gestionarea excepțiilor la apelarea procedurilor locale nu este deosebit de problematică. UNIX oferă procesare pentru erori de proces, cum ar fi împărțirea la zero, accesul la o zonă de memorie nevalidă etc. În cazul unui apel de procedură la distanță, probabilitatea unor situații de eroare crește. Pe lângă erorile de server și stub, sunt adăugate erori asociate, de exemplu, cu primirea unui mesaj de rețea eronat.

De exemplu, când se utilizează UDP ca protocol de transport, mesajele sunt retransmise după un anumit timeout. O eroare este returnată clientului dacă, după un anumit număr de încercări, nu a fost primit un răspuns de la server. În cazul în care se utilizează protocolul TCP, o eroare este returnată clientului dacă serverul a închis conexiunea TCP.

Semantica apelurilor

Apelarea unei proceduri locale duce fără ambiguitate la executarea acesteia, după care controlul revine la programul principal. Situația este diferită atunci când apelați o procedură de la distanță. Este imposibil să se determine când exact va fi efectuată procedura, dacă va fi efectuată deloc și, dacă da, de câte ori? De exemplu, dacă cererea este primită de sistemul de la distanță după ce programul server s-a prăbușit, procedura nu va fi executată deloc. Dacă clientul, atunci când nu primește un răspuns după o anumită perioadă de timp (timeout), retrimite cererea, atunci poate apărea o situație când răspunsul este deja transmis prin rețea, iar cererea repetată este din nou acceptată pentru procesare de la distanță. procedură. În acest caz, procedura va fi efectuată de mai multe ori.

Astfel, execuția unei proceduri la distanță poate fi caracterizată prin următoarea semantică:

- O dată și doar o dată. Acest comportament (în unele cazuri cel mai de dorit) este dificil de solicitat din cauza posibilelor blocări ale serverului.

- Timp maxim. Aceasta înseamnă că procedura fie nu a fost efectuată deloc, fie a fost efectuată o singură dată. O declarație similară poate fi făcută atunci când se primește o eroare în loc de un răspuns normal.

- Măcar o dată. Procedura a fost probabil efectuată o dată, dar este posibil mai multe. Pentru funcţionare normală intr-o astfel de situatie, procedura la distanta trebuie sa aiba proprietatea de idempotenta (din engleza idemponent). Această proprietate este deținută de o procedură a cărei execuție repetată nu provoacă modificări cumulate. De exemplu, citirea unui fișier este idempotent, dar adăugarea de text într-un fișier nu este.

Prezentarea datelor

Când clientul și serverul rulează pe același sistem pe același computer, nu există probleme de incompatibilitate a datelor. Atât pentru client, cât și pentru server, datele în formă binară sunt reprezentate în același mod. În cazul unui apel la distanță, problema este complicată de faptul că clientul și serverul pot rula pe sisteme cu arhitecturi diferite, având reprezentări de date diferite (de exemplu, reprezentarea în virgulă mobilă, ordinea octeților etc.)

Majoritatea implementărilor sistemului RPC definesc o reprezentare standard a datelor la care trebuie convertite toate valorile transmise în cereri și răspunsuri.

De exemplu, formatul de prezentare a datelor în RPC de la Sun Microsystems este următorul:

Ordinea octetilor - Cel mai semnificativ - ultimul

Reprezentare în virgulă mobilă - IEEE

Reprezentarea caracterelor - ASCII

Din punct de vedere al funcționalității, sistemul RPC ocupă un loc intermediar între stratul de aplicație și stratul de transport. Conform modelului OSI, această poziție corespunde straturilor de prezentare și sesiune. Astfel, RPC este teoretic independent de implementarea rețelei, în special, a protocoalelor de rețea de nivel transport.

Implementările software ale sistemului, de regulă, acceptă unul sau două protocoale. De exemplu, sistemul RPC dezvoltat de Sun Microsystems acceptă transmiterea mesajelor folosind protocoalele TCP și UDP. Alegerea unui protocol sau altuia depinde de cerințele aplicației. Alegerea protocolului UDP este justificată pentru aplicațiile care au următoarele caracteristici:

Procedurile numite sunt idempotente

Dimensiunea argumentelor transmise și a rezultatului returnat este mai mică decât dimensiunea pachetului UDP - 8 KB.

Serverul oferă lucru cu câteva sute de clienți. Deoarece atunci când lucrează cu protocoale TCP, serverul este forțat să mențină o conexiune cu fiecare dintre clienții activi, aceasta ocupă o parte semnificativă a resurselor sale. Protocolul UDP consumă mai puțin resurse în acest sens

Pe de altă parte, TCP asigură operarea eficientă a aplicațiilor cu următoarele caracteristici:

Aplicația necesită un protocol de transfer fiabil

Procedurile numite nu sunt identice

Dimensiunea argumentelor sau a rezultatului returnat depășește 8 KB

Alegerea protocolului este de obicei lăsată la latitudinea clientului, iar sistemul organizează generarea și transmiterea mesajelor în moduri diferite. Astfel, atunci când se utilizează protocolul TCP, pentru care datele transmise sunt un flux de octeți, este necesar să se separe mesajele unul de celălalt. Pentru aceasta, de exemplu, se folosește protocolul de marcare a înregistrărilor descris în RFC1057 „RPC: Remote Procedure Call Protocol specification version 2”, în care un număr întreg de 32 de biți este plasat la începutul fiecărui mesaj, definind dimensiunea mesajului în octeți.

Situația este diferită cu semantica apelului. De exemplu, dacă RPC este efectuat folosind un protocol de transport nefiabil (UDP), sistemul retransmite mesajul la intervale scurte (timeouts). Dacă aplicația client nu primește un răspuns, atunci putem spune cu încredere că procedura a fost finalizată zero sau număr mai mare dată. Dacă se primește un răspuns, cererea poate concluziona că procedura a fost executată cel puțin o dată. Când se utilizează un protocol de transport de încredere (TCP), dacă se primește un răspuns, se poate spune că procedura a fost efectuată o singură dată. Dacă nu se primește un răspuns, este imposibil să spunem cu siguranță că procedura nu a fost finalizată3.

Cum funcţionează asta?

În esență, sistemul RPC în sine este încorporat în programul client și în programul server. Este bine că atunci când dezvoltați aplicații distribuite, nu trebuie să vă aprofundați în detaliile protocolului RPC sau procesării mesajelor programului. Sistemul presupune existența unui mediu de dezvoltare adecvat, care simplifică foarte mult viața creatorilor de aplicații software. Unul dintre punctele cheie în RPC este că dezvoltarea unei aplicații distribuite începe cu definirea unei interfețe obiect - o descriere formală a funcțiilor serverului, scrisă într-un limbaj special. Pe baza acestei interfețe, stub-urile client și server sunt apoi generate automat. Singurul lucru pe care trebuie să-l faceți după aceasta este să scrieți codul real pentru procedură.

Ca exemplu, luați în considerare RPC de la Sun Microsystems. Sistemul este format din trei părți principale:

Rpcgen(1) este un compilator RPC care, pe baza descrierii interfeței procedurii de la distanță, generează stub-uri client și server sub formă de programe C.

Biblioteca XDR (eXternal Data Representation), care conține funcții pentru conversia diferitelor tipuri de date într-o formă independentă de mașină, care permite schimbul de informații între sisteme eterogene.

O bibliotecă de module care asigură funcționarea sistemului în ansamblu.

Să ne uităm la un exemplu de aplicație simplă de înregistrare a evenimentelor distribuite. Când clientul pornește, apelează o procedură de la distanță pentru a scrie un mesaj în fișierul jurnal al computerului la distanță.

Pentru a face acest lucru, va trebui să creați cel puțin trei fișiere: specificația interfețelor procedurilor de la distanță log.x (în limbajul de descriere a interfeței), textul propriu-zis al procedurilor de la distanță log.c și textul principalului client program main () - client.c (în limbajul C).

Compilatorul rpcgen(l) creează trei fișiere pe baza specificației log.x: textul stub-urilor client și server în C (log clnt.c și log svc.c) și fișierul de descriere log.h, utilizat de ambele stub-uri .

Deci, să ne uităm la codurile sursă ale programelor.

Acest fișier specifică parametrii de înregistrare ai procedurii de la distanță - numere de program, versiune și procedură și, de asemenea, definește interfața de apel - argumente de intrare și valori returnate. Astfel, este definită o procedură RLOG care ia ca argument un șir (care va fi scris în jurnal), iar valoarea returnată indică în mod standard succesul sau eșecul operației ordonate.

programul LOG_PROG (

versiunea LOG_VER (

int RLOG(șir) = 1;

) = 0x31234567;

Compilatorul rpcgen(l) creează un fișier antet log.h, unde, în special, sunt definite procedurile:

log.h

* Vă rugăm să nu editați acest fișier.

* A fost generat folosind rpcgen.

#ifndef _LOG_H_RPCGEN

#define_LOG_H_RPCGEN

#include

/* Numărul programului*/

#define LOG_PROG ((nesemnat lung) (0x31234567))

#define LOG_VER ((nesemnat lung) (1)) /*Numărul versiunii*/

#define RLOG ((nesemnat lung) (1)) /*Numărul procedurii*/

extern int *rlog_l () ;

/*Procedura internă - nu trebuie să o folosim*/ extern int log_prog_l_freeresult();

#endif /* !_LOG_H_RPCGEN */

Să ne uităm la acest fișier cu atenție. Compilatorul traduce numele RLOG definit în fișierul de descriere a interfeței în rlog_1, înlocuind caracterele mari cu litere mici și adăugând numărul versiunii programului cu un caracter de subliniere. Tipul de returnare s-a schimbat de la int la int*. Aceasta este regula - RPC vă permite să transmiteți și să primiți doar adresele parametrilor declarați la descrierea interfeței. Aceeași regulă se aplică șirului transmis ca argument. Deși nu apare din fișierul print.h, adresa șirului este de fapt transmisă ca argument către rlog_l().

Pe lângă fișierul antet, compilatorul rpcgen(l) produce module client stub și server stub. În esență, textul acestor fișiere conține tot codul pentru apelul de la distanță.

Server stub este programul principal care se ocupă de toate interacțiunile de rețea cu clientul (mai precis, cu stub-ul său). Pentru a efectua operația, stub-ul serverului efectuează un apel de funcție local, al cărui text trebuie scris:

log.c

#include

#include

#include

#include „log.h”

int *rlog_1 (char **arg)

/*Valoarea de returnare trebuie definită ca static*/

rezultat static int;

int fd; /*Descriptor de fișier jurnal*/

/*0deschideți fișierul jurnal (creați-l dacă nu există), dacă nu reușește, returnați rezultatul codului de eroare == 1.*/

dacă ((fd=open("./server .log",

O_CREAT | O_RDWR | O_APPEND))< 0) return (&result);

len = strlen(*arg);

dacă (scrie(fd, *arg, strlen(*arg)) != len)

return(&rezultat); /*Întoarce rezultatul - rezultatul adresei*/

Stub-ul client acceptă argumentul transmis procedurii de la distanță, face conversiile necesare, emite o cerere către serverul portmap(1M), comunică cu serverul procedurii de la distanță și, în final, transmite valoarea returnată clientului. Pentru client, un apel către o procedură de la distanță se reduce la un apel către un stub și nu este diferit de un apel local obișnuit.

client.c

#include

#include „log.h”

main(int argc, char *argv)

char *server, *mystring, *clnttime;

dacă (argc != 2) (

fprintf(stderr, „Format apel: %s Adresa_gazdă\n”,

/*Obțineți descriptorul clientului. În caz de eșec, vă vom informa despre

imposibilitatea stabilirii unei conexiuni cu serverul */

if ((c1 = clnt_create(server,

LOG_PROG, LOG_VER, „udp”)) == NULL) (

clnt_pcreateerror(server);

/*Alocați un buffer pentru linie*/

mystring = (char *)malloc(100);

/*Determină ora evenimentului*/

bintime = timp ((time_t *) NULL);

clnttime = ctime(&bintime);

sprintf (mystring, "%s - Clientul a pornit", clnttime);

/*Trimite un mesaj pentru jurnal - ora la care clientul a început să lucreze. Dacă nu reușim, vom raporta o eroare*/

if ((rezultat = rlog_l(&mystring, cl)) == NULL) (

fprintf(stderr, „eroare2\n”);

clnt_perror(cl, server);

/*În caz de defecțiune pe computerul de la distanță, vom raporta o eroare*/

dacă (*rezultat !=0)

fprintf(stderr, „Eroare de înregistrare\n”);

/*0eliberează mânerul*/

cint distruge(cl);

Stub-ul client log_clnt.c este compilat cu modulul client.c pentru a produce un program client executabil.

cc -o rlog client.c log_clnt.c -Insl

Serverul stub log_svc.c și procedura log.c sunt compilate pentru a produce un program server executabil.

cc -o logger log_svc.c log.c -Insl

Acum, pe un server gazdă.nowhere.ru, trebuie să începeți un proces de server:

Apoi, când rulați clientul rlog pe o altă mașină, serverul va adăuga o intrare corespunzătoare în fișierul jurnal.

Diagrama de funcționare a RPC în acest caz este prezentată în Fig. 1. Modulele interacționează după cum urmează:

1. Când începe procesul de server, acesta creează un socket UDP și leagă orice port local la acel socket. Apoi, serverul apelează funcția de bibliotecă svc_register(3N) pentru a înregistra numerele și versiunile programului. Pentru a face acest lucru, funcția apelează procesul portmap(IM) și transmite valorile necesare. Serverul portmap(IM) este de obicei pornit când sistemul este inițializat și se leagă la un port binecunoscut. Acum portmap(3N) știe numărul portului pentru programul și versiunea noastră. Serverul așteaptă să primească cererea. Rețineți că toate acțiunile descrise sunt efectuate de un server stub creat de compilatorul rpcgen(IM).

2. Când pornește programul rlog, primul lucru pe care îl face este să apeleze funcția de bibliotecă clnt_create(3N), oferindu-i adresa sistemului de la distanță, numerele de program și versiune și protocolul de transport. Funcția trimite o solicitare către serverul portmap(IM) al serverului de sistem la distanță.nowhere.m și obține numărul portului de la distanță pentru serverul de jurnal.

3. Clientul apelează procedura rlog_1() definită în stub-ul clientului și transferă controlul către stub. Aceasta, la rândul său, generează o cerere (conversia argumentelor în format XDR) sub forma unui pachet UDP și o trimite la portul de la distanță primit de la serverul portmap (IM). Apoi așteaptă un răspuns pentru ceva timp și, dacă nu este primit, retrimite cererea. În circumstanțe favorabile, cererea este acceptată de serverul de înregistrare (modul server stub). Stub-ul determină ce funcție a fost apelată (prin numărul procedurii) și apelează funcția rlog_1() a modulului log.c. După ce controlul revine la stub, acesta din urmă convertește valoarea returnată de funcția rlog_1() în format XDR și generează un răspuns tot sub forma unui pachet UDP. După primirea răspunsului, stub-ul clientului extrage valoarea returnată, o transformă și o returnează programului gazdă al clientului.


Scopul acestui articol este de a discuta terminologia. Articolul nu este despre cum și de ce, ci doar despre utilizarea terminologiei. Articolul reflectă opinia autorului și nu se pretinde a fi științific.

Introducere

Daca lucrezi in programare sisteme distribuite sau în integrarea sistemelor, atunci majoritatea celor prezentate aici nu sunt noi pentru tine.

Problema apare atunci când există oameni care folosesc tehnologii diferite, și când acești oameni încep discuție tehnică. În acest caz, neînțelegeri reciproce apar adesea din cauza terminologiei. Aici voi încerca să adun terminologiile folosite în diferite contexte.

Terminologie

Nu există o terminologie și o clasificare clară în acest domeniu. Terminologia folosită mai jos este o reflectare a modelului autorului, adică este strict subiectivă. Orice critica si orice discutie sunt binevenite.

Am împărțit terminologia în trei zone: RPC (Remote Procedure Call), Messaging și REST. Aceste zone au rădăcini istorice.

RPC

RPC tehnologii - cele mai vechi tehnologii. Cei mai proeminenți reprezentanți ai RPC sunt - CORBAŞi DCOM.

În acele vremuri, era în principal necesar să se conecteze sistemele într-un mod rapid și relativ fiabil rețele locale. Ideea principală RPC era despre a face apelarea sistemelor la distanță la fel ca funcțiile de apel în cadrul unui program. Întreaga mecanică a apelurilor de la distanță a fost ascunsă de programator. Cel puțin au încercat să o ascundă. În multe cazuri, programatorii au fost forțați să lucreze la un nivel mai profund, unde au apărut termenii de marshaling ( triaj) Și dezmembrarea(cum este asta în rusă?), ceea ce însemna în esență serializare. Apelurile de funcții normale din cadrul proceselor au fost gestionate la capătul apelantului Proxy, iar pe partea sistemului care îndeplinește funcția, în Dispecer. În mod ideal, nici sistemul de apelare, nici sistemul de procesare nu s-au ocupat de complexitatea transferului de date între sisteme. Toate aceste subtilități au fost concentrate în pachetul Proxy - Dispatcher, al cărui cod a fost generat automat.

Deci nu vei observa, nu ar trebui să observi, nicio diferență între a suna funcţie localăși apelarea unei funcții de la distanță.
Acum există un fel de renaștere RPC, cei mai importanți reprezentanți ai căruia sunt: ​​Google ProtoBuf, Thrift, Avro.

Mesaje

De-a lungul timpului, s-a dovedit că încercarea de a proteja programatorul de faptul că funcția apelată încă diferă de cea locală nu a condus la rezultatul dorit. Detaliile de implementare și diferențele fundamentale dintre sistemele distribuite au fost prea mari pentru a fi rezolvate folosind codul proxy generat automat. Treptat, s-a înțeles că faptul că sistemele sunt conectate printr-un mediu nefiabil, lent și cu viteză redusă trebuie să fie reflectat în mod explicit în codul programului.

Au apărut tehnologii servicii web. Am început să vorbim ABC: Adresă, Obligatoriu, Contract. Nu este în întregime clar de ce au apărut contractele, care sunt în esență Plicuri pentru argumente de intrare. Contractele complică adesea modelul general, mai degrabă decât să-l simplifice. Dar... nu contează.

Acum programatorul a creat în mod explicit serviciu(Serviciu) sau client(Client) apelarea serviciului. Serviciul a constat dintr-un set operațiuni (Operațiunea), dintre care fiecare a luat la intrare cerere(Cerere) și a emis răspuns(Răspuns). Client în mod explicit trimis(Trimis), serviciul primit în mod explicit ( Primi) și i-a răspuns (Trimis), trimițând răspunsul. Clientul a primit un răspuns și apelul s-a încheiat.

La fel ca în RPC, existau un Proxy și un Dispatcher care rulau undeva. Și ca și înainte, codul lor a fost generat automat și programatorul nu a trebuit să-l înțeleagă. Cu excepția cazului în care clientul a folosit în mod explicit clase de la Proxy.

Solicitările și răspunsurile sunt convertite în mod explicit într-un format destinat transmiterii prin cablu. Cel mai adesea aceasta este o matrice de octeți. Transformarea se numește SerializareŞi Deserializareași uneori se ascunde în codul proxy.
Punctul culminant al mesajelor s-a manifestat în apariția paradigmei ESB (Autobuz de servicii pentru întreprinderi). Nimeni nu poate articula cu adevărat ce este, dar toată lumea este de acord că datele se deplasează prin ESB sub formă de mesaje.

ODIHNĂ

În lupta constantă cu complexitatea codului, programatorii au făcut următorul pas și au creat ODIHNĂ.

Principiul principal al REST este că operațiunile cu funcții sunt limitate brusc și au lăsat doar un set de operații CRUD: Creare - Citire - Actualizare - Ștergere. În acest model, toate operațiile sunt întotdeauna aplicate unor date. Operațiunile disponibile în CRUD sunt suficiente pentru majoritatea aplicațiilor. Deoarece tehnologiile REST în majoritatea cazurilor implică utilizarea protocolului HTTP, comenzile CRUD au fost reflectate în comenzi. HTTP (Post - Obţine - Pune - Şterge) . Se spune în mod constant că REST nu este neapărat legat de HTTP. Dar, în practică, reflectarea semnăturilor operațiunilor în sintaxa comenzilor HTTP este utilizată pe scară largă. De exemplu, apelarea funcției

EntityAddress ReadEntityAddress(șir param1, șir param2)

Exprimat astfel:

GET: entityAddress?param1=value1¶m2=value2

Concluzie

Înainte de a începe o discuție despre sisteme distribuite sau integrare, definiți terminologia. Dacă Proxy va însemna întotdeauna același lucru în contexte diferite, atunci cererea, de exemplu, va însemna puțin în termeni RPC, iar marshalling-ul va provoca confuzie atunci când discutăm despre tehnologiile REST.

Scopul acestui articol este de a discuta terminologia. Articolul nu este despre cum și de ce, ci doar despre utilizarea terminologiei. Articolul reflectă opinia autorului și nu se pretinde a fi științific.

Introducere

Daca lucrezi in programare sisteme distribuite sau în integrarea sistemelor, atunci majoritatea celor prezentate aici nu sunt noi pentru tine.

Problema vine atunci când se întâlnesc oameni care folosesc diferite tehnologii și când acești oameni încep să aibă conversații tehnice. În acest caz, neînțelegeri reciproce apar adesea din cauza terminologiei. Aici voi încerca să adun terminologiile folosite în diferite contexte.

Terminologie

Nu există o terminologie și o clasificare clară în acest domeniu. Terminologia folosită mai jos este o reflectare a modelului autorului, adică este strict subiectivă. Orice critica si orice discutie sunt binevenite.

Am împărțit terminologia în trei zone: RPC (Remote Procedure Call), Messaging și REST. Aceste zone au rădăcini istorice.

RPC

RPC tehnologii - cele mai vechi tehnologii. Cei mai proeminenți reprezentanți ai RPC sunt - CORBAŞi DCOM.

În acele vremuri, sistemele trebuiau în mare parte conectate prin rețele locale rapide și relativ fiabile. Ideea principală din spatele RPC a fost de a face apelarea sistemelor la distanță la fel ca funcțiile de apel în cadrul unui program. Întreaga mecanică a apelurilor de la distanță a fost ascunsă de programator. Măcar au încercat să o ascundă. În multe cazuri, programatorii au fost forțați să lucreze la un nivel mai profund, unde au apărut termenii de marshaling ( triaj) Și dezmembrarea(cum este asta în rusă?), ceea ce însemna în esență serializare. Apelurile de funcții normale din cadrul proceselor au fost gestionate la capătul apelantului Proxy, iar pe partea sistemului care îndeplinește funcția, în Dispecer. În mod ideal, nici sistemul de apelare, nici sistemul de procesare nu s-au ocupat de complexitatea transferului de date între sisteme. Toate aceste subtilități au fost concentrate în pachetul Proxy - Dispatcher, al cărui cod a fost generat automat.

Deci nu veți observa, nu ar trebui să observați, nicio diferență între apelarea unei funcții locale și apelarea unei funcții la distanță.
Acum există un fel de renaștere RPC, cei mai importanți reprezentanți ai căruia sunt: ​​Google ProtoBuf, Thrift, Avro.

Mesaje

De-a lungul timpului, s-a dovedit că încercarea de a proteja programatorul de faptul că funcția apelată încă diferă de cea locală nu a condus la rezultatul dorit. Detaliile de implementare și diferențele fundamentale dintre sistemele distribuite au fost prea mari pentru a fi rezolvate folosind codul proxy generat automat. Treptat, s-a înțeles că faptul că sistemele sunt conectate printr-un mediu nefiabil, lent și cu viteză redusă trebuie să fie reflectat în mod explicit în codul programului.

Au apărut tehnologii servicii web. Am început să vorbim ABC: Adresă, Obligatoriu, Contract. Nu este în întregime clar de ce au apărut contractele, care sunt în esență Plicuri pentru argumente de intrare. Contractele complică adesea modelul general, mai degrabă decât să-l simplifice. Dar... nu contează.

Acum programatorul a creat în mod explicit serviciu(Serviciu) sau client(Client) apelarea serviciului. Serviciul a constat dintr-un set operațiuni (Operațiunea), dintre care fiecare a luat la intrare cerere(Cerere) și a emis răspuns(Răspuns). Client în mod explicit trimis(Trimis), serviciul primit în mod explicit ( Primi) și i-a răspuns (Trimis), trimițând răspunsul. Clientul a primit un răspuns și apelul s-a încheiat.

La fel ca în RPC, existau un Proxy și un Dispatcher care rulau undeva. Și ca și înainte, codul lor a fost generat automat și programatorul nu a trebuit să-l înțeleagă. Cu excepția cazului în care clientul a folosit în mod explicit clase de la Proxy.

Solicitările și răspunsurile sunt convertite în mod explicit într-un format destinat transmiterii prin cablu. Cel mai adesea aceasta este o matrice de octeți. Transformarea se numește SerializareŞi Deserializareași uneori se ascunde în codul proxy.
Punctul culminant al mesajelor s-a manifestat în apariția paradigmei ESB (Autobuz de servicii pentru întreprinderi). Nimeni nu poate articula cu adevărat ce este, dar toată lumea este de acord că datele se deplasează prin ESB sub formă de mesaje.

ODIHNĂ

În lupta constantă cu complexitatea codului, programatorii au făcut următorul pas și au creat ODIHNĂ.

Principiul principal al REST este că operațiunile cu funcții sunt limitate brusc și au lăsat doar un set de operații CRUD: Creare - Citire - Actualizare - Ștergere. În acest model, toate operațiile sunt întotdeauna aplicate unor date. Operațiunile disponibile în CRUD sunt suficiente pentru majoritatea aplicațiilor. Deoarece tehnologiile REST în majoritatea cazurilor implică utilizarea protocolului HTTP, comenzile CRUD au fost reflectate în comenzi. HTTP (Post - Obţine - Pune - Şterge) . Se spune în mod constant că REST nu este neapărat legat de HTTP. Dar, în practică, reflectarea semnăturilor operațiunilor în sintaxa comenzilor HTTP este utilizată pe scară largă. De exemplu, apelarea funcției

EntityAddress ReadEntityAddress(șir param1, șir param2)

Exprimat astfel:

GET: entityAddress?param1=value1¶m2=value2

Concluzie

Înainte de a începe o discuție despre sisteme distribuite sau integrare, definiți terminologia. Dacă Proxy va însemna întotdeauna același lucru în contexte diferite, atunci cererea, de exemplu, va însemna puțin în termeni RPC, iar marshalling-ul va provoca confuzie atunci când discutăm despre tehnologiile REST.