RPC (Remote Procedure Call)
What is RPC?
RPC (Remote Procedure Call) is a protocol that allows a program to execute a procedure (function) on a remote server as if it were a local function. This enables distributed computing where different services interact seamlessly over a network.
Unlike REST APIs, which are resource-based, RPC focuses on calling functions or procedures directly.
RPC Architecture and Workflow
Architecture Components
Client – Initiates the RPC request.
Stub (Client-Side Proxy) – Encodes the request and sends it over the network.
Transport Layer (Network) – Transfers the request to the remote system.
Stub (Server-Side Proxy) – Decodes the request.
Server – Executes the requested procedure and returns the response.
RPC Workflow
Client calls a function: A client calls a remote function just like a local one.
Marshalling (Serialization): The client stub serializes parameters.
Network Communication: The request is sent over the network.
Server Processing:
Server stub receives the request.
It deserializes (unmarshalls) the parameters.
The actual function is executed.
Response Transmission:
The server stub serializes the response and sends it back.
The client stub receives and deserializes the response.
The client receives the result as if it were a local function call.
Example: RPC API in gRPC (Google RPC with Protocol Buffers)
Let's build an RPC API using gRPC (a modern high-performance RPC framework developed by Google).
1. Define the RPC Service (Protocol Buffers)
We use Protocol Buffers (protobuf) to define the RPC methods and data structures.
// calculator.proto
syntax = "proto3";
service Calculator {
rpc Add (AddRequest) returns (AddResponse);
}
message AddRequest {
int32 a = 1;
int32 b = 2;
}
message AddResponse {
int32 result = 1;
}
2. Generate gRPC Code
After defining the .proto
file, use the gRPC compiler (protoc
) to generate client and server code in the desired programming language.
protoc --go_out=. --go-grpc_out=. calculator.proto
3. Implement the Server (Go)
The server implements the defined RPC methods.
package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "path/to/generated/calculatorpb"
)
type server struct {
pb.UnimplementedCalculatorServer
}
func (s *server) Add(ctx context.Context, req *pb.AddRequest) (*pb.AddResponse, error) {
result := req.A + req.B
return &pb.AddResponse{Result: result}, nil
}
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
pb.RegisterCalculatorServer(grpcServer, &server{})
log.Println("gRPC server running on port 50051")
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("Failed to serve: %v", err)
}
}
4. Implement the Client (Go)
The client makes an RPC call to the server.
package main
import (
"context"
"log"
"time"
"google.golang.org/grpc"
pb "path/to/generated/calculatorpb"
)
func main() {
conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
if err != nil {
log.Fatalf("Failed to connect: %v", err)
}
defer conn.Close()
client := pb.NewCalculatorClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
req := &pb.AddRequest{A: 10, B: 20}
res, err := client.Add(ctx, req)
if err != nil {
log.Fatalf("Error calling Add: %v", err)
}
log.Printf("Addition Result: %d", res.Result)
}
Types of RPC
Synchronous RPC – The client waits for a response before proceeding.
Asynchronous RPC – The client does not wait and continues execution, fetching the result later.
Streaming RPC – The client and server exchange multiple messages in a single RPC call (e.g., bidirectional streaming in gRPC).
Advantages of RPC
Simplicity – Calls appear as local function calls.
Performance – More efficient than REST over HTTP (especially with gRPC).
Streaming Support – Enables real-time communication.
Strongly Typed – Enforces structured communication with Protocol Buffers.
Disadvantages of RPC
Tightly Coupled – Client and server need shared interfaces.
Complex Debugging – More challenging than REST APIs.
Language Constraints – Requires language-specific bindings.
When to Use RPC?
Microservices Communication: Efficient for service-to-service calls.
Real-Time Applications: Streaming capabilities make it ideal for real-time systems.
High-Performance Systems: Faster and lightweight compared to REST.
Conclusion
RPC APIs provide a powerful way to enable distributed computing with minimal overhead. Modern implementations like gRPC improve efficiency, making it a great choice for microservices and high-performance applications. 🚀
Last updated
Was this helpful?