{T}

微服务架构基础

微服务(Microservices)不是"把一个项目拆成很多个 Spring Boot 工程"这么简单。它本质上是一种围绕业务能力组织系统的架构方式,强调:

  • 服务边界清晰:每个服务聚焦特定业务领域
  • 服务自治:独立开发、测试、部署、扩容
  • 去中心化治理:允许不同服务选择不同技术栈
  • 配套治理能力同步建设:服务发现、配置、监控、容错等基础设施

微服务的历史演进

从单体到微服务的演变

1. 单体架构时代(2000 年代初)

所有功能打包在一个应用中,部署在单一服务器上。

优点:

  • 开发简单,调试方便
  • 部署简单,只需部署一个应用
  • 事务处理容易(本地事务)

缺点:

  • 随着业务增长,代码变得庞大且复杂
  • 一个小改动需要重新部署整个应用
  • 技术栈被锁定,难以引入新技术
  • 扩容只能整体扩容,资源浪费

2. SOA 时代(2005-2010)

面向服务的架构(Service-Oriented Architecture)开始流行。

特点:

  • 将应用拆分为粗粒度的服务
  • 通过企业服务总线(ESB)连接各个服务
  • 强调服务的重用和组合

问题:

  • ESB 成为单点故障和性能瓶颈
  • 服务边界模糊,粒度不够细
  • 仍然存在大量集中式治理

3. 微服务时代(2014 至今)

2014 年,Martin Fowler 和 James Lewis 发表了微服务架构的经典论文,正式提出微服务概念。

核心理念:

微服务架构是一种将单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通过轻量级机制通信(通常是 HTTP API),每个服务围绕业务能力构建,可独立部署、独立扩展,并且可以用不同的编程语言和数据库。

微服务的定义与特征

Martin Fowler 的微服务定义:

  1. 组件化与解耦:系统由多个独立可替换、可升级的组件组成
  2. 按业务能力组织:服务围绕业务能力而不是技术层划分
  3. 产品而非项目:团队对服务的全生命周期负责
  4. 智能端点与哑管道:服务端点智能,通信管道简单
  5. 去中心化治理:允许不同服务选择不同技术栈
  6. 去中心化数据管理:每个服务管理自己的数据库
  7. 基础设施自动化:高度自动化的部署、测试、监控
  8. 容错设计:假设服务会失败,设计容错机制
  9. 演进式设计:逐步演进,而非一次性设计完成

什么是微服务

微服务是将一个大型系统拆分成多个相对独立的小型服务,每个服务围绕一项相对稳定的业务能力构建。

典型电商系统的服务拆分

code
┌─────────────────────────────────────────────────────┐
│              电商微服务架构                          │
├─────────────────────────────────────────────────────┤
│  用户服务(User Service)                           │
│  - 用户注册、登录、认证                             │
│  - 用户信息管理                                     │
│  - 会员等级、积分                                   │
├─────────────────────────────────────────────────────┤
│  商品服务(Product Service)                        │
│  - 商品信息管理                                     │
│  - 分类、品牌、属性                                 │
│  - 商品搜索、推荐                                   │
├─────────────────────────────────────────────────────┤
│  订单服务(Order Service)                          │
│  - 订单创建、查询、取消                             │
│  - 订单状态流转                                     │
│  - 订单统计分析                                     │
├─────────────────────────────────────────────────────┤
│  库存服务(Inventory Service)                      │
│  - 库存查询、扣减、回退                             │
│  - 库存预警、补货                                   │
│  - 仓库管理                                         │
├─────────────────────────────────────────────────────┤
│  支付服务(Payment Service)                        │
│  - 支付渠道对接                                     │
│  - 支付状态管理                                     │
│  - 退款处理                                         │
├─────────────────────────────────────────────────────┤
│  营销服务(Marketing Service)                      │
│  - 优惠券管理                                       │
│  - 促销活动                                         │
│  - 积分兑换                                         │
└─────────────────────────────────────────────────────┘

微服务的核心特征

1. 服务自治

每个服务可以:

  • 独立开发:团队独立开发,不受其他服务影响
  • 独立测试:完整的测试套件,包括单元测试、集成测试、端到端测试
  • 独立部署:部署不影响其他服务
  • 独立扩容:根据业务压力独立水平扩展

2. 业务边界清晰

服务划分基于业务能力(Business Capability),而不是技术层:

code
× 错误拆分(按技术层):
┌─────────────────┐
│  Web 层         │
├─────────────────┤
│  Service 层     │
├─────────────────┤
│  DAO 层         │
├─────────────────┤
│  Database 层    │
└─────────────────┘

√ 正确拆分(按业务能力):
┌─────────┐  ┌─────────┐  ┌─────────┐
│ 用户服务 │  │ 商品服务 │  │ 订单服务 │
└─────────┘  └─────────┘  └─────────┘

3. 技术多样性

不同服务可以选择不同的技术栈:

code
用户服务    → Spring Boot + MySQL
商品服务    → Spring Boot + Elasticsearch
推荐服务    → Python + TensorFlow
统计服务    → Go + ClickHouse
前端服务    → Node.js + React
技术多样性是一把双刃剑

虽然允许技术多样性,但大多数企业仍会限制技术栈,避免:

  • 团队学习成本增加
  • 运维复杂度提升
  • 招聘难度加大

4. 数据独立

每个服务管理自己的数据:

code
┌──────────────────────┐
│   用户服务            │
│  ┌────────────────┐  │
│  │  用户数据库     │  │
│  │  MySQL         │  │
│  └────────────────┘  │
└──────────────────────┘

┌──────────────────────┐
│   商品服务            │
│  ┌────────────────┐  │
│  │  商品数据库     │  │
│  │  Elasticsearch │  │
│  └────────────────┘  │
└──────────────────────┘

┌──────────────────────┐
│   订单服务            │
│  ┌────────────────┐  │
│  │  订单数据库     │  │
│  │  PostgreSQL    │  │
│  └────────────────┘  │
└──────────────────────┘

关键原则:

  • 服务间不共享数据库
  • 通过 API 或消息队列获取数据
  • 接受最终一致性

为什么会出现微服务

单体架构的痛点

系统在早期通常从单体架构起步,这是非常正常的选择。因为单体在业务早期有明显优势:

  • 开发快、调试方便、部署简单、事务处理容易

但随着业务和团队规模增长,单体系统往往会暴露这些问题:

1. 代码复杂度爆炸

code
单体应用的代码规模:
- 初期:10,000 行代码
- 一年后:100,000 行代码
- 三年后:1,000,000+ 行代码

问题:
- 模块相互影响,牵一发动全身
- 新人上手困难,理解成本高
- 代码质量难以保证

2. 部署频率受限

code
场景:支付团队需要发布一个紧急补丁

单体架构:
- 必须等待其他模块的改动完成
- 回归测试整个系统
- 协调发布窗口
- 风险高,影响范围大

微服务架构:
- 独立测试支付服务
- 独立发布支付服务
- 风险可控,影响范围小

3. 扩容效率低

code
场景:大促期间订单服务压力大

单体架构:
- 只能整体扩容
- 其他模块跟着消耗资源
- 成本高,资源浪费

微服务架构:
- 只扩容订单服务
- 其他服务保持不变
- 成本优化,资源利用率高

4. 技术栈锁定

code
单体架构:
- 所有模块必须使用相同技术栈
- 难以引入新技术(如 AI、大数据)
- 技术债务难以偿还

微服务架构:
- 不同服务可以使用不同技术栈
- 渐进式技术升级
- 技术创新更容易落地

5. 团队协作冲突

code
场景:20 人团队维护一个单体应用

问题:
- 代码冲突频繁
- 测试互相影响
- 发布需要协调
- 责任不清

微服务架构:
- 每个团队负责自己的服务
- 代码隔离,冲突减少
- 独立测试、独立发布
- 责任清晰

微服务解决的核心问题

微服务主要解决的是:

  1. 复杂业务的边界治理问题

    • 通过清晰的业务边界,降低系统复杂度
    • 领域驱动设计(DDD)提供方法论支持
  2. 复杂团队的协作问题

    • 服务与团队对应,减少协作成本
    • 康威定律(Conway's Law)的实践
  3. 复杂系统的独立发布与独立扩容问题

    • 独立部署,降低发布风险
    • 按需扩容,优化资源利用

微服务不是什么

下面这些情况不能简单等同于微服务:

× 错误认知

1. 多模块单体应用 ≠ 微服务

java
// 单体应用的多模块结构
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// 虽然分了多个模块,但仍然是单体
modules/
├── user-module/
├── order-module/
├── product-module/
└── payment-module/

所有模块在同一个进程中运行,共享同一个数据库

2. 一个应用部署多个实例 ≠ 微服务

code
负载均衡
    ↓
┌─────────┐  ┌─────────┐  ┌─────────┐
│ 实例 1   │  │ 实例 2   │  │ 实例 3   │
│ (完整)   │  │ (完整)   │  │ (完整)   │
└─────────┘  └─────────┘  └─────────┘

这只是水平扩展,不是微服务
每个实例都包含所有功能

3. 按数据库表拆项目 ≠ 微服务

code
× 错误拆分:一表一服务

用户表 → 用户服务
角色表 → 角色服务
权限表 → 权限服务
日志表 → 日志服务
...

问题:
- 业务被切碎
- 调用链路过长
- 性能和稳定性下降

4. 服务数量多 ≠ 架构先进

code
微服务的价值不在于"拆了多少个服务",而在于:
- 边界是否稳定
- 协作是否清晰
- 治理是否可控

常见失败案例

很多失败的微服务实践,本质上不是技术组件选错了,而是:

案例 1:边界没拆清

code
问题:
- 服务 A 调用服务 B
- 服务 B 调用服务 A
- 循环依赖,边界不清

后果:
- 修改一个服务影响其他服务
- 部署顺序复杂
- 排障困难

案例 2:服务拆得过细

code
问题:
- 一个简单的业务拆了 20+ 个服务
- 一个请求经过 10+ 个服务
- 同步调用链路过长

后果:
- 性能下降(网络延迟)
- 稳定性下降(任何一个服务失败都会导致整个请求失败)
- 排障困难(调用链路复杂)

案例 3:配套治理没跟上

code
问题:
- 只拆了服务
- 没有服务发现
- 没有配置中心
- 没有链路追踪
- 没有监控告警

后果:
- 服务治理混乱
- 排障效率低
- 运维成本高

微服务解决了什么问题

1. 发布耦合问题

单体系统:

code
支付模块改动 → 回归测试整个系统 → 协调发布窗口 → 全站发版
                 ↓
            影响所有模块

微服务:

code
支付服务改动 → 测试支付服务 → 独立发布支付服务
                                    ↓
                            影响范围可控

价值:

  • 降低发布风险
  • 提高发布频率
  • 加快迭代速度

2. 扩容粒度问题

场景:大促期间订单服务压力大

单体架构:

code
┌─────────────────────────────────────┐
│  单体应用(4 核 8GB)               │
│  ┌───────┬───────┬───────┬───────┐ │
│  │ 用户  │ 商品  │ 订单  │ 支付  │ │
│  │ 模块  │ 模块  │ 模块  │ 模块  │ │
│  └───────┴───────┴───────┴───────┘ │
└─────────────────────────────────────┘
            ↓ 扩容
┌─────────────────────────────────────┐
│  单体应用(8 核 16GB)              │
│  所有模块都跟着扩容                 │
│  但只有订单模块压力大               │
│  其他模块资源浪费                   │
└─────────────────────────────────────┘

微服务架构:

code
┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐
│ 用户服务 │  │ 商品服务 │  │ 订单服务 │  │ 支付服务 │
│ 2 核 4GB │  │ 2 核 4GB │  │ 2 核 4GB │  │ 2 核 4GB │
└─────────┘  └─────────┘  └─────────┘  └─────────┘
                             ↓ 只扩容订单服务
┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐
│ 用户服务 │  │ 商品服务 │  │ 订单服务 │  │ 支付服务 │
│ 2 核 4GB │  │ 2 核 4GB │  │ 8 核 16GB│  │ 2 核 4GB │
└─────────┘  └─────────┘  └─────────┘  └─────────┘

只扩容有压力的服务,资源利用率高

价值:

  • 精细化资源管理
  • 降低成本
  • 提高资源利用率

3. 团队协作问题

康威定律(Conway's Law):

设计系统的组织,其产生的设计等同于组织间的沟通结构。

单体架构:

code
一个 20 人的大团队维护一个单体应用

问题:
- 代码冲突频繁
- 测试互相影响
- 发布需要协调
- 责任不清

微服务架构:

code
用户团队(5 人)→ 用户服务
商品团队(5 人)→ 商品服务
订单团队(5 人)→ 订单服务
支付团队(5 人)→ 支付服务

优势:
- 团队对服务负责
- 接口成为协作契约
- 发布节奏相对独立

价值:

  • 降低沟通成本
  • 提高团队效率
  • 责任清晰

4. 技术演进问题

单体架构:

code
技术栈绑定:
- Java 8 + Spring 4.x
- MySQL 5.6
- Redis 3.x

升级困难:
- 必须整体升级
- 风险高,影响大
- 技术债务积累

微服务架构:

code
技术多样性:

用户服务    → Java 17 + Spring Boot 3.x
商品服务    → Java 17 + Spring Boot 3.x
推荐服务    → Python 3.11 + TensorFlow
统计服务    → Go 1.21 + ClickHouse
实时计算    → Flink 1.17

渐进式升级:
- 新服务使用新技术
- 旧服务逐步迁移
- 技术创新更容易落地

价值:

  • 技术升级风险可控
  • 技术创新容易落地
  • 技术债务容易偿还

微服务引入的新复杂度

这是理解微服务最重要的一点:微服务不是简单降低复杂度,而是把复杂度从单体内部转移到分布式协作和治理层面

1. 网络通信问题

单体架构:

java
// 进程内调用,稳定可靠
public class OrderService {
    @Autowired
    private UserService userService;
    
    public void createOrder(Long userId) {
        // 直接调用,无网络开销
        User user = userService.getUser(userId);
    }
}

微服务架构:

java
// 跨进程调用,网络不可靠
public class OrderService {
    @Autowired
    private UserClient userClient;
    
    public void createOrder(Long userId) {
        // 网络调用,存在各种问题
        try {
            User user = userClient.getUser(userId);
        } catch (SocketTimeoutException e) {
            // 超时
        } catch (ConnectException e) {
            // 连接失败
        } catch (UnknownHostException e) {
            // DNS 解析失败
        }
    }
}

新问题:

  • 网络延迟:远程调用比本地调用慢几个数量级
  • 网络不可靠:超时、失败、抖动是常态
  • 序列化开销:数据需要序列化/反序列化

2. 数据一致性问题

单体架构:

java
// 本地事务,ACID 保证
@Transactional
public void placeOrder(Long userId, Long productId) {
    // 扣减库存
    inventoryDao.decrement(productId);
    // 创建订单
    orderDao.insert(order);
    // 扣减余额
    accountDao.decrement(userId);
    // 一个事务,要么全部成功,要么全部回滚
}

微服务架构:

code
跨服务事务:

订单服务          库存服务          账户服务
   │                │                │
   │ 创建订单       │                │
   ├───────────────>│                │
   │                │ 扣减库存       │
   │                ├───────────────>│
   │                │                │ 扣减余额
   │                │                │ × 失败
   │                │                │
   │ 如何回滚?     │                │
   │                │                │
   
问题:
- 如何保证跨服务的数据一致性?
- 部分失败时如何处理?
- 如何实现补偿?

解决方案:

  • 最终一致性
  • Saga 模式
  • TCC(Try-Confirm-Cancel)
  • 本地消息表

3. 服务治理问题

单体架构:

code
只需要关注:
- 应用本身
- 数据库
- 缓存
- 负载均衡

微服务架构:

code
需要额外关注:
- 服务注册与发现
- 配置中心
- API 网关
- 负载均衡(服务级别)
- 服务熔断与降级
- 服务限流
- 链路追踪
- 日志聚合
- 指标监控
- 告警系统

4. 运维复杂度问题

单体架构:

code
部署:1 个应用
监控:1 个应用
排障:查看单机日志

微服务架构:

code
部署:N 个服务 × M 个实例
监控:N × M 个实例
排障:需要聚合日志、链路追踪

5. 测试复杂度问题

单体架构:

code
测试类型:
- 单元测试
- 集成测试
- 端到端测试

测试环境:
- 本地开发环境
- 测试环境
- 生产环境

微服务架构:

code
测试类型:
- 单元测试
- 集成测试
- 契约测试
- 端到端测试

测试环境:
- 本地开发环境(需要模拟依赖服务)
- 集成测试环境
- 预发布环境
- 生产环境

挑战:
- 依赖服务不可用
- 服务间契约变更
- 测试数据管理

微服务架构模式

1. 服务发现模式(Service Discovery)

问题: 服务实例动态变化,如何知道服务的地址?

解决方案:

客户端发现

code
服务消费者 → 查询注册中心 → 获取服务实例列表 → 负载均衡 → 调用实例

示例(Spring Cloud Eureka):

java
// 服务提供者注册
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

// 服务消费者调用
@FeignClient(name = "user-service")
public interface UserClient {
    @GetMapping("/users/{id}")
    User getUser(@PathVariable("id") Long id);
}

服务端发现

code
服务消费者 → 负载均衡器/网关 → 查询注册中心 → 调用实例

示例(Kubernetes + Service):

yaml
apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: user-service
  ports:
  - port: 8080
    targetPort: 8080

2. API 网关模式(API Gateway)

问题: 客户端如何访问多个服务?

解决方案: 使用 API 网关作为统一入口。

网关职责:

code
┌─────────────────────────────────────────────────────┐
│              API 网关                                │
├─────────────────────────────────────────────────────┤
│  1. 路由转发                                         │
│     /api/users/*   → 用户服务                       │
│     /api/orders/*  → 订单服务                       │
│     /api/products/*→ 商品服务                       │
├─────────────────────────────────────────────────────┤
│  2. 认证授权                                         │
│     - JWT 验证                                      │
│     - 权限检查                                      │
├─────────────────────────────────────────────────────┤
│  3. 限流熔断                                         │
│     - 请求限流                                      │
│     - 服务熔断                                      │
├─────────────────────────────────────────────────────┤
│  4. 日志监控                                         │
│     - 请求日志                                      │
│     - 指标统计                                      │
├─────────────────────────────────────────────────────┤
│  5. 协议转换                                         │
│     - HTTP → gRPC                                  │
│     - SOAP → REST                                  │
└─────────────────────────────────────────────────────┘

示例(Spring Cloud Gateway):

java
@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
    
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("user-service", r -> r.path("/api/users/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter()))
                )
                .uri("lb://user-service"))
            .route("order-service", r -> r.path("/api/orders/**")
                .filters(f -> f.stripPrefix(1))
                .uri("lb://order-service"))
            .build();
    }
}

3. 断路器模式(Circuit Breaker)

问题: 服务调用失败时,如何防止级联故障?

解决方案: 使用断路器自动熔断。

断路器状态机:

code
         失败率超过阈值
    ┌──────────────────────┐
    │                      │
    ▼                      │
┌─────────┐  调用成功  ┌─────────┐
│  关闭   │────────────>│  半开   │
│ (Closed)│            │ (Half-Open)│
└─────────┘            └─────────┘
    ▲                      │
    │      调用失败        │
    │  ┌──────────────────┘
    │  │
    │  ▼
┌─────────┐
│  打开   │
│ (Open)  │
└─────────┘
    │
    │ 超时后进入半开状态
    └────────────┐
                 │
                 ▼
            ┌─────────┐
            │  半开   │
            └─────────┘

示例(Resilience4j):

java
@Service
public class OrderService {
    
    private final UserClient userClient;
    private final CircuitBreaker circuitBreaker;
    
    public OrderService(UserClient userClient) {
        this.userClient = userClient;
        this.circuitBreaker = CircuitBreaker.ofDefaults("userClient");
    }
    
    public User getUserWithFallback(Long userId) {
        return circuitBreaker.executeSupplier(() -> userClient.getUser(userId));
    }
    
    @CircuitBreaker(name = "userClient", fallbackMethod = "getUserFallback")
    public User getUser(Long userId) {
        return userClient.getUser(userId);
    }
    
    public User getUserFallback(Long userId, Exception e) {
        // 降级逻辑
        return new User(userId, "默认用户", false);
    }
}

4. 服务网格模式(Service Mesh)

问题: 每个服务都需要实现服务发现、熔断、限流等能力,代码侵入性强。

解决方案: 使用 Sidecar 代理将基础设施能力下沉。

架构:

code
┌─────────────────────────────────────────────────┐
│  Pod                                            │
│  ┌──────────────────┐  ┌──────────────────┐   │
│  │  服务容器         │  │  Sidecar(Envoy)│   │
│  │  - 业务逻辑       │  │  - 服务发现      │   │
│  │  - 无基础设施代码 │  │  - 负载均衡      │   │
│  │                   │  │  - 熔断限流      │   │
│  │                   │  │  - 链路追踪      │   │
│  └──────────────────┘  └──────────────────┘   │
│           │                     │              │
│           └─────────┬───────────┘              │
│                     │                          │
└─────────────────────┼──────────────────────────┘
                      │
              通过 Sidecar 通信

示例(Istio):

yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: user-service
spec:
  hosts:
  - user-service
  http:
  - route:
    - destination:
        host: user-service
        subset: v1
      weight: 90
    - destination:
        host: user-service
        subset: v2
      weight: 10
    retries:
      attempts: 3
      perTryTimeout: 2s

5. 事件驱动架构(Event-Driven Architecture)

问题: 服务间同步调用链路过长,稳定性差。

解决方案: 使用消息队列异步解耦。

架构:

code
同步调用(链路长):
订单服务 → 库存服务 → 支付服务 → 通知服务
    ↓          ↓          ↓          ↓
  200ms     150ms      300ms      100ms
  总耗时:750ms

异步调用(解耦):
订单服务 → 消息队列 ← 库存服务
              ↓
           支付服务
              ↓
           通知服务
订单服务只负责发消息,耗时:50ms

示例(Spring Cloud Stream + RabbitMQ):

java
// 订单服务发送消息
@Service
public class OrderService {
    
    @Autowired
    private StreamBridge streamBridge;
    
    public void placeOrder(Order order) {
        // 保存订单
        orderRepository.save(order);
        
        // 发送订单创建事件
        streamBridge.send("orderCreated-out-0", new OrderCreatedEvent(order.getId()));
    }
}

// 库存服务消费消息
@Service
public class InventoryService {
    
    @Bean
    public Consumer<OrderCreatedEvent> orderCreated() {
        return event -> {
            // 扣减库存
            inventoryService.decrement(event.getProductId(), event.getQuantity());
        };
    }
}

6. CQRS 模式(Command Query Responsibility Segregation)

问题: 读写模型混合,复杂度增加。

解决方案: 分离读写模型。

架构:

code
┌─────────────────────────────────────────────────────┐
│              CQRS 架构                               │
├─────────────────────────────────────────────────────┤
│  命令模型(Command Model)                          │
│  - 处理写操作                                       │
│  - 关注数据一致性                                   │
│  - 使用主数据库(MySQL)                            │
│  ┌─────────────────────────────────────┐          │
│  │  写入 → MySQL                        │          │
│  └─────────────────────────────────────┘          │
│           │                                         │
│           │ 发布事件                                │
│           ▼                                         │
│  查询模型(Query Model)                            │
│  - 处理读操作                                       │
│  - 关注查询性能                                     │
│  - 使用读库(Elasticsearch/Redis)                 │
│  ┌─────────────────────────────────────┐          │
│  │  读取 ← Elasticsearch/Redis          │          │
│  └─────────────────────────────────────┘          │
└─────────────────────────────────────────────────────┘

示例:

java
// 命令模型
@Service
public class OrderCommandService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    @Transactional
    public void createOrder(CreateOrderCommand command) {
        Order order = new Order(command);
        orderRepository.save(order);
        
        // 发布事件,更新查询模型
        eventPublisher.publishEvent(new OrderCreatedEvent(order));
    }
}

// 查询模型
@Service
public class OrderQueryService {
    
    @Autowired
    private OrderQueryRepository queryRepository;
    
    public OrderSummary getOrderSummary(Long orderId) {
        return queryRepository.findById(orderId);
    }
    
    @EventListener
    public void handle(OrderCreatedEvent event) {
        // 更新查询模型
        OrderSummary summary = new OrderSummary(event.getOrder());
        queryRepository.save(summary);
    }
}

微服务常见基础设施

基础设施全景图

基础设施作用主流组件为什么重要
API 网关统一入口、鉴权、路由、限流、灰度Spring Cloud Gateway、Kong、Nginx横切能力集中治理
注册中心维护服务名到实例地址的映射Nacos、Eureka、Consul、Zookeeper支撑动态扩缩容和实例变化
配置中心集中管理配置并支持变更治理Nacos、Apollo、Spring Cloud Config避免配置散落在本地文件和机器上
链路追踪还原一次请求的完整调用链SkyWalking、Zipkin、Jaeger提高分布式排障效率
日志系统集中收集、查询、分析日志ELK(Elasticsearch + Logstash + Kibana)分布式环境日志聚合
指标监控监控运行状态、异常和容量Prometheus + Grafana没有可观测性就很难稳定运行
熔断限流保护系统在高压和异常下有序退化Sentinel、Resilience4j、Hystrix防止局部故障扩散
消息队列异步解耦、削峰填谷、最终一致性Kafka、RocketMQ、RabbitMQ缩短主链路,减少同步依赖
容器编排自动化部署、扩缩容、服务治理Kubernetes、Docker Swarm微服务部署和运维的基础设施

1. 服务注册与发现

Nacos(推荐):

yaml
# application.yml
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: dev
        group: DEFAULT_GROUP
      config:
        server-addr: localhost:8848
        file-extension: yaml

服务注册:

java
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

2. 配置中心

Nacos Config:

yaml
# bootstrap.yml
spring:
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        file-extension: yaml
        shared-configs:
          - data-id: common.yaml
            group: DEFAULT_GROUP
            refresh: true

动态配置刷新:

java
@RefreshScope
@RestController
public class ConfigController {
    
    @Value("${app.config.value}")
    private String configValue;
    
    @GetMapping("/config")
    public String getConfig() {
        return configValue;
    }
}

3. API 网关

Spring Cloud Gateway:

java
@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
    
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("user-service", r -> r.path("/api/users/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter()))
                )
                .uri("lb://user-service"))
            .build();
    }
}

4. 链路追踪

SkyWalking:

bash
# 启动参数
java -javaagent:/path/to/skywalking-agent.jar \
     -Dskywalking.agent.service_name=user-service \
     -Dskywalking.collector.backend_service=localhost:11800 \
     -jar user-service.jar

查看调用链:

code
TraceId: 1234567890abcdef
┌─────────────────────────────────────────┐
│ user-service /api/users/123  200ms     │
│   ├─ order-service /orders  100ms      │
│   └─ payment-service /pay  50ms        │
└─────────────────────────────────────────┘

5. 监控告警

Prometheus + Grafana:

yaml
# prometheus.yml
scrape_configs:
  - job_name: 'user-service'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['user-service:8080']

Grafana 仪表盘:

  • 服务请求量、响应时间、错误率
  • JVM 内存、GC、线程
  • 数据库连接池、慢查询
  • Redis 命中率、延迟

6. 熔断限流

Sentinel:

java
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

@RestController
public class OrderController {
    
    @SentinelResource(value = "createOrder", blockHandler = "handleBlock")
    @PostMapping("/orders")
    public Order createOrder(@RequestBody OrderRequest request) {
        // 创建订单逻辑
    }
    
    public Order handleBlock(OrderRequest request, BlockException ex) {
        // 限流降级逻辑
        return new Order("系统繁忙,请稍后重试");
    }
}

服务拆分的核心原则

1. DDD 领域驱动设计

领域驱动设计(Domain-Driven Design)是微服务拆分的核心方法论。

关键概念:

  • 限界上下文(Bounded Context):明确的业务边界
  • 聚合(Aggregate):一组相关对象的集合,作为数据修改的单元
  • 领域事件(Domain Event):领域内发生的事情

示例:电商系统的领域划分

code
┌─────────────────────────────────────────────────────┐
│  用户域(User Context)                             │
│  聚合:User、Member、Address                        │
│  领域事件:UserRegistered、MemberUpgraded          │
├─────────────────────────────────────────────────────┤
│  商品域(Product Context)                          │
│  聚合:Product、Category、Brand                     │
│  领域事件:ProductCreated、PriceChanged            │
├─────────────────────────────────────────────────────┤
│  订单域(Order Context)                            │
│  聚合:Order、OrderItem                             │
│  领域事件:OrderCreated、OrderPaid、OrderShipped   │
├─────────────────────────────────────────────────────┤
│  库存域(Inventory Context)                        │
│  聚合:Inventory、Warehouse                         │
│  领域事件:StockDeducted、StockRestocked           │
└─────────────────────────────────────────────────────┘

2. 服务拆分原则

原则 1:按业务能力拆分

正确示例:

code
√ 按业务能力拆分:

用户服务
  - 用户注册、登录
  - 用户信息管理
  - 会员等级、积分

商品服务
  - 商品信息管理
  - 分类、品牌、属性
  - 商品搜索、推荐

订单服务
  - 订单创建、查询、取消
  - 订单状态流转

错误示例:

code
× 按技术层拆分:

Web 层服务
  - 所有 Controller

Service 层服务
  - 所有 Service

DAO 层服务
  - 所有 DAO

问题:
- 服务间调用频繁
- 业务逻辑分散
- 边界不清

原则 2:高内聚、低耦合

判断标准:

code
高内聚:
- 服务内部的代码围绕同一业务职责
- 频繁一起变化的功能放在一起

低耦合:
- 服务间通过接口交互
- 服务可以独立部署
- 服务可以独立扩容

示例:

java
// √ 高内聚:订单相关的逻辑都在订单服务
@Service
public class OrderService {
    public Order createOrder(CreateOrderCommand command) {
        // 校验用户
        User user = userClient.getUser(command.getUserId());
        // 校验商品
        Product product = productClient.getProduct(command.getProductId());
        // 创建订单
        Order order = new Order(user, product, command.getQuantity());
        orderRepository.save(order);
        return order;
    }
}

// × 低内聚:订单逻辑分散在多个服务
// 用户服务中有创建订单的逻辑
// 商品服务中有计算价格和逻辑
// 订单服务只是保存订单

原则 3:数据归属明确

原则:

  • 每个服务管理自己的核心数据
  • 其他服务通过 API 或消息获取信息
  • 避免跨服务直接访问数据库
  • 接受最终一致性

示例:

java
// √ 正确:通过 API 获取用户信息
@FeignClient(name = "user-service")
public interface UserClient {
    @GetMapping("/users/{id}")
    User getUser(@PathVariable("id") Long id);
}

// × 错误:直接连接用户服务的数据库
@Service
public class OrderService {
    @Autowired
    @Qualifier("userDataSource")
    private DataSource userDataSource;  // × 不应该这样
}

原则 4:先粗后细,避免过度拆分

拆分策略:

code
第一阶段:粗粒度拆分
┌─────────┐  ┌─────────┐  ┌─────────┐
│ 用户服务 │  │ 商品服务 │  │ 订单服务 │
└─────────┘  └─────────┘  └─────────┘

第二阶段:细粒度拆分(如果需要)
┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐
│ 用户服务 │  │ 商品服务 │  │ 订单服务 │  │ 库存服务 │  │ 支付服务 │
└─────────┘  └─────────┘  └─────────┘  └─────────┘  └─────────┘

第三阶段:进一步拆分(谨慎)
┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐
│ 用户服务 │  │ 商品服务 │  │ 订单服务 │  │ 库存服务 │  │ 支付服务 │
└─────────┘  └─────────┘  └─────────┘  └─────────┘  └─────────┘
┌─────────┐  ┌─────────┐  ┌─────────┐
│ 搜索服务 │  │ 推荐服务 │  │ 风控服务 │
└─────────┘  └─────────┘  └─────────┘

判断是否需要拆分:

问题答案是否拆分
是否有独立的业务生命周期?√ 拆分
是否有独立的扩容诉求?√ 拆分
是否由独立的团队负责?√ 拆分
领域边界是否稳定?√ 拆分

原则 5:同步依赖链路不要过长

问题:

code
× 同步链路过长:

用户请求
  → API 网关(10ms)
  → 认证服务(50ms)
  → 订单服务(200ms)
    → 用户服务(100ms)
    → 商品服务(100ms)
    → 库存服务(150ms)
    → 支付服务(300ms)
  → 通知服务(100ms)

总耗时:1010ms
任何一个服务失败都会导致整个请求失败

优化:

code
√ 核心流程同步,非核心流程异步:

用户请求
  → API 网关(10ms)
  → 认证服务(50ms)
  → 订单服务(200ms)
    → 库存服务(150ms)【同步】
  → 消息队列(10ms)
    → 支付服务(异步)
    → 通知服务(异步)

总耗时:420ms
核心流程稳定,非核心流程异步化

数据一致性解决方案

1. 分布式事务问题

经典场景:下单扣库存

code
订单服务          库存服务          支付服务
   │                │                │
   │ 1. 创建订单    │                │
   │ √              │                │
   ├───────────────>│                │
   │                │ 2. 扣减库存    │
   │                │ √              │
   │                ├───────────────>│
   │                │                │ 3. 扣款
   │                │                │ × 失败
   │                │                │
   │ 如何回滚?     │ 如何回滚?     │

2. 解决方案对比

方案一致性性能复杂度适用场景
2PC(两阶段提交)强一致性传统数据库
TCC最终一致性金融场景
Saga最终一致性长事务
本地消息表最终一致性简单场景
事务消息最终一致性消息队列场景

3. Saga 模式

编排式 Saga:

java
@Service
public class OrderSagaOrchestrator {
    
    @Autowired
    private OrderService orderService;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private PaymentService paymentService;
    
    public void placeOrder(PlaceOrderCommand command) {
        // 步骤 1:创建订单
        Order order = orderService.createOrder(command);
        
        try {
            // 步骤 2:扣减库存
            inventoryService.decrement(command.getProductId(), command.getQuantity());
            
            try {
                // 步骤 3:支付
                paymentService.pay(order.getId(), command.getAmount());
                
                // 步骤 4:确认订单
                orderService.confirmOrder(order.getId());
                
            } catch (PaymentException e) {
                // 补偿:恢复库存
                inventoryService.increment(command.getProductId(), command.getQuantity());
                // 补偿:取消订单
                orderService.cancelOrder(order.getId());
                throw e;
            }
            
        } catch (InventoryException e) {
            // 补偿:取消订单
            orderService.cancelOrder(order.getId());
            throw e;
        }
    }
}

协同式 Saga(事件驱动):

java
// 订单服务
@Service
public class OrderService {
    
    @Transactional
    public Order createOrder(PlaceOrderCommand command) {
        Order order = new Order(command);
        orderRepository.save(order);
        
        // 发布事件
        eventPublisher.publish(new OrderCreatedEvent(order));
        return order;
    }
    
    @Transactional
    @EventListener
    public void handle(PaymentFailedEvent event) {
        // 补偿:取消订单
        orderRepository.findById(event.getOrderId())
            .ifPresent(order -> order.cancel());
    }
}

// 库存服务
@Service
public class InventoryService {
    
    @Transactional
    @EventListener
    public void handle(OrderCreatedEvent event) {
        try {
            inventoryRepository.decrement(event.getProductId(), event.getQuantity());
            eventPublisher.publish(new InventoryDeductedEvent(event.getOrderId()));
        } catch (Exception e) {
            eventPublisher.publish(new InventoryDeductionFailedEvent(event.getOrderId()));
        }
    }
    
    @Transactional
    @EventListener
    public void handle(PaymentFailedEvent event) {
        // 补偿:恢复库存
        inventoryRepository.increment(event.getProductId(), event.getQuantity());
    }
}

4. 本地消息表

java
@Service
public class OrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private MessageRepository messageRepository;
    
    @Transactional
    public void placeOrder(PlaceOrderCommand command) {
        // 1. 创建订单
        Order order = new Order(command);
        orderRepository.save(order);
        
        // 2. 保存消息到本地消息表(同一个事务)
        Message message = new Message(
            "order-created",
            JSON.toJSONString(new OrderCreatedEvent(order))
        );
        messageRepository.save(message);
    }
}

// 定时任务扫描并发送消息
@Scheduled(fixedDelay = 5000)
public void sendPendingMessages() {
    List<Message> messages = messageRepository.findPendingMessages();
    for (Message message : messages) {
        try {
            mqProducer.send(message.getTopic(), message.getContent());
            message.markAsSent();
            messageRepository.save(message);
        } catch (Exception e) {
            // 下次重试
        }
    }
}

容器化与 Kubernetes

1. Docker 容器化

Dockerfile:

dockerfile
# 多阶段构建
FROM eclipse-temurin:17-jdk-alpine AS build
WORKDIR /app
COPY . .
RUN ./gradlew build -x test

FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY --from=build /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

构建与运行:

bash
# 构建镜像
docker build -t user-service:1.0.0 .

# 运行容器
docker run -d \
  --name user-service \
  -p 8080:8080 \
  -e SPRING_PROFILES_ACTIVE=prod \
  -e SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/user_db \
  user-service:1.0.0

2. Kubernetes 部署

Deployment:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
  labels:
    app: user-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
      - name: user-service
        image: user-service:1.0.0
        ports:
        - containerPort: 8080
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: "prod"
        - name: SPRING_DATASOURCE_URL
          valueFrom:
            configMapKeyRef:
              name: user-service-config
              key: database.url
        resources:
          requests:
            memory: "512Mi"
            cpu: "250m"
          limits:
            memory: "1Gi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5

Service:

yaml
apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: user-service
  ports:
  - port: 80
    targetPort: 8080
  type: ClusterIP

Ingress:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: user-service-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /users
        pathType: Prefix
        backend:
          service:
            name: user-service
            port:
              number: 80

3. Kubernetes 微服务治理

配置管理:

yaml
# ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: user-service-config
data:
  application.yaml: |
    server:
      port: 8080
    spring:
      datasource:
        url: jdbc:mysql://mysql:3306/user_db
        username: root
        password: password

---
# Secret
apiVersion: v1
kind: Secret
metadata:
  name: user-service-secret
type: Opaque
data:
  database.password: cGFzc3dvcmQ=  # base64 编码

自动扩缩容:

yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: user-service-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: user-service
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

可观测性建设

1. 三大支柱

code
┌─────────────────────────────────────────────────────┐
│          可观测性(Observability)                   │
├─────────────────────────────────────────────────────┤
│  指标(Metrics)                                    │
│  - 请求量、错误率、响应时间                         │
│  - CPU、内存、磁盘、网络                            │
│  - 业务指标(订单量、支付金额)                     │
│  工具:Prometheus + Grafana                        │
├─────────────────────────────────────────────────────┤
│  日志(Logs)                                       │
│  - 应用日志                                         │
│  - 访问日志                                         │
│  - 错误日志                                         │
│  工具:ELK(Elasticsearch + Logstash + Kibana)   │
├─────────────────────────────────────────────────────┤
│  链路追踪(Traces)                                 │
│  - 调用链路                                         │
│  - 性能瓶颈                                         │
│  - 错误定位                                         │
│  工具:SkyWalking、Zipkin、Jaeger                  │
└─────────────────────────────────────────────────────┘

2. 指标监控

Spring Boot Actuator:

yaml
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  metrics:
    tags:
      application: ${spring.application.name}
    export:
      prometheus:
        enabled: true

Prometheus 配置:

yaml
scrape_configs:
  - job_name: 'spring-boot'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets:
        - 'user-service:8080'
        - 'order-service:8080'
        - 'product-service:8080'

Grafana 仪表盘:

  • JVM 监控(堆内存、GC、线程)
  • HTTP 监控(请求量、响应时间、错误率)
  • 数据库监控(连接池、慢查询)
  • 自定义业务指标

3. 日志聚合

日志规范:

java
@Slf4j
@RestController
public class OrderController {
    
    @PostMapping("/orders")
    public Order createOrder(@RequestBody OrderRequest request) {
        log.info("[创建订单] 开始处理, userId={}, productId={}", 
            request.getUserId(), request.getProductId());
        
        try {
            Order order = orderService.createOrder(request);
            log.info("[创建订单] 处理成功, orderId={}", order.getId());
            return order;
        } catch (Exception e) {
            log.error("[创建订单] 处理失败, userId={}, error={}", 
                request.getUserId(), e.getMessage(), e);
            throw e;
        }
    }
}

Logback 配置:

xml
<configuration>
    <springProperty scope="context" name="appName" source="spring.application.name"/>
    
    <appender name="JSON" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/application.log</file>
        <encoder class="net.logstash.logback.encoder.LogstashEncoder">
            <customFields>{"app_name":"${appName}"}</customFields>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/application.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
    </appender>
    
    <root level="INFO">
        <appender-ref ref="JSON"/>
    </root>
</configuration>

ELK 架构:

code
应用服务 → Filebeat → Logstash → Elasticsearch → Kibana

4. 链路追踪

Spring Cloud Sleuth + Zipkin:

xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
yaml
spring:
  zipkin:
    base-url: http://zipkin:9411
  sleuth:
    sampler:
      probability: 1.0  # 采样率 100%

SkyWalking:

bash
java -javaagent:/path/to/skywalking-agent.jar \
     -Dskywalking.agent.service_name=user-service \
     -Dskywalking.collector.backend_service=localhost:11800 \
     -jar user-service.jar

链路追踪示例:

code
TraceId: 1234567890abcdef
SpanId: a1b2c3d4

┌─────────────────────────────────────────────┐
│ user-service                                │
│ Span: GET /api/users/123                    │
│ Duration: 200ms                             │
│   └─ order-service                          │
│       Span: POST /orders                    │
│       Duration: 150ms                       │
│         └─ inventory-service                │
│             Span: POST /inventory/decrement │
│             Duration: 80ms                  │
└─────────────────────────────────────────────┘

主流微服务框架对比

Spring Cloud Alibaba vs Spring Cloud Netflix vs Dubbo

特性Spring Cloud AlibabaSpring Cloud NetflixDubbo
注册中心NacosEureka(已停止维护)Nacos、Zookeeper
配置中心NacosSpring Cloud Config不提供
负载均衡Ribbon(已废弃)→ Spring Cloud LoadBalancerRibbonDubbo 自带
服务调用OpenFeignOpenFeignRPC(Dubbo 协议)
熔断限流SentinelHystrix(已停止维护)Sentinel
网关Spring Cloud GatewayZuul(已停止维护)不提供
社区活跃度低(Netflix 组件已停止维护)
学习曲线中等中等较陡
适用场景Spring Boot 项目传统 Spring Cloud 项目RPC 调用、高性能场景

推荐方案

新项目推荐:

code
Spring Cloud Alibaba(2022.x 及以上版本):
- 注册中心:Nacos
- 配置中心:Nacos
- 服务调用:OpenFeign
- 熔断限流:Sentinel
- 网关:Spring Cloud Gateway
- 链路追踪:SkyWalking
- 监控:Prometheus + Grafana

RPC 场景推荐:

code
Dubbo 3.x:
- 注册中心:Nacos
- 配置中心:Nacos
- 服务调用:Dubbo RPC
- 熔断限流:Sentinel
- 网关:Higress 或 Spring Cloud Gateway

实战案例:电商微服务架构

系统架构图

code
┌─────────────────────────────────────────────────────────────┐
│                      客户端层                                │
│  Web App  │  Mobile App  │  小程序  │  第三方系统           │
└─────────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────┐
│                    负载均衡层                                │
│                    Nginx / SLB                              │
└─────────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────┐
│                      API 网关层                              │
│  Spring Cloud Gateway / Kong                               │
│  - 路由转发                                                 │
│  - 认证授权                                                 │
│  - 限流熔断                                                 │
│  - 日志监控                                                 │
└─────────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────┐
│                     业务服务层                               │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  │
│  │用户服务   │  │商品服务   │  │订单服务   │  │支付服务   │  │
│  │          │  │          │  │          │  │          │  │
│  │- 注册登录 │  │- 商品管理 │  │- 订单创建 │  │- 支付处理 │  │
│  │- 用户信息 │  │- 库存管理 │  │- 订单查询 │  │- 退款处理 │  │
│  │- 会员积分 │  │- 价格策略 │  │- 订单状态 │  │- 支付渠道 │  │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘  │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  │
│  │营销服务   │  │搜索服务   │  │推荐服务   │  │通知服务   │  │
│  │          │  │          │  │          │  │          │  │
│  │- 优惠券   │  │- 商品搜索 │  │- 个性化推荐│  │- 短信通知 │  │
│  │- 促销活动 │  │- 全文检索 │  │- 协同过滤 │  │- 邮件通知 │  │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘  │
└─────────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────┐
│                    基础设施层                                │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  │
│  │注册中心   │  │配置中心   │  │消息队列   │  │链路追踪   │  │
│  │ Nacos    │  │ Nacos    │  │ RocketMQ │  │SkyWalking│  │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘  │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  │
│  │监控告警   │  │日志系统   │  │缓存服务   │  │搜索服务   │  │
│  │Prometheus│  │   ELK    │  │  Redis   │  │   ES     │  │
│  │ Grafana  │  │          │  │          │  │          │  │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘  │
└─────────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────┐
│                      数据层                                  │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  │
│  │ MySQL    │  │ Redis    │  │Elasticsearch│ │ MongoDB │  │
│  │ 主从复制 │  │ 集群     │  │  集群     │  │ 副本集   │  │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘  │
└─────────────────────────────────────────────────────────────┘

示例代码:订单服务

订单创建流程:

java
@Service
@Slf4j
public class OrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private UserClient userClient;
    @Autowired
    private ProductClient productClient;
    @Autowired
    private InventoryClient inventoryClient;
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    @Transactional
    @GlobalTransactional  // Seata 分布式事务
    public Order createOrder(CreateOrderCommand command) {
        // 1. 校验用户
        User user = userClient.getUser(command.getUserId());
        if (user == null || !user.isEnabled()) {
            throw new BusinessException("用户状态异常");
        }
        
        // 2. 校验商品
        Product product = productClient.getProduct(command.getProductId());
        if (product == null || !product.isOnSale()) {
            throw new BusinessException("商品不可购买");
        }
        
        // 3. 扣减库存
        boolean success = inventoryClient.decrement(
            command.getProductId(), 
            command.getQuantity()
        );
        if (!success) {
            throw new BusinessException("库存不足");
        }
        
        // 4. 创建订单
        Order order = new Order(
            user.getId(),
            product.getId(),
            command.getQuantity(),
            product.getPrice().multiply(new BigDecimal(command.getQuantity()))
        );
        orderRepository.save(order);
        
        // 5. 发布订单创建事件
        eventPublisher.publishEvent(new OrderCreatedEvent(order));
        
        log.info("[创建订单] 成功, orderId={}, userId={}, productId={}", 
            order.getId(), user.getId(), product.getId());
        
        return order;
    }
}

Feign 客户端:

java
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient {
    
    @GetMapping("/api/users/{id}")
    User getUser(@PathVariable("id") Long id);
}

@Component
public class UserClientFallback implements UserClient {
    
    @Override
    public User getUser(Long id) {
        // 降级逻辑
        return new User(id, "默认用户", false);
    }
}

微服务最佳实践

1. 服务拆分最佳实践

何时拆分:

code
√ 应该拆分的情况:
- 业务边界清晰且稳定
- 有独立的扩容诉求
- 团队规模足够(每个服务至少 3-5 人)
- 具备完善的基础设施(服务发现、配置、监控)

× 不应该拆分的情况:
- 业务仍在快速试错
- 团队规模小(< 10 人)
- 基础设施不完善
- 领域边界不清晰

拆分步骤:

code
1. 领域建模(DDD)
   - 识别限界上下文
   - 定义聚合和领域事件

2. 服务划分
   - 按业务能力拆分
   - 先粗后细

3. 数据拆分
   - 数据归属明确
   - 避免共享数据库

4. 接口定义
   - 契约优先
   - 版本管理

5. 基础设施建设
   - 服务发现
   - 配置中心
   - 链路追踪
   - 监控告警

2. 服务治理最佳实践

服务发现:

code
- 使用 Nacos 作为注册中心和配置中心
- 配置健康检查
- 合理设置心跳时间
- 多注册中心支持(异地多活)

配置管理:

code
- 配置分层:全局配置 → 应用配置 → 环境配置
- 敏感配置使用加密
- 配置变更审计
- 灰度发布支持

容错设计:

code
- 设置合理的超时时间
- 配置重试策略(幂等接口)
- 使用断路器防止级联故障
- 设计降级策略
- 限流保护系统

3. 数据管理最佳实践

数据库选型:

code
用户服务    → MySQL(事务性要求高)
商品服务    → Elasticsearch(搜索需求)
推荐服务    → Redis + MongoDB(推荐算法)
订单服务    → MySQL(事务性要求高)
支付服务    → MySQL(事务性要求高)
日志服务    → Elasticsearch(日志检索)

数据一致性:

code
- 核心流程:Saga 模式
- 简单场景:本地消息表
- 高可靠性:TCC
- 接受最终一致性

4. 运维最佳实践

CI/CD:

yaml
# GitLab CI/CD
stages:
  - build
  - test
  - docker
  - deploy

build:
  stage: build
  script:
    - ./gradlew build -x test

test:
  stage: test
  script:
    - ./gradlew test

docker:
  stage: docker
  script:
    - docker build -t registry.example.com/user-service:$CI_COMMIT_SHA .
    - docker push registry.example.com/user-service:$CI_COMMIT_SHA

deploy:
  stage: deploy
  script:
    - kubectl set image deployment/user-service user-service=registry.example.com/user-service:$CI_COMMIT_SHA
  only:
    - master

灰度发布:

yaml
# Istio VirtualService
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: user-service
spec:
  hosts:
  - user-service
  http:
  - match:
    - headers:
        canary:
          exact: "true"
    route:
    - destination:
        host: user-service
        subset: v2
  - route:
    - destination:
        host: user-service
        subset: v1
      weight: 95
    - destination:
        host: user-service
        subset: v2
      weight: 5

常见误区

误区一:团队规模和业务复杂度还没到位,就把微服务当成默认高级架构

真相:

微服务不是默认最优解,很多时候模块化单体才是更理性的阶段性选择。

何时选择微服务:

code
√ 应该选择微服务:
- 业务复杂度高
- 团队规模大(> 20 人)
- 边界稳定
- 基础设施完善

× 不应该选择微服务:
- 业务简单
- 团队规模小(< 10 人)
- 业务快速试错期
- 基础设施不完善

误区二:按数据库表拆服务

真相:

按表拆服务很容易形成"一表一服务",最后业务被切碎,调用链路变得又长又脆。

正确做法:

code
√ 按业务能力拆分:

订单服务
  - 订单表
  - 订单项表
  - 订单状态流转表

库存服务
  - 库存表
  - 仓库表
  - 库存流水表

× 按表拆分:

订单表服务
订单项服务
库存表服务
仓库表服务
...

误区三:服务拆开了,但还共享一个数据库

真相:

共享数据库会直接破坏服务自治,让边界失效。

问题:

code
用户服务 ─┐
商品服务 ─┼→ 共享数据库
订单服务 ─┤
支付服务 ─┘

问题:
- 数据修改互相影响
- 发布耦合
- 排障困难
- 边界形同虚设

正确做法:

code
用户服务 → 用户数据库
商品服务 → 商品数据库
订单服务 → 订单数据库
支付服务 → 支付数据库

通过 API 或消息获取数据

误区四:核心业务流程全部同步串联

真相:

同步链路过长会显著降低系统稳定性,非核心流程应优先考虑异步化。

问题:

code
× 全同步:

用户请求
  → 订单服务(200ms)
  → 库存服务(150ms)
  → 支付服务(300ms)
  → 积分服务(100ms)
  → 通知服务(100ms)

总耗时:850ms
任何一个服务失败都会导致整个请求失败

优化:

code
√ 核心同步,非核心异步:

用户请求
  → 订单服务(200ms)
  → 库存服务(150ms)
  → 支付服务(300ms)
  → 消息队列(10ms)
      → 积分服务(异步)
      → 通知服务(异步)

总耗时:660ms
非核心流程异步化,提高稳定性

误区五:只关注技术拆分,不关注治理和协作

真相:

微服务能不能长期跑稳,往往不取决于拆分动作本身,而取决于治理体系是否成熟。

需要关注:

code
√ 技术层面:
- 服务发现
- 配置中心
- 熔断限流
- 链路追踪
- 监控告警

√ 协作层面:
- 接口契约
- 文档管理
- 变更流程
- 责任边界

√ 组织层面:
- 团队与服务的对应关系
- 发布节奏
- 值班机制

误区六:过度追求技术多样性

真相:

技术多样性是一把双刃剑,过多的技术栈会增加学习和运维成本。

建议:

code
√ 主流技术栈统一:
- 编程语言:Java(大部分服务)
- 框架:Spring Boot / Spring Cloud
- 数据库:MySQL(事务服务)、Redis(缓存)、Elasticsearch(搜索)

√ 特殊场景允许差异:
- 推荐服务:Python(机器学习)
- 实时计算:Flink
- 前端渲染:Node.js

微服务与模块化单体的关系

很多团队真正需要的第一步,并不是微服务,而是模块化单体。

模块化单体的特征

code
┌─────────────────────────────────────────────┐
│  模块化单体应用                             │
│  ┌─────────────────────────────────────┐   │
│  │  用户模块                           │   │
│  │  - UserService                      │   │
│  │  - UserRepository                   │   │
│  │  - UserController                   │   │
│  └─────────────────────────────────────┘   │
│  ┌─────────────────────────────────────┐   │
│  │  订单模块                           │   │
│  │  - OrderService                     │   │
│  │  - OrderRepository                  │   │
│  │  - OrderController                  │   │
│  └─────────────────────────────────────┘   │
│  ┌─────────────────────────────────────┐   │
│  │  商品模块                           │   │
│  │  - ProductService                   │   │
│  │  - ProductRepository                │   │
│  │  - ProductController                │   │
│  └─────────────────────────────────────┘   │
└─────────────────────────────────────────────┘
特点:
- 单一进程
- 模块边界清晰
- 部署简单
- 事务处理容易

对比分析

对比项模块化单体微服务
部署方式整体部署独立部署
调用方式进程内调用网络调用
事务处理本地事务,简单分布式事务,复杂
运维复杂度
团队要求小团队即可需要成熟的团队和基础设施
技术栈统一可以多样化
扩容方式整体扩容按需扩容
故障隔离
学习成本

选择建议

优先选择模块化单体:

code
- 团队规模较小(< 20 人)
- 业务仍在快速试错
- 领域边界尚未稳定
- 运维与治理能力还不成熟
- 项目初期

考虑微服务:

code
- 业务复杂度高
- 团队规模大(> 20 人)
- 业务边界稳定
- 有独立的扩容诉求
- 基础设施完善

演进路径

code
第一阶段:单体应用
  ↓ 业务增长,代码复杂度提升
  
第二阶段:模块化单体
  ↓ 业务复杂度继续增长,团队扩大
  
第三阶段:微服务
  ↓ 按需拆分,逐步演进
  
第四阶段:服务网格 / 云原生

面试要点

基础概念题

Q1:什么是微服务架构?它的核心特征是什么?

参考答案:

微服务架构是一种将单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通过轻量级机制通信。

核心特征:

  1. 服务自治:独立开发、测试、部署、扩容
  2. 业务边界清晰:按业务能力组织,而非技术层
  3. 技术多样性:允许不同服务使用不同技术栈
  4. 数据独立:每个服务管理自己的数据库
  5. 基础设施自动化:高度自动化的部署、测试、监控
  6. 容错设计:假设服务会失败,设计容错机制
  7. 演进式设计:逐步演进,而非一次性设计

Q2:微服务解决了什么问题?又引入了什么新问题?

参考答案:

解决的问题:

  1. 发布耦合:独立部署,降低发布风险
  2. 扩容粒度:按需扩容,提高资源利用率
  3. 团队协作:服务与团队对应,减少协作成本
  4. 技术演进:允许渐进式技术升级

引入的新问题:

  1. 网络通信:网络延迟、超时、失败
  2. 数据一致性:分布式事务复杂
  3. 服务治理:需要注册、配置、监控等基础设施
  4. 运维复杂度:服务数量多,运维难度大
  5. 测试复杂度:需要契约测试、端到端测试

Q3:微服务拆分的核心原则是什么?

参考答案:

  1. 按业务能力拆分:基于领域边界,而非技术层或数据库表
  2. 高内聚、低耦合:服务内部高内聚,服务间低耦合
  3. 数据归属明确:每个服务管理自己的数据,避免共享数据库
  4. 先粗后细:从粗粒度开始,逐步细化
  5. 链路长度适中:同步链路不要过长,非核心流程异步化

Q4:微服务和 SOA 的区别?

参考答案:

特性SOA微服务
服务粒度粗粒度细粒度
通信方式ESB(企业服务总线)轻量级协议(HTTP/REST)
治理方式集中式治理去中心化治理
数据管理共享数据库每个服务独立数据库
技术栈统一多样化
部署方式依赖 ESB独立部署

Q5:如何保证微服务的数据一致性?

参考答案:

微服务架构中,数据一致性主要通过最终一致性实现:

常见方案:

  1. Saga 模式

    • 将分布式事务拆分为多个本地事务
    • 每个步骤有对应的补偿操作
    • 适用于长事务
  2. TCC(Try-Confirm-Cancel)

    • Try:预留资源
    • Confirm:确认提交
    • Cancel:取消预留
    • 适用于金融场景
  3. 本地消息表

    • 业务操作和消息写入在同一个事务
    • 定时任务扫描并发送消息
    • 消费者保证幂等性
  4. 事务消息

    • RocketMQ 提供事务消息机制
    • 半消息 + 提交/回滚

核心原则:

  • 核心流程同步保证必要校验
  • 非核心流程异步化
  • 接受最终一致性
  • 设计幂等性和补偿机制

实战理解题

Q1:如何判断是否应该使用微服务架构?

参考答案:

应该考虑的因素:

  1. 业务复杂度

    • 高复杂度:考虑微服务
    • 低复杂度:单体或模块化单体
  2. 团队规模

    • 大团队(> 20 人):微服务
    • 小团队(< 10 人):单体
  3. 业务稳定性

    • 稳定:微服务
    • 快速试错:单体
  4. 扩容需求

    • 独立扩容需求明显:微服务
    • 整体扩容即可:单体
  5. 基础设施

    • 完善的 CI/CD、监控、日志:微服务
    • 基础设施不完善:单体

推荐路径:

code
单体应用 → 模块化单体 → 微服务 → 云原生

不要为了"先进"而选择微服务,要根据实际情况选择合适的架构。


Q2:微服务架构中,如何设计 API 网关?

参考答案:

网关职责:

  1. 路由转发:将请求路由到对应的服务
  2. 认证授权:统一的身份认证和权限校验
  3. 限流熔断:保护后端服务
  4. 协议转换:HTTP → gRPC、SOAP → REST
  5. 日志监控:请求日志、指标统计
  6. 灰度发布:流量控制和分流

技术选型:

  • Spring Cloud Gateway:Spring Cloud 生态,功能丰富
  • Kong:基于 Nginx,高性能
  • APISIX:Apache 项目,云原生

设计要点:

  1. 无状态:网关不存储业务状态
  2. 高可用:多实例部署,负载均衡
  3. 性能优化:缓存、异步非阻塞
  4. 安全加固:防止 SQL 注入、XSS、CSRF

Q3:如何进行微服务的性能优化?

参考答案:

优化维度:

  1. 网络优化

    • 减少同步调用链路长度
    • 使用 gRPC 替代 HTTP(高性能场景)
    • 启用 HTTP/2
    • 使用连接池
  2. 缓存优化

    • 多级缓存(本地缓存 + 分布式缓存)
    • 热点数据预热
    • 缓存穿透、击穿、雪崩防护
  3. 数据库优化

    • 读写分离
    • 分库分表
    • 索引优化
    • 慢查询治理
  4. 异步化

    • 非核心流程异步化
    • 使用消息队列解耦
    • 削峰填谷
  5. 服务治理

    • 熔断降级
    • 限流保护
    • 服务隔离

Q4:如何设计微服务的灰度发布方案?

参考答案:

灰度发布策略:

  1. 基于权重

    yaml
    # Istio VirtualService
    http:
    - route:
      - destination:
          host: user-service
          subset: v1
        weight: 90
      - destination:
          host: user-service
          subset: v2
        weight: 10
  2. 基于请求头

    yaml
    http:
    - match:
      - headers:
          canary:
            exact: "true"
      route:
      - destination:
          host: user-service
          subset: v2
    - route:
      - destination:
          host: user-service
          subset: v1
  3. 基于 Cookie

发布流程:

code
1. 部署新版本(v2)
2. 内部测试(100% 流量到 v2,仅限测试用户)
3. 小流量灰度(5% → 10% → 30% → 50%)
4. 全量发布(100%)
5. 下线旧版本(v1)

监控指标:

  • 错误率
  • 响应时间
  • 业务指标(转化率、订单量)

回滚策略:

  • 快速回滚(调整流量权重)
  • 保留旧版本足够时间(至少 24 小时)

下一步学习

继续深入微服务相关主题:


本节小结:

  • 微服务是一种围绕业务能力组织系统的架构方式,强调服务自治、边界清晰、独立部署
  • 微服务解决了发布耦合、扩容粒度、团队协作、技术演进等问题
  • 微服务引入了网络通信、数据一致性、服务治理、运维复杂度等新问题
  • 服务拆分应基于业务能力(DDD),遵循高内聚低耦合、数据独立、先粗后细的原则
  • 微服务需要完善的基础设施:服务发现、配置中心、网关、链路追踪、监控告警
  • 数据一致性通过最终一致性实现,常见方案有 Saga、TCC、本地消息表
  • 微服务不是默认最优解,模块化单体往往是更理性的阶段性选择
  • 成功的微服务需要技术、协作、组织三方面的配套建设

版本差异(Spring Cloud 旧版 → 2025.x)

特性旧版(本文编写时)当前(Spring Cloud 2025.x / Boot 3.5.x)
架构组件Eureka/Ribbon/Hystrix/Zuul(已停止维护)LoadBalancer/Gateway/Resilience4j/Nacos
版本对应Hoxton/2020.x + Boot 2.x + JDK 82025.x + Boot 3.5.x + JDK 17+
云原生初步支持全面云原生(K8s、虚拟线程、GraalVM 支持)
链路追踪Sleuth + ZipkinMicrometer Tracing + Zipkin/OTel

本文为通用微服务概念讲解,架构思想长期有效;落地时请采用 Spring Cloud 2025.x + Spring Boot 3.5.x 技术栈(JDK 17+)。