正在加载,请稍候…

Microservices Communication: REST, gRPC, and Message Queues

Choose the right communication pattern for microservices. Compare synchronous REST and gRPC with asynchronous message queues, learn service discovery, and handle failures.

Microservices Communication Patterns

Synchronous vs Asynchronous

Synchronous (REST/gRPC):
  + Simple request/response
  + Immediate feedback
  - Tight coupling (caller waits)
  Use for: User-facing queries, real-time data needs

Asynchronous (Message Queue):
  + Loose coupling
  + Better fault isolation
  - Eventual consistency
  Use for: Commands, notifications, data sync

gRPC Schema

syntax = "proto3";
service UserService {
  rpc GetUser(GetUserRequest) returns (UserResponse);
  rpc ListUsers(ListUsersRequest) returns (stream UserResponse);
}

message GetUserRequest { string id = 1; }
message UserResponse {
  string id = 1;
  string email = 2;
  string name = 3;
}

Message Queue Patterns

Command Pattern (one-to-one)

// Order service sends command to inventory
await messageQueue.send('inventory.reserve', {
  orderId: order.id,
  items: order.items,
}, { messageId: generateId() }); // idempotency key

// Inventory service processes command
consumer.subscribe('inventory.reserve', async (msg) => {
  if (await processedMessages.has(msg.messageId)) return; // Already handled
  await inventoryService.reserve(msg.payload.items);
  await processedMessages.add(msg.messageId);
  await messageQueue.send('inventory.reserved', { orderId: msg.payload.orderId });
});

Event Pattern (one-to-many)

// User service publishes event
await eventBus.publish('user.registered', { userId: user.id, email: user.email });

// Multiple services subscribe independently
eventBus.subscribe('user.registered', async (e) => emailService.sendWelcome(e.email));
eventBus.subscribe('user.registered', async (e) => analytics.track('signup', e));

Circuit Breaker

class CircuitBreaker {
  private failures = 0;
  private state: 'closed' | 'open' | 'half-open' = 'closed';

  async execute<T>(fn: () => Promise<T>): Promise<T> {
    if (this.state === 'open') throw new Error('Circuit breaker is open');
    try {
      const result = await fn();
      if (this.state === 'half-open') this.reset();
      return result;
    } catch (err) {
      this.failures++;
      if (this.failures >= 5) this.state = 'open';
      throw err;
    }
  }

  private reset() { this.failures = 0; this.state = 'closed'; }
}

Saga Pattern (Distributed Transactions)

Order Placed
  -> Payment Charged
  -> Inventory Reserved
  -> Shipping Scheduled
  -> Order Confirmed

If Shipping Fails:
  -> Inventory Released (compensating transaction)
  -> Payment Refunded (compensating transaction)
  -> Order Failed

Start with a monolith, extract services when you have clear domain boundaries.