← 返回资讯
陈默
AI 行业分析师
已审核

微服务通信模式对比:我们踩过的坑和最终方案

我们的系统从单体拆分成 30+ 微服务后,通信问题层出不穷。

微服务通信模式对比:我们踩过的坑和最终方案

微服务通信模式对比:我们踩过的坑和最终方案

我们的系统从单体拆分成 30+ 微服务后,通信问题层出不穷。

经过两年的迭代,终于找到了适合我们的通信模式。

问题背景

拆分后的痛点

CODE
服务 A 调用服务 B 超时
服务 C 发布消息,服务 D 没收到
服务 E 和 F 循环依赖
服务 G 挂了,整个系统雪崩

系统规模

| 指标 | 数值 |

|------|------|

| 微服务数量 | 30+ |

| 日均请求量 | 5000 万 |

| 服务间调用 | 2 亿次/天 |

| 消息队列消息 | 1 亿条/天 |

通信模式对比

模式 1:同步 HTTP/REST

JAVASCRIPT
// 服务 A 调用服务 B
async function getUserOrders(userId) {
  const user = await fetch(`http://user-service/users/${userId}`);
  const orders = await fetch(`http://order-service/users/${userId}/orders`);
  
  return {
    user: await user.json(),
    orders: await orders.json()
  };
}

优点:

缺点:

踩过的坑:

JAVASCRIPT
// ❌ 问题:级联超时
// 服务 A → 服务 B → 服务 C → 服务 D
// 每个服务 1 秒超时,总超时 4 秒
// 用户等了 4 秒,体验很差

// ❌ 问题:雪崩效应
// 服务 D 变慢 → 服务 C 等待 → 服务 B 等待 → 服务 A 等待
// 所有服务都被拖垮

模式 2:gRPC

PROTOBUF
// user.proto
syntax = "proto3";

service UserService {
  rpc GetUser (GetUserRequest) returns (User);
  rpc ListUsers (ListUsersRequest) returns (ListUsersResponse);
}

message GetUserRequest {
  int64 user_id = 1;
}

message User {
  int64 id = 1;
  string name = 2;
  string email = 3;
}
JAVASCRIPT
// 客户端
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

const packageDefinition = protoLoader.loadSync('user.proto');
const userProto = grpc.loadPackageDefinition(packageDefinition);

const client = new userProto.UserService(
  'user-service:50051',
  grpc.credentials.createInsecure()
);

client.GetUser({ user_id: 123 }, (err, response) => {
  console.log(response);
});

优点:

缺点:

模式 3:消息队列(异步)

JAVASCRIPT
// 发布者(订单服务)
const amqp = require('amqplib');

async function publishOrderCreated(order) {
  const conn = await amqp.connect('amqp://rabbitmq');
  const channel = await conn.createChannel();
  
  const exchange = 'order_events';
  await channel.assertExchange(exchange, 'topic', { durable: true });
  
  channel.publish(
    exchange,
    'order.created',
    Buffer.from(JSON.stringify(order)),
    { persistent: true }
  );
  
  console.log('订单创建事件已发布:', order.id);
}

// 订阅者(库存服务)
async function subscribeToOrders() {
  const conn = await amqp.connect('amqp://rabbitmq');
  const channel = await conn.createChannel();
  
  const exchange = 'order_events';
  await channel.assertExchange(exchange, 'topic', { durable: true });
  
  const q = await channel.assertQueue('inventory_service', { durable: true });
  await channel.bindQueue(q.queue, exchange, 'order.created');
  
  channel.consume(q.queue, (msg) => {
    const order = JSON.parse(msg.content);
    console.log('收到订单事件:', order.id);
    
    // 处理库存
    reserveInventory(order);
    
    channel.ack(msg);
  });
}

优点:

缺点:

模式 4:事件溯源(Event Sourcing)

JAVASCRIPT
// 事件存储
class EventStore {
  constructor() {
    this.events = [];
  }
  
  async append(streamId, event) {
    this.events.push({
      streamId,
      eventType: event.type,
      data: event.data,
      timestamp: Date.now(),
      version: this.events.filter(e => e.streamId === streamId).length + 1
    });
  }
  
  async getEvents(streamId) {
    return this.events.filter(e => e.streamId === streamId);
  }
}

// 聚合根
class Order {
  constructor() {
    this.id = null;
    this.status = 'new';
    this.items = [];
    this.changes = [];
  }
  
  create(id, items) {
    this.apply({
      type: 'OrderCreated',
      data: { id, items }
    });
  }
  
  confirm() {
    this.apply({
      type: 'OrderConfirmed',
      data: {}
    });
  }
  
  apply(event) {
    // 应用事件
    switch (event.type) {
      case 'OrderCreated':
        this.id = event.data.id;
        this.items = event.data.items;
        this.status = 'new';
        break;
      case 'OrderConfirmed':
        this.status = 'confirmed';
        break;
    }
    
    // 记录变更
    this.changes.push(event);
  }
  
  static async load(eventStore, orderId) {
    const events = await eventStore.getEvents(orderId);
    const order = new Order();
    events.forEach(e => order.apply(e));
    return order;
  }
}

优点:

缺点:

我们的最终方案

混合模式

CODE
┌─────────────────────────────────────────────┐
│  同步通信(gRPC)                           │
│  - 实时查询                                 │
│  - 需要立即响应                             │
│  - 服务内部调用                             │
├─────────────────────────────────────────────┤
│  异步通信(消息队列)                       │
│  - 状态变更通知                             │
│  - 不需要立即响应                           │
│  - 跨服务事件                               │
├─────────────────────────────────────────────┤
│  事件溯源(特定场景)                       │
│  - 金融交易                                 │
│  - 需要完整审计                             │
│  - 复杂业务逻辑                             │
└─────────────────────────────────────────────┘

具体实现

JAVASCRIPT
// 1. 同步查询用 gRPC
async function getUserProfile(userId) {
  const user = await userServiceClient.GetUser({ user_id: userId });
  const orders = await orderServiceClient.GetUserOrders({ user_id: userId });
  
  return {
    user,
    orders: orders.orders
  };
}

// 2. 状态变更用消息队列
async function createOrder(orderData) {
  // 创建订单
  const order = await db.orders.create(orderData);
  
  // 发布事件
  await publishEvent('order.created', {
    orderId: order.id,
    userId: order.userId,
    items: order.items,
    total: order.total
  });
  
  return order;
}

// 3. 关键业务用事件溯源
class PaymentService {
  async processPayment(paymentId, amount) {
    // 记录事件
    await eventStore.append(paymentId, {
      type: 'PaymentInitiated',
      data: { amount }
    });
    
    // 处理支付
    const result = await paymentGateway.charge(amount);
    
    // 记录结果
    await eventStore.append(paymentId, {
      type: result.success ? 'PaymentSucceeded' : 'PaymentFailed',
      data: result
    });
    
    // 发布事件
    await publishEvent('payment.completed', {
      paymentId,
      success: result.success
    });
  }
}

最佳实践

1. 超时和重试

JAVASCRIPT
// 使用指数退避重试
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      
      const delay = Math.pow(2, i) * 1000;
      await sleep(delay);
    }
  }
}

// 设置合理超时
const client = new UserServiceClient({
  timeout: 3000,  // 3 秒超时
  retryPolicy: {
    maxRetries: 3,
    initialBackoff: 1000,
    maxBackoff: 10000
  }
});

2. 熔断器

JAVASCRIPT
class CircuitBreaker {
  constructor(fn, options = {}) {
    this.fn = fn;
    this.state = 'CLOSED';
    this.failureCount = 0;
    this.successCount = 0;
    this.lastFailureTime = null;
    
    this.failureThreshold = options.failureThreshold || 5;
    this.resetTimeout = options.resetTimeout || 60000;
  }
  
  async call(...args) {
    if (this.state === 'OPEN') {
      if (Date.now() - this.lastFailureTime > this.resetTimeout) {
        this.state = 'HALF_OPEN';
      } else {
        throw new Error('Circuit breaker is OPEN');
      }
    }
    
    try {
      const result = await this.fn(...args);
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }
  
  onSuccess() {
    this.failureCount = 0;
    if (this.state === 'HALF_OPEN') {
      this.state = 'CLOSED';
    }
  }
  
  onFailure() {
    this.failureCount++;
    this.lastFailureTime = Date.now();
    
    if (this.failureCount >= this.failureThreshold) {
      this.state = 'OPEN';
    }
  }
}

// 使用
const userService = new CircuitBreaker(
  (userId) => userServiceClient.GetUser({ user_id: userId }),
  { failureThreshold: 5, resetTimeout: 60000 }
);

const user = await userService.call(123);

3. 幂等性

JAVASCRIPT
// 使用请求 ID 保证幂等
async function createOrder(orderData, requestId) {
  // 检查是否已处理
  const existing = await db.idempotency_keys.findOne({
    where: { key: requestId }
  });
  
  if (existing) {
    return existing.response;
  }
  
  // 处理请求
  const order = await db.orders.create(orderData);
  
  // 记录幂等键
  await db.idempotency_keys.create({
    key: requestId,
    response: order
  });
  
  return order;
}

效果对比

| 指标 | 优化前 | 优化后 |

|------|--------|--------|

| 平均延迟 | 850ms | 120ms |

| P99 延迟 | 5200ms | 450ms |

| 故障率 | 2.5% | 0.1% |

| 雪崩次数 | 3 次/月 | 0 |

总结

微服务通信选择指南:

| 场景 | 推荐模式 |

|------|---------|

| 实时查询 | gRPC / REST |

| 状态变更 | 消息队列 |

| 关键业务 | 事件溯源 |

| 简单集成 | REST |

核心原则:

1. 选择合适的模式:不要一刀切

2. 设计失败:超时、重试、熔断

3. 保证幂等:防止重复处理

4. 监控一切:及时发现问题

做好这些,微服务通信就不再是噩梦。


优化时间:2026年7月

系统规模:30+ 微服务

故障率:2.5% → 0.1%

#微服务 #分布式系统 #通信模式 #架构设计

389
9744 阅读
2 评论
分享
链接已复制
编辑说明

本文由 MakeSense 编辑团队撰写并审核。文中引用的数据和观点均经过交叉验证,如有疏漏欢迎在评论区指正。最后更新:2026年07月10日 18:09

陈默

AI 行业分析师

前某大厂 AI 实验室研究员,关注大模型技术演进和商业化落地。写过 200+ 篇行业分析,擅长从产品视角拆解技术趋势。

读者评论 2

技术小白 1周前
作为非技术人员也看懂了,感谢作者的通俗讲解。
回复 点赞 (3)
Dev小王 2天前
终于有人把这个说清楚了,收藏了。
回复 点赞 (8)