Skip to content

微服务架构

概述

微服务架构是一种将应用程序构建为一组小型、独立服务的软件架构风格。每个服务运行在自己的进程中,通过轻量级机制(通常是HTTP API)进行通信。

核心概念

什么是微服务

微服务是一种软件架构模式,将应用程序分解为多个小型、独立的服务,每个服务负责特定的业务功能。

特点:

  • 服务独立部署
  • 技术栈多样化
  • 数据自治
  • 故障隔离
  • 团队自治

微服务 vs 单体架构

特性单体架构微服务架构
部署整体部署独立部署
技术栈统一多样化
扩展性水平扩展整个应用按需扩展服务
故障影响整个应用单个服务
团队协作紧密耦合松耦合

设计原则

1. 单一职责原则

每个微服务应该只负责一个业务功能或领域。

javascript
// 用户服务 - 只负责用户相关功能
class UserService {
  async createUser(userData) { /* 用户创建逻辑 */ }
  async getUserById(id) { /* 用户查询逻辑 */ }
  async updateUser(id, data) { /* 用户更新逻辑 */ }
}

// 订单服务 - 只负责订单相关功能
class OrderService {
  async createOrder(orderData) { /* 订单创建逻辑 */ }
  async getOrderById(id) { /* 订单查询逻辑 */ }
  async updateOrderStatus(id, status) { /* 订单状态更新逻辑 */ }
}

2. 服务自治

每个服务应该能够独立运行,不依赖其他服务的状态。

javascript
// 好的设计 - 服务自治
class ProductService {
  async getProduct(id) {
    // 服务内部处理,不依赖外部服务
    return await this.productRepository.findById(id);
  }
}

// 避免的设计 - 服务依赖
class ProductService {
  async getProduct(id) {
    // 依赖用户服务,违反自治原则
    const user = await this.userService.getCurrentUser();
    return await this.productRepository.findById(id, user.id);
  }
}

3. 数据隔离

每个服务拥有自己的数据库,避免数据共享。

sql
-- 用户服务数据库
CREATE TABLE users (
  id INT PRIMARY KEY,
  username VARCHAR(50),
  email VARCHAR(100),
  created_at TIMESTAMP
);

-- 订单服务数据库
CREATE TABLE orders (
  id INT PRIMARY KEY,
  user_id INT,  -- 只存储用户ID,不存储用户详细信息
  product_id INT,
  quantity INT,
  total_amount DECIMAL(10,2),
  created_at TIMESTAMP
);

技术栈

1. 服务框架

Spring Cloud (Java)

xml
<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
java
// 服务注册
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

// 服务调用
@FeignClient(name = "order-service")
public interface OrderServiceClient {
    @GetMapping("/orders/user/{userId}")
    List<Order> getUserOrders(@PathVariable("userId") Long userId);
}

NestJS (Node.js)

typescript
// 微服务配置
import { Transport } from '@nestjs/microservices';

@Module({
  imports: [
    ClientsModule.register([
      {
        name: 'USER_SERVICE',
        transport: Transport.TCP,
        options: {
          host: 'localhost',
          port: 3001,
        },
      },
    ]),
  ],
})
export class AppModule {}

2. 服务发现

Eureka (Spring Cloud)

yaml
# application.yml
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

Consul

javascript
// Node.js 服务注册
const consul = require('consul')();

consul.agent.service.register({
  name: 'user-service',
  address: 'localhost',
  port: 3000,
  check: {
    http: 'http://localhost:3000/health',
    interval: '10s'
  }
});

3. API网关

Spring Cloud Gateway

yaml
# application.yml
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**

Kong

yaml
# kong.yml
services:
  - name: user-service
    url: http://user-service:3000
    routes:
      - name: user-routes
        paths:
          - /api/users

4. 配置管理

Spring Cloud Config

yaml
# bootstrap.yml
spring:
  cloud:
    config:
      uri: http://localhost:8888
      name: user-service
      profile: dev

Apollo (携程开源)

javascript
// Node.js 配置管理
const { ApolloClient } = require('apollo-client');

const client = new ApolloClient({
  appId: 'user-service',
  cluster: 'default',
  namespace: 'application',
  ip: 'localhost'
});

通信模式

1. 同步通信

REST API

javascript
// 服务间调用
class OrderService {
  async createOrder(orderData) {
    // 调用用户服务验证用户
    const user = await fetch('http://user-service/api/users/' + orderData.userId);
    if (!user) {
      throw new Error('User not found');
    }
    
    // 创建订单
    return await this.orderRepository.create(orderData);
  }
}

gRPC

protobuf
// user.proto
service UserService {
  rpc GetUser(GetUserRequest) returns (GetUserResponse);
  rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
}

message GetUserRequest {
  int32 user_id = 1;
}

message GetUserResponse {
  User user = 1;
}

2. 异步通信

消息队列 (RabbitMQ)

javascript
// 发布者
class OrderService {
  async createOrder(orderData) {
    const order = await this.orderRepository.create(orderData);
    
    // 发布订单创建事件
    await this.messageQueue.publish('order.created', {
      orderId: order.id,
      userId: order.userId,
      amount: order.amount
    });
    
    return order;
  }
}

// 订阅者
class NotificationService {
  async handleOrderCreated(event) {
    const user = await this.userService.getUser(event.userId);
    await this.sendEmail(user.email, `订单 ${event.orderId} 创建成功`);
  }
}

Apache Kafka

javascript
// 生产者
const kafka = require('kafka-node');
const producer = new kafka.Producer(new kafka.KafkaClient());

producer.send([{
  topic: 'order-events',
  messages: JSON.stringify({
    type: 'ORDER_CREATED',
    data: { orderId: 123, userId: 456 }
  })
}]);

// 消费者
const consumer = new kafka.Consumer(new kafka.KafkaClient(), [
  { topic: 'order-events' }
]);

consumer.on('message', (message) => {
  const event = JSON.parse(message.value);
  if (event.type === 'ORDER_CREATED') {
    handleOrderCreated(event.data);
  }
});

数据管理

1. 数据库设计

每个服务独立数据库

sql
-- 用户服务数据库
CREATE DATABASE user_service;
USE user_service;

CREATE TABLE users (
  id BIGINT PRIMARY KEY,
  username VARCHAR(50) UNIQUE,
  email VARCHAR(100) UNIQUE,
  password_hash VARCHAR(255),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 订单服务数据库
CREATE DATABASE order_service;
USE order_service;

CREATE TABLE orders (
  id BIGINT PRIMARY KEY,
  user_id BIGINT,  -- 只存储用户ID
  product_id BIGINT,
  quantity INT,
  total_amount DECIMAL(10,2),
  status ENUM('pending', 'paid', 'shipped', 'delivered'),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

2. 数据一致性

Saga模式

javascript
// Saga协调器
class OrderSaga {
  async createOrder(orderData) {
    try {
      // 1. 创建订单
      const order = await this.orderService.createOrder(orderData);
      
      // 2. 扣减库存
      await this.inventoryService.reduceStock(orderData.productId, orderData.quantity);
      
      // 3. 扣减余额
      await this.paymentService.deductBalance(orderData.userId, order.totalAmount);
      
      // 4. 更新订单状态
      await this.orderService.updateOrderStatus(order.id, 'paid');
      
      return order;
    } catch (error) {
      // 补偿操作
      await this.compensate(order, error);
      throw error;
    }
  }
  
  async compensate(order, error) {
    // 根据错误类型执行补偿
    if (error.service === 'inventory') {
      await this.inventoryService.restoreStock(order.productId, order.quantity);
    }
    if (error.service === 'payment') {
      await this.paymentService.refund(order.userId, order.totalAmount);
    }
  }
}

事件溯源

javascript
// 事件存储
class EventStore {
  async appendEvents(aggregateId, events) {
    for (const event of events) {
      await this.db.insert('events', {
        aggregate_id: aggregateId,
        event_type: event.type,
        event_data: JSON.stringify(event.data),
        version: event.version,
        timestamp: new Date()
      });
    }
  }
  
  async getEvents(aggregateId) {
    return await this.db.query(
      'SELECT * FROM events WHERE aggregate_id = ? ORDER BY version',
      [aggregateId]
    );
  }
}

// 聚合根
class Order {
  constructor(id) {
    this.id = id;
    this.events = [];
    this.state = { status: 'created' };
  }
  
  createOrder(userId, productId, quantity, amount) {
    const event = {
      type: 'OrderCreated',
      data: { userId, productId, quantity, amount },
      version: this.events.length + 1
    };
    
    this.events.push(event);
    this.apply(event);
  }
  
  apply(event) {
    switch (event.type) {
      case 'OrderCreated':
        this.state = { ...this.state, ...event.data, status: 'created' };
        break;
      case 'OrderPaid':
        this.state.status = 'paid';
        break;
    }
  }
}

监控与可观测性

1. 分布式追踪

Jaeger

javascript
// Node.js 集成
const { initTracer } = require('jaeger-client');

const tracer = initTracer({
  serviceName: 'user-service',
  sampler: {
    type: 'const',
    param: 1,
  },
  reporter: {
    logSpans: true,
    agentHost: 'localhost',
    agentPort: 6832,
  },
});

// 创建span
const span = tracer.startSpan('getUser');
span.setTag('user.id', userId);

try {
  const user = await getUserById(userId);
  span.setTag('user.found', true);
  return user;
} catch (error) {
  span.setTag('error', true);
  span.log({ event: 'error', 'error.object': error });
  throw error;
} finally {
  span.finish();
}

2. 日志聚合

ELK Stack

javascript
// 结构化日志
const winston = require('winston');

const logger = winston.createLogger({
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [
    new winston.transports.Console(),
    new winston.transports.File({ filename: 'app.log' })
  ]
});

logger.info('User created', {
  userId: 123,
  username: 'john_doe',
  service: 'user-service',
  traceId: span.context().traceId
});

3. 指标监控

Prometheus + Grafana

javascript
// 自定义指标
const prometheus = require('prom-client');

const httpRequestDuration = new prometheus.Histogram({
  name: 'http_request_duration_seconds',
  help: 'Duration of HTTP requests in seconds',
  labelNames: ['method', 'route', 'status_code']
});

// 中间件
app.use((req, res, next) => {
  const start = Date.now();
  
  res.on('finish', () => {
    const duration = (Date.now() - start) / 1000;
    httpRequestDuration
      .labels(req.method, req.route?.path || req.path, res.statusCode)
      .observe(duration);
  });
  
  next();
});

部署策略

1. 容器化部署

Docker

dockerfile
# Dockerfile
FROM node:16-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 3000

CMD ["npm", "start"]
yaml
# docker-compose.yml
version: '3.8'
services:
  user-service:
    build: ./user-service
    ports:
      - "3001:3000"
    environment:
      - NODE_ENV=production
      - DB_HOST=user-db
    depends_on:
      - user-db
  
  order-service:
    build: ./order-service
    ports:
      - "3002:3000"
    environment:
      - NODE_ENV=production
      - DB_HOST=order-db
    depends_on:
      - order-db
  
  user-db:
    image: postgres:13
    environment:
      - POSTGRES_DB=user_service
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
  
  order-db:
    image: postgres:13
    environment:
      - POSTGRES_DB=order_service
      - POSTGRES_USER=order
      - POSTGRES_PASSWORD=password

2. Kubernetes部署

yaml
# user-service-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
      - name: user-service
        image: user-service:latest
        ports:
        - containerPort: 3000
        env:
        - name: DB_HOST
          valueFrom:
            configMapKeyRef:
              name: user-service-config
              key: db_host
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5

最佳实践

1. 服务拆分原则

  • 按业务领域拆分:根据业务功能划分服务
  • 按团队边界拆分:考虑团队的组织结构
  • 按数据边界拆分:避免跨服务的数据依赖
  • 按变更频率拆分:将变更频率不同的功能分离

2. API设计

javascript
// RESTful API设计
// 用户服务API
GET    /api/users          // 获取用户列表
GET    /api/users/:id      // 获取单个用户
POST   /api/users          // 创建用户
PUT    /api/users/:id      // 更新用户
DELETE /api/users/:id      // 删除用户

// 订单服务API
GET    /api/orders         // 获取订单列表
GET    /api/orders/:id     // 获取单个订单
POST   /api/orders         // 创建订单
PUT    /api/orders/:id     // 更新订单
DELETE /api/orders/:id     // 删除订单

3. 错误处理

javascript
// 统一错误处理
class ServiceError extends Error {
  constructor(message, statusCode, service) {
    super(message);
    this.statusCode = statusCode;
    this.service = service;
  }
}

// 错误响应格式
{
  "error": {
    "code": "USER_NOT_FOUND",
    "message": "User with id 123 not found",
    "service": "user-service",
    "timestamp": "2024-01-15T10:30:00Z",
    "traceId": "abc123"
  }
}

4. 版本管理

javascript
// API版本控制
// v1 API
app.use('/api/v1/users', userRoutesV1);

// v2 API
app.use('/api/v2/users', userRoutesV2);

// 版本兼容
app.use('/api/users', (req, res, next) => {
  const version = req.headers['api-version'] || 'v1';
  req.apiVersion = version;
  next();
});

常见挑战与解决方案

1. 分布式事务

挑战:跨服务的数据一致性 解决方案:Saga模式、事件溯源、最终一致性

2. 服务间通信

挑战:网络延迟、服务不可用 解决方案:熔断器、重试机制、异步通信

3. 数据管理

挑战:数据分散、查询复杂 解决方案:CQRS、事件溯源、数据聚合

4. 测试复杂性

挑战:服务间依赖、集成测试困难 解决方案:契约测试、服务虚拟化、端到端测试

总结

微服务架构是一种强大的软件架构模式,能够提供更好的可扩展性、可维护性和团队自治。但同时也带来了分布式系统的复杂性。成功实施微服务需要:

  1. 正确的设计原则:单一职责、服务自治、数据隔离
  2. 合适的技术栈:服务发现、API网关、消息队列
  3. 完善的监控:分布式追踪、日志聚合、指标监控
  4. 良好的实践:容器化部署、自动化测试、持续集成

通过合理的设计和实践,微服务架构能够为企业带来巨大的价值。