encyklopedia.space

RPC – Remote Procedure Call (Zdalne Wywołanie Procedury)

Remote Procedure Call (skrót RPC) to model komunikacji w systemach rozproszonych, w którym program wywołuje procedurę lub metodę znajdującą się na innym komputerze tak, jakby była ona wywoływana lokalnie. Dzięki abstrakcji warstwy transportowej i szczegółów sieciowych, programista może skupić się na logice aplikacji, nie martwiąc się o ręczne kodowanie komunikatów sieciowych.

Historia

Pierwsze koncepcje RPC pojawiły się na początku lat 1970 w projektach ARPANET. W 1985 firma Sun Microsystems zaprezentowała protokół SUN‑RPC, który stał się podstawą wielu kolejnych implementacji. W kolejnych dekadach rozwijano różne warianty, m.in. XML‑RPC (1998), JSON‑RPC (2005) oraz bardziej nowoczesny gRPC (od 2015).

Podstawowe założenia

  • Ukrycie szczegółów sieciowych – wywołujący nie wie, czy procedura jest lokalna, czy zdalna.
  • Proceduralny interfejs – wywołanie przyjmuje argumenty i zwraca wynik, podobnie jak tradycyjna funkcja.
  • Transmisja danych – argumenty i wyniki są serializowane (marshalling) i deserializowane (unmarshalling) przed i po przesłaniu.
  • Model synchroniczny i asynchroniczny – klasyczne RPC działa synchronicznie (wywołujący czeka), ale istnieją także asynchroniczne warianty.

Architektura RPC

Typowy system RPC składa się z czterech głównych warstw:

  1. Client Stub (kod po stronie wywołującego) – konwertuje wywołanie procedury na komunikat sieciowy.
  2. Transport Layer – np. TCP, UDP lub HTTP.
  3. Server Stub (kod po stronie serwera) – odczytuje komunikat, wywołuje rzeczywistą procedurę i zwraca wynik.
  4. Procedura docelowa – faktyczna funkcja lub metoda implementowana w aplikacji serwera.

Identyfikatory języków i definicja interfejsu

Wiele implementacji RPC wykorzystuje IDL (Interface Definition Language) do opisania dostępnych metod, ich parametrów oraz typów zwracanych danych. Przykładowe IDL:

interface Kalkulator {
    int Dodaj(int a, int b);
    double Podziel(double licznik, double mianownik);
}
    

Popularne protokoły i biblioteki

Zastosowania

RPC jest wykorzystywane w wielu dziedzinach informatyki:

  • Usługi sieciowe – mikroserwisy komunikują się ze sobą przy pomocy gRPC lub JSON‑RPC.
  • Systemy operacyjne – np. DCE/RPC w systemach Windows i Unix.
  • Rozproszone bazy danych – wywołania operacji na węzłach klastra.
  • Systemy czasu rzeczywistego – asynchroniczne RPC w aplikacjach IoT.

Zalety i wady

ZaletyWady
  • Proste API – programista nie musi zajmować się niskopoziomową komunikacją.
  • Możliwość budowy rozproszonych aplikacji w stylu klient‑serwer.
  • Wsparcie wielu języków programowania dzięki wspólnym IDL.
  • Ukrycie warstwy sieciowej może prowadzić do nieefektywności (np. wysokie opóźnienia).
  • Trudności w debugowaniu – błędy pojawiają się na granicy sieci.
  • Problem z wersjonowaniem interfejsu przy zmianach API.

Porównanie z innymi modelami komunikacji

W przeciwieństwie do REST, które operuje na zasobach i wykorzystuje metody HTTP, RPC koncentruje się na wywoływaniu metod. Model ten jest bardziej zbliżony do tradycyjnego wywoływania funkcji, co może upraszczać projektowanie API, ale jednocześnie wprowadza silniejsze powiązanie między klientem a serwerem.

Przyszłość RPC

Obecnie największy rozgłos zdobywa gRPC ze względu na wydajność, wsparcie dla strumieniowania i integrację z ekosystemem Kubernetes. Wraz z rosnącą popularnością mikroserwisów oraz chmur obliczeniowych, model RPC pozostaje kluczowym elementem architektur rozproszonych.

Przykładowe użycie gRPC w języku Python

# plik: kalkulator.proto
syntax = "proto3";

service Kalkulator {
    rpc Dodaj (Para) returns (Wynik);
}

message Para {
    int32 a = 1;
    int32 b = 2;
}

message Wynik {
    int32 wynik = 1;
}
    

Po wygenerowaniu kodu przy pomocy protoc, serwer może wyglądać tak:

import grpc
from concurrent import futures
import kalkulator_pb2
import kalkulator_pb2_grpc

class KalkulatorServicer(kalkulator_pb2_grpc.KalkulatorServicer):
    def Dodaj(self, request, context):
        return kalkulator_pb2.Wynik(wynik=request.a + request.b)

server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
kalkulator_pb2_grpc.add_KalkulatorServicer_to_server(KalkulatorServicer(), server)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()
    

Bibliografia i dalsza lektura

  • W. Birrell i B. Nelson, Implementing Remote Procedure Calls, ACM SIGOPS Operating Systems Review, 1984.
  • J. Lloyd, gRPC: A High Performance, Open Source Universal RPC Framework, 2015.
  • Dokumentacja gRPC oraz Protocol Buffers.