ESC
Type to search guides, tutorials, and reference documentation.
Verified by Garnet Grid

gRPC Architecture

Build high-performance microservice communication with gRPC. Covers Protocol Buffers, service definitions, streaming patterns, error handling, load balancing, and the patterns that make gRPC the standard for internal service communication.

gRPC is a high-performance RPC framework that uses Protocol Buffers for serialization and HTTP/2 for transport. Compared to REST/JSON, gRPC is 2-10x faster, generates type-safe client and server code, supports streaming, and produces payloads 3-5x smaller. It is the standard for internal microservice communication at Google, Netflix, and most cloud-native companies.


gRPC vs REST

REST/JSON:
  Transport: HTTP/1.1 (text-based)
  Serialization: JSON (text, human readable)
  Contract: OpenAPI/Swagger (optional, not enforced)
  Streaming: Not native (WebSocket is separate)
  Code generation: Optional
  
gRPC:
  Transport: HTTP/2 (binary, multiplexed)
  Serialization: Protocol Buffers (binary, compact)
  Contract: .proto file (required, enforced)
  Streaming: Native (unary, server, client, bidirectional)
  Code generation: Automatic (10+ languages)
  
Performance comparison:
  Payload size: gRPC 3-5x smaller than JSON
  Latency: gRPC 2-10x lower
  Throughput: gRPC 3-10x higher
  CPU usage: gRPC 30-50% lower

Protocol Buffers

// user_service.proto
syntax = "proto3";

package userservice;

// Service definition
service UserService {
  // Unary RPC
  rpc GetUser(GetUserRequest) returns (User);
  rpc CreateUser(CreateUserRequest) returns (User);
  rpc UpdateUser(UpdateUserRequest) returns (User);
  rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse);
  
  // Server streaming: stream many users
  rpc ListUsers(ListUsersRequest) returns (stream User);
  
  // Bidirectional streaming
  rpc SyncUsers(stream UserUpdate) returns (stream SyncResult);
}

// Message definitions
message User {
  string id = 1;
  string email = 2;
  string name = 3;
  UserPlan plan = 4;
  google.protobuf.Timestamp created_at = 5;
}

message GetUserRequest {
  string id = 1;
}

message CreateUserRequest {
  string email = 1;
  string name = 2;
  UserPlan plan = 3;
}

enum UserPlan {
  USER_PLAN_UNSPECIFIED = 0;
  USER_PLAN_FREE = 1;
  USER_PLAN_PRO = 2;
  USER_PLAN_ENTERPRISE = 3;
}

Server Implementation (Python)

import grpc
from concurrent import futures
import user_service_pb2 as pb2
import user_service_pb2_grpc as pb2_grpc

class UserServiceServicer(pb2_grpc.UserServiceServicer):
    def GetUser(self, request, context):
        user = self.db.get_user(request.id)
        
        if not user:
            context.set_code(grpc.StatusCode.NOT_FOUND)
            context.set_details(f"User {request.id} not found")
            return pb2.User()
        
        return pb2.User(
            id=user.id,
            email=user.email,
            name=user.name,
            plan=user.plan,
        )
    
    def ListUsers(self, request, context):
        """Server streaming: yield users one at a time."""
        users = self.db.list_users(
            page_size=request.page_size,
            filter=request.filter,
        )
        
        for user in users:
            yield pb2.User(
                id=user.id,
                email=user.email,
                name=user.name,
            )

# Start server
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
pb2_grpc.add_UserServiceServicer_to_server(UserServiceServicer(), server)
server.add_insecure_port("[::]:50051")
server.start()

Streaming Patterns

Unary (Request → Response):
  Client sends one message, server returns one message
  Like REST but with Protobuf
  Use for: CRUD operations

Server Streaming (Request → Stream of Responses):
  Client sends one message, server returns a stream
  Use for: List operations, real-time feeds, large result sets

Client Streaming (Stream of Requests → Response):
  Client sends a stream, server returns one message
  Use for: File upload, batch operations, sensor data

Bidirectional Streaming (Stream ↔ Stream):
  Both client and server send streams simultaneously
  Use for: Chat, real-time collaboration, game state sync

Anti-Patterns

Anti-PatternConsequenceFix
gRPC for public APIsBrowsers can’t call gRPC nativelyREST/GraphQL for public, gRPC for internal
No deadlines/timeoutsRequests hang foreverAlways set deadline on every call
Large messages (>4MB)gRPC has 4MB default limitStreaming for large payloads
No error codesCannot handle errors properlyUse gRPC status codes (NOT_FOUND, etc.)
Breaking proto changesClients crashNever remove fields, use reserved

gRPC is the right choice for internal service communication where performance matters. For public APIs that browsers consume, use REST or GraphQL with a gRPC gateway.

Jakub Dimitri Rezayev
Jakub Dimitri Rezayev
Founder & Chief Architect • Garnet Grid Consulting

Jakub holds an M.S. in Customer Intelligence & Analytics and a B.S. in Finance & Computer Science from Pace University. With deep expertise spanning D365 F&O, Azure, Power BI, and AI/ML systems, he architects enterprise solutions that bridge legacy systems and modern technology — and has led multi-million dollar ERP implementations for Fortune 500 supply chains.

View Full Profile →