高扩展-微服务架构演进
从单体应用到微服务架构,是现代软件系统扩展性演进的必经之路。微服务架构通过将复杂系统拆分为多个独立的小服务,实现了更好的扩展性、灵活性和团队协作效率。
然而,微服务并非银弹,盲目拆分反而会带来更大的复杂度。本文将深入探讨微服务架构的演进路径、拆分原则和实践经验,帮助你做出正确的架构决策。
# 一、架构演进的必然性
# 1、单体架构的局限
单体应用(Monolithic Application)是指所有功能模块都在一个应用中的架构模式。
┌─────────────────────────────────────┐
│ 单体应用 (WAR/JAR) │
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │用户模块 │ │订单模块 │ │
│ └─────────┘ └─────────┘ │
│ ┌─────────┐ ┌─────────┐ │
│ │商品模块 │ │支付模块 │ │
│ └─────────┘ └─────────┘ │
│ │
│ 共享数据库 │
└─────────────────────────────────────┘
单体架构的问题:
① 扩展性差:
- 只能整体扩展,无法针对性扩展高负载模块
- 一个模块需要扩展,整个应用都要复制
② 部署风险高:
- 修改一行代码,整个应用都要重新部署
- 部署周期长,发布窗口大
③ 技术栈固化:
- 所有模块必须使用同一技术栈
- 升级框架版本影响整个系统
④ 团队协作困难:
- 多个团队修改同一代码库,冲突频繁
- 代码耦合严重,改动影响面大
⑤ 故障隔离差:
- 一个模块出问题,整个应用不可用
- 内存泄漏会拖垮整个系统
# 2、架构演进的典型路径
阶段1: 单体应用
↓ (业务增长,团队扩大)
阶段2: 单体应用 + 垂直拆分
↓ (用户量暴增,性能瓶颈)
阶段3: SOA 服务化
↓ (业务复杂度提升)
阶段4: 微服务架构
↓ (云原生转型)
阶段5: Service Mesh
# 3、何时考虑微服务
需要微服务的信号:
| 问题 | 描述 | 影响 |
|---|---|---|
| 部署频率低 | 每月只能发布1-2次 | 业务迭代缓慢 |
| 团队规模大 | 10人以上在同一代码库协作 | 冲突频繁,效率低 |
| 启动时间长 | 应用启动超过5分钟 | 开发调试效率低 |
| 扩展粒度粗 | 只有少数模块高负载,却要整体扩展 | 资源浪费 |
| 技术债务重 | 代码耦合严重,改动风险大 | 维护成本高 |
| 故障影响大 | 局部问题导致整体不可用 | 可用性差 |
不需要微服务的场景:
- ❌ 团队规模小于10人
- ❌ 业务逻辑简单,CRUD为主
- ❌ 用户量不大(DAU < 10万)
- ❌ 团队缺乏分布式系统经验
- ❌ 基础设施不完善(监控、日志、链路追踪)
# 二、微服务架构的核心特征
# 1、服务自治
每个微服务都是一个独立的业务单元:
- 独立的代码库
- 独立的数据库
- 独立的部署周期
- 独立的技术选型
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 用户服务 │ │ 订单服务 │ │ 商品服务 │
│ │ │ │ │ │
│ Spring Boot │ │ Go + Gin │ │ Node.js │
│ MySQL │ │ PostgreSQL │ │ MongoDB │
└──────────────┘ └──────────────┘ └──────────────┘
# 2、按业务能力拆分
基于领域驱动设计(DDD)思想,按业务边界拆分:
电商系统拆分:
┌─────────────────────────────────────────┐
│ 用户中心 │ 商品中心 │ 订单中心 │
│ 账户服务 │ 商品服务 │ 订单服务 │
│ 认证服务 │ 库存服务 │ 支付服务 │
│ 权限服务 │ 分类服务 │ 物流服务 │
└─────────────────────────────────────────┘
# 3、去中心化治理
数据去中心化:
- 每个服务管理自己的数据
- 避免共享数据库
- 通过 API 访问其他服务的数据
❌ 共享数据库:
[用户服务] ─┐
├─→ [共享数据库]
[订单服务] ─┘
✅ 独立数据库:
[用户服务] → [用户DB]
[订单服务] → [订单DB]
│
└─ RPC ─→ [用户服务] (获取用户信息)
技术去中心化:
- 各团队自主选择技术栈
- 使用统一的通信协议(HTTP/gRPC)
- 遵守统一的 API 规范
# 4、自动化部署
微服务数量多,必须实现自动化:
- CI/CD 流水线
- 容器化部署(Docker)
- 容器编排(Kubernetes)
- 基础设施即代码(Terraform)
# 5、故障隔离
舱壁模式(Bulkhead Pattern):
// 为不同的服务配置独立的线程池
@Bean
public ThreadPoolTaskExecutor userServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("user-service-");
return executor;
}
@Bean
public ThreadPoolTaskExecutor orderServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(200);
executor.setThreadNamePrefix("order-service-");
return executor;
}
熔断降级:
@Service
public class OrderService {
@Autowired
private UserServiceClient userServiceClient;
// 用户服务故障时,使用降级逻辑
@HystrixCommand(fallbackMethod = "getUserFallback")
public User getUser(Long userId) {
return userServiceClient.getById(userId);
}
public User getUserFallback(Long userId) {
// 返回默认用户信息
User user = new User();
user.setId(userId);
user.setUsername("用户" + userId);
return user;
}
}
# 三、服务拆分原则
# 1、单一职责原则
每个服务只负责一个业务领域:
❌ 职责不清晰:
用户服务:
- 用户注册
- 用户登录
- 订单管理 ← 不属于用户领域
- 商品收藏 ← 不属于用户领域
✅ 职责明确:
用户服务:
- 用户注册
- 用户登录
- 用户信息管理
订单服务:
- 订单创建
- 订单管理
收藏服务:
- 商品收藏
- 收藏管理
# 2、高内聚低耦合
高内聚: 相关功能放在同一服务。
✅ 商品服务(高内聚):
- 商品CRUD
- 商品详情
- 商品搜索
- 商品分类
低耦合: 服务间依赖尽可能少。
❌ 强耦合:
订单服务 → 用户服务 → 权限服务 → 角色服务
↓
商品服务 → 库存服务 → 仓库服务
✅ 低耦合:
订单服务 → 用户服务(只获取基本信息)
→ 商品服务(只获取基本信息)
# 3、业务边界清晰
基于 DDD 的限界上下文(Bounded Context)拆分:
电商系统的限界上下文:
┌─────────────────────────────────────────────┐
│ 电商系统 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │用户上下文│ │商品上下文│ │交易上下文│ │
│ │ │ │ │ │ │ │
│ │ 用户 │ │ 商品 │ │ 订单 │ │
│ │ 账户 │ │ 分类 │ │ 支付 │ │
│ │ 认证 │ │ 库存 │ │ 物流 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────┘
聚合根识别:
// 订单聚合根
@Entity
public class Order {
@Id
private Long id;
private Long userId; // 不直接关联 User 实体
@OneToMany(cascade = CascadeType.ALL)
private List<OrderItem> items; // 订单项是订单的一部分
private OrderStatus status;
}
// 订单项(值对象)
@Embeddable
public class OrderItem {
private Long productId; // 不直接关联 Product 实体
private String productName;
private Integer quantity;
private BigDecimal price;
}
# 4、数据独立性
每个服务拥有独立的数据库:
-- 用户服务数据库
CREATE DATABASE user_service;
USE user_service;
CREATE TABLE users (...);
CREATE TABLE accounts (...);
-- 订单服务数据库
CREATE DATABASE order_service;
USE order_service;
CREATE TABLE orders (...);
CREATE TABLE order_items (...);
-- 商品服务数据库
CREATE DATABASE product_service;
USE product_service;
CREATE TABLE products (...);
CREATE TABLE categories (...);
数据冗余:
为了避免跨服务查询,适当冗余数据:
// 订单服务保存商品快照
@Entity
public class OrderItem {
private Long productId;
// 冗余商品信息(下单时的快照)
private String productName;
private String productImage;
private BigDecimal productPrice;
}
# 5、团队自治
康威定律: 系统架构反映组织的沟通结构。
组织结构:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 用户团队 │ │ 商品团队 │ │ 订单团队 │
│ (5人) │ │ (8人) │ │ (10人) │
└──────────┘ └──────────┘ └──────────┘
对应的服务:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 用户服务 │ │ 商品服务 │ │ 订单服务 │
│ │ │ │ │ │
└──────────┘ └──────────┘ └──────────┘
# 6、拆分粒度适中
过度拆分的问题:
- 服务数量爆炸,运维成本高
- 服务间调用链过长,性能下降
- 分布式事务难以处理
粒度建议:
- 单个服务代码量: 1万-5万行
- 服务团队规模: 2-10人(两个披萨团队)
- 服务启动时间: < 1分钟
- 服务数据库表数: 5-20张
# 四、服务拆分实战
# 1、识别服务边界
步骤 1: 领域建模
使用事件风暴(Event Storming)识别领域:
电商系统事件流:
用户注册 → 浏览商品 → 加入购物车 → 下单 → 支付 → 发货 → 收货 → 评价
领域识别:
- 用户域: 用户注册、用户登录
- 商品域: 浏览商品、商品详情
- 购物车域: 加入购物车、购物车管理
- 订单域: 下单、订单管理
- 支付域: 支付、退款
- 物流域: 发货、收货、物流查询
- 评价域: 商品评价
步骤 2: 分析依赖关系
依赖关系图:
┌──────────┐
│ 用户服务 │ ← 认证基础服务
└──────────┘
↑
│
┌──────────┐ ┌──────────┐
│ 订单服务 │ ←─→ │ 商品服务 │
└──────────┘ └──────────┘
│ ↑
↓ │
┌──────────┐ ┌──────────┐
│ 支付服务 │ │ 库存服务 │
└──────────┘ └──────────┘
│
↓
┌──────────┐
│ 物流服务 │
└──────────┘
步骤 3: 确定拆分顺序
优先拆分:
- ✅ 变更频繁的模块
- ✅ 性能瓶颈模块
- ✅ 依赖少的模块
- ✅ 边界清晰的模块
延后拆分:
- ❌ 核心复杂业务模块
- ❌ 依赖关系复杂的模块
- ❌ 变更不频繁的模块
# 2、单体应用拆分示例
原单体应用结构:
e-commerce-monolith/
├── src/main/java/com/example/
│ ├── user/
│ │ ├── controller/
│ │ ├── service/
│ │ └── repository/
│ ├── product/
│ │ ├── controller/
│ │ ├── service/
│ │ └── repository/
│ ├── order/
│ │ ├── controller/
│ │ ├── service/
│ │ └── repository/
│ └── payment/
│ ├── controller/
│ ├── service/
│ └── repository/
└── application.yml (共享配置)
拆分后的微服务结构:
microservices/
├── user-service/
│ ├── src/main/java/com/example/user/
│ ├── application.yml
│ └── Dockerfile
├── product-service/
│ ├── src/main/java/com/example/product/
│ ├── application.yml
│ └── Dockerfile
├── order-service/
│ ├── src/main/java/com/example/order/
│ ├── application.yml
│ └── Dockerfile
└── payment-service/
├── src/main/java/com/example/payment/
├── application.yml
└── Dockerfile
# 3、数据库拆分
阶段 1: 逻辑拆分(Schema 隔离)
-- 同一数据库实例,不同 Schema
CREATE SCHEMA user_schema;
CREATE SCHEMA product_schema;
CREATE SCHEMA order_schema;
-- 应用连接不同 Schema
user-service:
datasource:
url: jdbc:mysql://localhost:3306/user_schema
product-service:
datasource:
url: jdbc:mysql://localhost:3306/product_schema
阶段 2: 物理拆分(独立数据库)
# 不同的数据库实例
user-service:
datasource:
url: jdbc:mysql://user-db:3306/user_service
product-service:
datasource:
url: jdbc:mysql://product-db:3306/product_service
order-service:
datasource:
url: jdbc:mysql://order-db:3306/order_service
# 4、共享代码处理
抽取公共库:
common-lib/
├── common-core/ # 核心工具类
│ ├── Result.java
│ ├── PageResult.java
│ └── Constants.java
├── common-redis/ # Redis 封装
│ └── RedisService.java
├── common-security/ # 安全组件
│ ├── JwtTokenProvider.java
│ └── SecurityConfig.java
└── common-api/ # API 定义
├── UserDTO.java
└── ProductDTO.java
服务引用公共库:
<!-- user-service pom.xml -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>common-core</artifactId>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>common-security</artifactId>
</dependency>
</dependencies>
# 五、微服务通信模式
# 1、同步通信
RESTful API:
// 商品服务提供 API
@RestController
@RequestMapping("/api/products")
public class ProductController {
@GetMapping("/{id}")
public Result<ProductDTO> getProduct(@PathVariable Long id) {
Product product = productService.getById(id);
return Result.success(ProductMapper.toDTO(product));
}
}
// 订单服务调用商品服务
@Service
public class OrderService {
@Autowired
private RestTemplate restTemplate;
public Order createOrder(CreateOrderRequest request) {
// 调用商品服务获取商品信息
String url = "http://product-service/api/products/" + request.getProductId();
ProductDTO product = restTemplate.getForObject(url, ProductDTO.class);
// 创建订单
Order order = new Order();
order.setProductId(product.getId());
order.setProductName(product.getName());
order.setPrice(product.getPrice());
return orderRepository.save(order);
}
}
gRPC:
// product.proto
syntax = "proto3";
service ProductService {
rpc GetProduct(GetProductRequest) returns (ProductResponse);
}
message GetProductRequest {
int64 id = 1;
}
message ProductResponse {
int64 id = 1;
string name = 2;
double price = 3;
}
// 订单服务调用商品服务(gRPC)
@Service
public class OrderService {
@Autowired
private ProductServiceGrpc.ProductServiceBlockingStub productStub;
public Order createOrder(CreateOrderRequest request) {
// gRPC 调用
ProductResponse product = productStub.getProduct(
GetProductRequest.newBuilder()
.setId(request.getProductId())
.build()
);
Order order = new Order();
order.setProductId(product.getId());
order.setProductName(product.getName());
order.setPrice(product.getPrice());
return orderRepository.save(order);
}
}
# 2、异步通信
基于消息队列:
// 订单服务发送订单创建事件
@Service
public class OrderService {
@Autowired
private RabbitTemplate rabbitTemplate;
public Order createOrder(CreateOrderRequest request) {
Order order = new Order();
order.setUserId(request.getUserId());
order.setProductId(request.getProductId());
order.setStatus(OrderStatus.PENDING);
orderRepository.save(order);
// 发送订单创建事件
OrderCreatedEvent event = new OrderCreatedEvent();
event.setOrderId(order.getId());
event.setUserId(order.getUserId());
event.setProductId(order.getProductId());
rabbitTemplate.convertAndSend("order.exchange", "order.created", event);
return order;
}
}
// 库存服务监听订单创建事件
@Component
public class OrderEventListener {
@Autowired
private InventoryService inventoryService;
@RabbitListener(queues = "inventory.order.created")
public void handleOrderCreated(OrderCreatedEvent event) {
// 扣减库存
inventoryService.decreaseStock(event.getProductId(), event.getQuantity());
}
}
// 物流服务监听订单创建事件
@Component
public class OrderEventListener {
@Autowired
private ShippingService shippingService;
@RabbitListener(queues = "shipping.order.created")
public void handleOrderCreated(OrderCreatedEvent event) {
// 创建物流单
shippingService.createShippingOrder(event.getOrderId());
}
}
# 3、服务发现
使用 Nacos:
# 商品服务注册到 Nacos
spring:
application:
name: product-service
cloud:
nacos:
discovery:
server-addr: nacos-server:8848
namespace: production
group: DEFAULT_GROUP
// 订单服务通过服务名调用商品服务
@Service
public class OrderService {
@Autowired
private RestTemplate restTemplate; // 已配置 @LoadBalanced
public Order createOrder(CreateOrderRequest request) {
// 使用服务名(自动负载均衡)
String url = "http://product-service/api/products/" + request.getProductId();
ProductDTO product = restTemplate.getForObject(url, ProductDTO.class);
// ...
}
}
# 4、API 网关
统一入口:
客户端
│
↓
┌──────────────┐
│ API Gateway │ (Spring Cloud Gateway / Kong)
└──────────────┘
│
├─→ [用户服务]
├─→ [商品服务]
├─→ [订单服务]
└─→ [支付服务]
Spring Cloud Gateway 配置:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
- id: product-service
uri: lb://product-service
predicates:
- Path=/api/products/**
filters:
- StripPrefix=1
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1
网关功能:
- ✅ 路由转发
- ✅ 负载均衡
- ✅ 认证鉴权
- ✅ 限流熔断
- ✅ 日志监控
- ✅ 协议转换
# 六、数据一致性解决方案
# 1、分布式事务问题
场景: 下单需要同时操作订单服务和库存服务。
下单流程:
1. 订单服务: 创建订单
2. 库存服务: 扣减库存
3. 支付服务: 创建支付单
问题: 如何保证这3个操作要么全部成功,要么全部失败?
# 2、Saga 模式
编排式 Saga:
// 订单服务(Saga 编排器)
@Service
public class OrderSagaOrchestrator {
@Autowired
private OrderRepository orderRepository;
@Autowired
private InventoryServiceClient inventoryClient;
@Autowired
private PaymentServiceClient paymentClient;
@Transactional
public Order createOrder(CreateOrderRequest request) {
// 1. 创建订单(本地事务)
Order order = new Order();
order.setStatus(OrderStatus.PENDING);
orderRepository.save(order);
try {
// 2. 调用库存服务扣减库存
inventoryClient.decreaseStock(request.getProductId(), request.getQuantity());
// 3. 调用支付服务创建支付单
paymentClient.createPayment(order.getId(), order.getAmount());
// 4. 全部成功,更新订单状态
order.setStatus(OrderStatus.CONFIRMED);
orderRepository.save(order);
return order;
} catch (Exception e) {
// 补偿操作
try {
inventoryClient.increaseStock(request.getProductId(), request.getQuantity());
} catch (Exception ex) {
log.error("库存回滚失败", ex);
}
order.setStatus(OrderStatus.FAILED);
orderRepository.save(order);
throw new OrderCreateException("订单创建失败", e);
}
}
}
事件驱动式 Saga:
// 1. 订单服务: 创建订单并发送事件
@Service
public class OrderService {
@Autowired
private RabbitTemplate rabbitTemplate;
@Transactional
public Order createOrder(CreateOrderRequest request) {
Order order = new Order();
order.setStatus(OrderStatus.PENDING);
orderRepository.save(order);
// 发送订单创建事件
OrderCreatedEvent event = new OrderCreatedEvent(order.getId(), request);
rabbitTemplate.convertAndSend("saga.exchange", "order.created", event);
return order;
}
}
// 2. 库存服务: 监听事件并扣减库存
@Component
public class InventorySagaListener {
@RabbitListener(queues = "saga.inventory.order.created")
@Transactional
public void handleOrderCreated(OrderCreatedEvent event) {
try {
inventoryService.decreaseStock(event.getProductId(), event.getQuantity());
// 发送库存扣减成功事件
InventoryDecreasedEvent successEvent = new InventoryDecreasedEvent(event.getOrderId());
rabbitTemplate.convertAndSend("saga.exchange", "inventory.decreased", successEvent);
} catch (Exception e) {
// 发送库存扣减失败事件
InventoryDecreaseFailedEvent failEvent = new InventoryDecreaseFailedEvent(event.getOrderId());
rabbitTemplate.convertAndSend("saga.exchange", "inventory.decrease.failed", failEvent);
}
}
}
// 3. 订单服务: 监听库存扣减结果
@Component
public class OrderSagaListener {
@RabbitListener(queues = "saga.order.inventory.decreased")
@Transactional
public void handleInventoryDecreased(InventoryDecreasedEvent event) {
// 库存扣减成功,继续下一步(调用支付服务)
PaymentCreateEvent paymentEvent = new PaymentCreateEvent(event.getOrderId());
rabbitTemplate.convertAndSend("saga.exchange", "payment.create", paymentEvent);
}
@RabbitListener(queues = "saga.order.inventory.failed")
@Transactional
public void handleInventoryFailed(InventoryDecreaseFailedEvent event) {
// 库存扣减失败,订单标记为失败
Order order = orderRepository.findById(event.getOrderId()).orElseThrow();
order.setStatus(OrderStatus.FAILED);
orderRepository.save(order);
}
}
# 3、最终一致性
本地消息表:
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private OutboxEventRepository outboxRepository;
@Transactional
public Order createOrder(CreateOrderRequest request) {
// 1. 创建订单
Order order = new Order();
order.setStatus(OrderStatus.PENDING);
orderRepository.save(order);
// 2. 保存待发送事件到本地消息表(同一事务)
OutboxEvent event = new OutboxEvent();
event.setEventType("ORDER_CREATED");
event.setPayload(JSON.toJSONString(order));
event.setStatus(EventStatus.PENDING);
outboxRepository.save(event);
return order;
}
}
// 定时任务:扫描本地消息表并发送事件
@Component
public class OutboxEventPublisher {
@Autowired
private OutboxEventRepository outboxRepository;
@Autowired
private RabbitTemplate rabbitTemplate;
@Scheduled(fixedDelay = 5000)
@Transactional
public void publishPendingEvents() {
List<OutboxEvent> pendingEvents = outboxRepository.findByStatus(EventStatus.PENDING);
for (OutboxEvent event : pendingEvents) {
try {
rabbitTemplate.convertAndSend("order.exchange", event.getEventType(), event.getPayload());
event.setStatus(EventStatus.PUBLISHED);
outboxRepository.save(event);
} catch (Exception e) {
log.error("发送事件失败: {}", event.getId(), e);
}
}
}
}
# 4、TCC 模式
// Try-Confirm-Cancel 模式
public interface InventoryTccService {
/**
* Try: 预留库存
*/
@Tcc(confirmMethod = "confirmDecrease", cancelMethod = "cancelDecrease")
boolean tryDecrease(Long productId, Integer quantity);
/**
* Confirm: 确认扣减库存
*/
boolean confirmDecrease(Long productId, Integer quantity);
/**
* Cancel: 释放预留库存
*/
boolean cancelDecrease(Long productId, Integer quantity);
}
@Service
public class InventoryTccServiceImpl implements InventoryTccService {
@Override
public boolean tryDecrease(Long productId, Integer quantity) {
// 冻结库存
Inventory inventory = inventoryRepository.findByProductId(productId);
inventory.setFrozen(inventory.getFrozen() + quantity);
inventory.setAvailable(inventory.getAvailable() - quantity);
inventoryRepository.save(inventory);
return true;
}
@Override
public boolean confirmDecrease(Long productId, Integer quantity) {
// 确认扣减
Inventory inventory = inventoryRepository.findByProductId(productId);
inventory.setFrozen(inventory.getFrozen() - quantity);
inventoryRepository.save(inventory);
return true;
}
@Override
public boolean cancelDecrease(Long productId, Integer quantity) {
// 释放冻结库存
Inventory inventory = inventoryRepository.findByProductId(productId);
inventory.setFrozen(inventory.getFrozen() - quantity);
inventory.setAvailable(inventory.getAvailable() + quantity);
inventoryRepository.save(inventory);
return true;
}
}
# 七、微服务治理
# 1、服务限流
令牌桶算法:
@Configuration
public class RateLimitConfig {
@Bean
public RateLimiter orderRateLimiter() {
// 每秒允许100个请求
return RateLimiter.create(100);
}
}
@RestController
public class OrderController {
@Autowired
private RateLimiter rateLimiter;
@PostMapping("/orders")
public Result createOrder(@RequestBody CreateOrderRequest request) {
// 尝试获取令牌
if (!rateLimiter.tryAcquire(1, 100, TimeUnit.MILLISECONDS)) {
return Result.error("系统繁忙,请稍后重试");
}
Order order = orderService.createOrder(request);
return Result.success(order);
}
}
基于 Redis 的分布式限流:
@Component
public class DistributedRateLimiter {
@Autowired
private RedisTemplate<String, Long> redisTemplate;
/**
* 限流检查
* @param key 限流key
* @param limit 限流阈值
* @param window 时间窗口(秒)
*/
public boolean isAllowed(String key, int limit, int window) {
String redisKey = "rate_limit:" + key + ":" + (System.currentTimeMillis() / (window * 1000));
Long count = redisTemplate.opsForValue().increment(redisKey);
if (count == 1) {
redisTemplate.expire(redisKey, window, TimeUnit.SECONDS);
}
return count <= limit;
}
}
# 2、服务熔断
使用 Resilience4j:
@Service
public class OrderService {
@Autowired
private ProductServiceClient productClient;
@CircuitBreaker(name = "productService", fallbackMethod = "getProductFallback")
@Retry(name = "productService")
@TimeLimiter(name = "productService")
public ProductDTO getProduct(Long productId) {
return productClient.getById(productId);
}
public ProductDTO getProductFallback(Long productId, Exception e) {
log.warn("商品服务调用失败,使用降级数据, productId={}", productId, e);
// 返回默认商品信息
ProductDTO product = new ProductDTO();
product.setId(productId);
product.setName("商品" + productId);
product.setPrice(BigDecimal.ZERO);
return product;
}
}
配置:
resilience4j:
circuitbreaker:
instances:
productService:
registerHealthIndicator: true
slidingWindowSize: 10 # 滑动窗口大小
minimumNumberOfCalls: 5 # 最小调用次数
failureRateThreshold: 50 # 失败率阈值50%
waitDurationInOpenState: 10s # 熔断后等待10秒
permittedNumberOfCallsInHalfOpenState: 3
retry:
instances:
productService:
maxAttempts: 3 # 最大重试3次
waitDuration: 1s # 重试间隔1秒
timelimiter:
instances:
productService:
timeoutDuration: 3s # 超时时间3秒
# 3、链路追踪
使用 SkyWalking:
# application.yml
skywalking:
agent:
service_name: ${spring.application.name}
collector:
backend_service: skywalking-oap:11800
自定义 Span:
@Service
public class OrderService {
@Autowired
private Tracer tracer;
public Order createOrder(CreateOrderRequest request) {
Span span = tracer.createEntrySpan("createOrder", null);
try {
span.tag("user_id", request.getUserId().toString());
span.tag("product_id", request.getProductId().toString());
// 业务逻辑
Order order = doCreateOrder(request);
span.tag("order_id", order.getId().toString());
return order;
} catch (Exception e) {
span.errorOccurred();
span.log(e);
throw e;
} finally {
tracer.stopSpan();
}
}
}
# 4、日志聚合
ELK Stack:
应用服务 → Filebeat → Logstash → Elasticsearch → Kibana
Logback 配置:
<configuration>
<appender name="JSON" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"service":"${spring.application.name}"}</customFields>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="JSON" />
</root>
</configuration>
结构化日志:
@Slf4j
@Service
public class OrderService {
public Order createOrder(CreateOrderRequest request) {
String traceId = MDC.get("traceId");
log.info("创建订单开始, traceId={}, userId={}, productId={}",
traceId, request.getUserId(), request.getProductId());
try {
Order order = doCreateOrder(request);
log.info("创建订单成功, traceId={}, orderId={}", traceId, order.getId());
return order;
} catch (Exception e) {
log.error("创建订单失败, traceId={}, userId={}", traceId, request.getUserId(), e);
throw e;
}
}
}
# 5、配置中心
使用 Nacos Config:
# bootstrap.yml
spring:
application:
name: order-service
cloud:
nacos:
config:
server-addr: nacos-server:8848
namespace: production
group: DEFAULT_GROUP
file-extension: yaml
shared-configs:
- data-id: common-config.yaml
refresh: true
动态刷新配置:
@RefreshScope
@RestController
public class ConfigController {
@Value("${business.max-order-amount}")
private BigDecimal maxOrderAmount;
@Value("${business.discount-rate}")
private BigDecimal discountRate;
@GetMapping("/config")
public Map<String, Object> getConfig() {
Map<String, Object> config = new HashMap<>();
config.put("maxOrderAmount", maxOrderAmount);
config.put("discountRate", discountRate);
return config;
}
}
# 八、部署与运维
# 1、容器化
Dockerfile:
FROM openjdk:17-jdk-alpine
WORKDIR /app
COPY target/order-service-1.0.0.jar app.jar
ENV JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseG1GC"
EXPOSE 8080
ENTRYPOINT java $JAVA_OPTS -jar app.jar
Docker Compose(本地开发):
version: '3.8'
services:
user-service:
build: ./user-service
ports:
- "8081:8080"
environment:
- SPRING_PROFILES_ACTIVE=dev
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/user_service
depends_on:
- mysql
- redis
product-service:
build: ./product-service
ports:
- "8082:8080"
environment:
- SPRING_PROFILES_ACTIVE=dev
depends_on:
- mysql
- redis
order-service:
build: ./order-service
ports:
- "8083:8080"
environment:
- SPRING_PROFILES_ACTIVE=dev
depends_on:
- mysql
- redis
mysql:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=root123
volumes:
- mysql-data:/var/lib/mysql
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
volumes:
mysql-data:
redis-data:
# 2、Kubernetes 部署
Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
labels:
app: order-service
spec:
replicas: 3
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: myregistry/order-service:1.0.0
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: "production"
- name: SPRING_CLOUD_NACOS_DISCOVERY_SERVER_ADDR
value: "nacos-server:8848"
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
Service:
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
HPA(自动扩缩容):
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: order-service-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: order-service
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
# 3、CI/CD 流水线
GitLab CI:
# .gitlab-ci.yml
stages:
- build
- test
- package
- deploy
variables:
MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
build:
stage: build
image: maven:3.8-openjdk-17
script:
- mvn clean compile
cache:
paths:
- .m2/repository
test:
stage: test
image: maven:3.8-openjdk-17
script:
- mvn test
coverage: '/Total.*?([0-9]{1,3})%/'
package:
stage: package
image: maven:3.8-openjdk-17
script:
- mvn package -DskipTests
- docker build -t myregistry/order-service:$CI_COMMIT_SHA .
- docker push myregistry/order-service:$CI_COMMIT_SHA
only:
- master
deploy-production:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl set image deployment/order-service order-service=myregistry/order-service:$CI_COMMIT_SHA
- kubectl rollout status deployment/order-service
only:
- master
when: manual
# 4、灰度发布
基于 Istio 的金丝雀发布:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: order-service
spec:
hosts:
- order-service
http:
- match:
- headers:
x-canary:
exact: "true"
route:
- destination:
host: order-service
subset: v2
- route:
- destination:
host: order-service
subset: v1
weight: 90
- destination:
host: order-service
subset: v2
weight: 10
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: order-service
spec:
host: order-service
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
# 九、监控告警
# 1、监控体系
四个黄金指标:
| 指标 | 说明 | 阈值 |
|---|---|---|
| 延迟(Latency) | 请求响应时间 | P99 < 200ms |
| 流量(Traffic) | 每秒请求数(QPS) | 根据容量规划 |
| 错误(Errors) | 错误率 | < 0.1% |
| 饱和度(Saturation) | 资源使用率 | CPU < 70%, Memory < 80% |
Prometheus + Grafana:
# application.yml
management:
endpoints:
web:
exposure:
include: "*"
metrics:
export:
prometheus:
enabled: true
tags:
application: ${spring.application.name}
自定义指标:
@Component
public class OrderMetrics {
private final Counter orderCreatedCounter;
private final Timer orderCreateTimer;
private final Gauge orderPendingGauge;
public OrderMetrics(MeterRegistry registry) {
this.orderCreatedCounter = Counter.builder("orders.created")
.description("订单创建总数")
.tag("service", "order-service")
.register(registry);
this.orderCreateTimer = Timer.builder("orders.create.time")
.description("订单创建耗时")
.tag("service", "order-service")
.register(registry);
this.orderPendingGauge = Gauge.builder("orders.pending", this, OrderMetrics::getPendingCount)
.description("待处理订单数")
.register(registry);
}
public void recordOrderCreated() {
orderCreatedCounter.increment();
}
public void recordOrderCreateTime(Runnable task) {
orderCreateTimer.record(task);
}
private double getPendingCount() {
// 查询待处理订单数
return orderRepository.countByStatus(OrderStatus.PENDING);
}
}
# 2、告警规则
Prometheus AlertManager:
groups:
- name: order-service-alerts
interval: 30s
rules:
# 错误率告警
- alert: HighErrorRate
expr: rate(http_server_requests_seconds_count{status=~"5.."}[5m]) > 0.01
for: 5m
labels:
severity: critical
annotations:
summary: "服务错误率过高"
description: "{{ $labels.application }} 错误率超过1%, 当前值: {{ $value }}"
# 响应时间告警
- alert: HighLatency
expr: histogram_quantile(0.99, rate(http_server_requests_seconds_bucket[5m])) > 0.2
for: 5m
labels:
severity: warning
annotations:
summary: "服务响应时间过长"
description: "{{ $labels.application }} P99延迟超过200ms, 当前值: {{ $value }}"
# CPU 使用率告警
- alert: HighCPUUsage
expr: process_cpu_usage > 0.8
for: 10m
labels:
severity: warning
annotations:
summary: "CPU使用率过高"
description: "{{ $labels.application }} CPU使用率超过80%, 当前值: {{ $value }}"
# 内存使用率告警
- alert: HighMemoryUsage
expr: jvm_memory_used_bytes / jvm_memory_max_bytes > 0.9
for: 10m
labels:
severity: critical
annotations:
summary: "内存使用率过高"
description: "{{ $labels.application }} 内存使用率超过90%, 当前值: {{ $value }}"
# 十、常见问题与解决方案
# 1、服务雪崩
问题: 一个服务故障导致级联失败。
解决方案:
- ✅ 熔断降级(Hystrix/Resilience4j)
- ✅ 超时控制
- ✅ 限流保护
- ✅ 舱壁隔离
# 2、链路过长
问题: A → B → C → D → E,调用链过长导致延迟累加。
解决方案:
- ✅ 异步化:使用消息队列解耦
- ✅ 服务聚合:在网关层聚合多个服务
- ✅ 数据冗余:减少跨服务调用
# 3、数据一致性
问题: 分布式事务难以保证。
解决方案:
- ✅ 最终一致性(本地消息表、事务消息)
- ✅ Saga 模式
- ✅ TCC 模式
- ✅ 业务补偿
# 4、服务数量爆炸
问题: 微服务拆分过细,服务数量过多。
解决方案:
- ✅ 合理的拆分粒度(单个服务1-5万行代码)
- ✅ 服务合并:将相关服务合并
- ✅ 服务分层:核心服务 + 聚合服务
# 5、测试复杂度
问题: 微服务环境下集成测试困难。
解决方案:
- ✅ 契约测试(Pact)
- ✅ 服务虚拟化(WireMock)
- ✅ 完善的单元测试
- ✅ 自动化测试流水线
# 十一、总结
# 微服务的核心价值
- 独立部署: 每个服务独立发布,互不影响
- 技术异构: 不同服务可以使用不同技术栈
- 故障隔离: 单个服务故障不影响整体
- 按需扩展: 根据负载情况独立扩展
- 团队自治: 小团队独立开发和维护
# 架构演进建议
| 阶段 | 建议 |
|---|---|
| 初创期 | 单体应用,快速迭代 |
| 成长期 | 垂直拆分,模块化 |
| 扩张期 | 核心服务微服务化 |
| 成熟期 | 全面微服务,云原生 |
# 最佳实践
- 渐进式演进: 不要一次性全部拆分
- 业务优先: 先拆分变更频繁的业务
- 监控先行: 完善的监控体系是基础
- 自动化: CI/CD、测试、部署全自动化
- 团队能力: 团队必须具备分布式系统经验
# 微服务不是银弹
适合微服务:
- ✅ 大型复杂系统
- ✅ 高并发高流量
- ✅ 团队规模大
- ✅ 快速迭代需求
不适合微服务:
- ❌ 小型简单系统
- ❌ 团队规模小
- ❌ 缺乏运维能力
- ❌ 业务不稳定
微服务架构是现代软件系统扩展性的最佳实践,但也带来了复杂度的提升。只有在正确的场景下,采用正确的方式实施,才能真正发挥微服务的价值。
祝你变得更强!