CSDN分布式系统深度实战系列 :一个电商平台从单体架构 到分布式微服务架构 的全过程演进。涵盖技术选型、架构设计、数据迁移、性能优化 四大核心模块,每个阶段都配有真实的业务场景、架构图和性能数据对比。通过订单系统、库存系统、支付系统等核心模块的演进案例,展示如何构建高可用、可扩展的电商平台架构。建议⭐收藏⭐,架构演进时随时参考!
🏗️ 电商平台架构演进全景图
单体架构 垂直拆分 分布式服务 微服务架构 云原生架构 LAMP堆栈 单一数据库 用户服务 商品服务 订单服务 服务化 消息队列 缓存集群 服务网格 容器化 CI/CD Service Mesh Serverless AIOps
一、🚀 第一阶段:单体架构(日订单<1000)
1.1 技术栈与架构设计
java
// 单体应用结构 - Spring Boot + MySQL
@SpringBootApplication
public class MonolithEcommerceApplication {
public static void main(String[] args) {
SpringApplication.run(MonolithEcommerceApplication.class, args);
}
}
// 单体应用包结构
src/main/java/com/ebusiness/
├── controller/ # 控制层
│ ├── UserController.java
│ ├── ProductController.java
│ └── OrderController.java
├── service/ # 业务层
│ ├── UserService.java
│ ├── ProductService.java
│ └── OrderService.java
├── repository/ # 数据层
│ ├── UserRepository.java
│ ├── ProductRepository.java
│ └── OrderRepository.java
└── entity/ # 实体类
├── User.java
├── Product.java
└── Order.java
1.2 数据库设计
sql
-- 单一数据库设计
CREATE DATABASE ecommerce_monolith;
-- 用户表
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password_hash VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_username (username),
INDEX idx_email (email)
);
-- 商品表
CREATE TABLE products (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(200) NOT NULL,
price DECIMAL(10,2) NOT NULL,
stock INT NOT NULL,
category_id BIGINT,
status TINYINT DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_category (category_id),
INDEX idx_status (status)
);
-- 订单表
CREATE TABLE orders (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
total_amount DECIMAL(10,2) NOT NULL,
status ENUM('PENDING','PAID','SHIPPED','COMPLETED','CANCELLED') DEFAULT 'PENDING',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
INDEX idx_user_id (user_id),
INDEX idx_status (status),
INDEX idx_created_at (created_at)
);
-- 订单项表
CREATE TABLE order_items (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_id BIGINT NOT NULL,
product_id BIGINT NOT NULL,
quantity INT NOT NULL,
price DECIMAL(10,2) NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(id),
FOREIGN KEY (product_id) REFERENCES products(id),
INDEX idx_order_id (order_id)
);
1.3 核心业务逻辑
java
@Service
@Transactional
@Slf4j
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private ProductRepository productRepository;
@Autowired
private UserRepository userRepository;
/**
* 创建订单 - 单体架构下的简单实现
*/
public Order createOrder(OrderRequest request) {
// 1. 验证用户
User user = userRepository.findById(request.getUserId())
.orElseThrow(() -> new BusinessException("用户不存在"));
// 2. 验证商品和库存
List<OrderItem> items = new ArrayList<>();
BigDecimal totalAmount = BigDecimal.ZERO;
for (OrderItemRequest itemRequest : request.getItems()) {
Product product = productRepository.findById(itemRequest.getProductId())
.orElseThrow(() -> new BusinessException("商品不存在"));
if (product.getStock() < itemRequest.getQuantity()) {
throw new BusinessException("库存不足: " + product.getName());
}
// 扣减库存
product.setStock(product.getStock() - itemRequest.getQuantity());
productRepository.save(product);
// 计算订单项
BigDecimal itemTotal = product.getPrice().multiply(
BigDecimal.valueOf(itemRequest.getQuantity()));
totalAmount = totalAmount.add(itemTotal);
OrderItem item = new OrderItem();
item.setProductId(product.getId());
item.setQuantity(itemRequest.getQuantity());
item.setPrice(product.getPrice());
items.add(item);
}
// 3. 创建订单
Order order = new Order();
order.setUserId(user.getId());
order.setTotalAmount(totalAmount);
order.setStatus(OrderStatus.PENDING);
order.setItems(items);
Order savedOrder = orderRepository.save(order);
log.info("订单创建成功: {}", savedOrder.getId());
return savedOrder;
}
}
二、💡 第二阶段:垂直拆分(日订单1万-10万)
2.1 服务拆分策略
java
// 用户服务 - 独立部署
@Service
@Slf4j
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private RedisTemplate<String, User> redisTemplate;
private static final String USER_CACHE_PREFIX = "user:";
private static final Duration CACHE_TTL = Duration.ofHours(1);
public User getUser(Long userId) {
// 缓存优化
String cacheKey = USER_CACHE_PREFIX + userId;
User user = redisTemplate.opsForValue().get(cacheKey);
if (user != null) {
return user;
}
user = userRepository.findById(userId)
.orElseThrow(() -> new BusinessException("用户不存在"));
redisTemplate.opsForValue().set(cacheKey, user, CACHE_TTL);
return user;
}
}
// 商品服务 - 独立部署
@Service
@Slf4j
public class ProductService {
@Autowired
private ProductRepository productRepository;
@Autowired
private RedisTemplate<String, Product> redisTemplate;
/**
* 商品查询 - 加入缓存和搜索优化
*/
public Page<Product> searchProducts(ProductQuery query, Pageable pageable) {
// 复杂的商品搜索逻辑
Specification<Product> spec = (root, criteriaQuery, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
if (StringUtils.isNotBlank(query.getKeyword())) {
Predicate namePredicate = criteriaBuilder.like(
root.get("name"), "%" + query.getKeyword() + "%");
Predicate descPredicate = criteriaBuilder.like(
root.get("description"), "%" + query.getKeyword() + "%");
predicates.add(criteriaBuilder.or(namePredicate, descPredicate));
}
if (query.getCategoryId() != null) {
predicates.add(criteriaBuilder.equal(
root.get("categoryId"), query.getCategoryId()));
}
if (query.getMinPrice() != null && query.getMaxPrice() != null) {
predicates.add(criteriaBuilder.between(
root.get("price"), query.getMinPrice(), query.getMaxPrice()));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
};
return productRepository.findAll(spec, pageable);
}
}
2.2 数据库垂直拆分
sql
-- 用户数据库
CREATE DATABASE user_db;
CREATE TABLE users (...); -- 同单体架构,但独立数据库
-- 商品数据库
CREATE DATABASE product_db;
CREATE TABLE products (...);
CREATE TABLE categories (...);
CREATE TABLE product_skus (...);
-- 订单数据库
CREATE DATABASE order_db;
CREATE TABLE orders (...);
CREATE TABLE order_items (...);
2.3 服务间通信 - RESTful API
java
// 订单服务调用用户服务
@Service
public class OrderService {
@Autowired
private RestTemplate restTemplate;
private static final String USER_SERVICE_URL = "http://user-service/api/users";
private static final String PRODUCT_SERVICE_URL = "http://product-service/api/products";
/**
* 跨服务创建订单
*/
public Order createOrderDistributed(OrderRequest request) {
// 1. 调用用户服务验证用户
User user = restTemplate.getForObject(
USER_SERVICE_URL + "/" + request.getUserId(),
User.class
);
if (user == null) {
throw new BusinessException("用户不存在");
}
// 2. 调用商品服务验证库存
for (OrderItemRequest itemRequest : request.getItems()) {
ProductStock stock = restTemplate.getForObject(
PRODUCT_SERVICE_URL + "/" + itemRequest.getProductId() + "/stock",
ProductStock.class
);
if (stock.getAvailable() < itemRequest.getQuantity()) {
throw new BusinessException("库存不足");
}
}
// 3. 创建订单(本地事务)
return createOrderLocal(request);
}
}
三、⚡ 第三阶段:分布式服务(日订单10万-100万)
3.1 服务注册与发现
yaml
# Spring Cloud Eureka 配置
eureka:
client:
service-url:
defaultZone: http://eureka1:8761/eureka,http://eureka2:8762/eureka
register-with-eureka: true
fetch-registry: true
instance:
hostname: ${spring.application.name}
prefer-ip-address: true
# 应用配置
spring:
application:
name: order-service
cloud:
loadbalancer:
ribbon:
enabled: true
3.2 分布式事务 - Saga模式
java
// Saga模式实现分布式事务
@Service
@Slf4j
public class OrderSagaService {
@Autowired
private InventoryService inventoryService;
@Autowired
private PaymentService paymentService;
@Autowired
private ShippingService shippingService;
@Autowired
private SagaCoordinator sagaCoordinator;
/**
* 创建订单Saga事务
*/
@Saga
public OrderResult createOrderSaga(OrderRequest request) {
SagaExecution saga = new SagaExecution("create-order");
try {
// 步骤1: 预留库存
saga.addStep("reserve-inventory", () -> {
inventoryService.reserveStock(request.getItems());
}, () -> {
inventoryService.releaseStock(request.getItems());
});
// 步骤2: 创建订单
saga.addStep("create-order", () -> {
return orderRepository.save(buildOrder(request));
}, (order) -> {
orderRepository.delete(order);
});
// 步骤3: 处理支付
saga.addStep("process-payment", () -> {
paymentService.processPayment(request.getPaymentInfo());
}, (payment) -> {
paymentService.refundPayment(payment);
});
// 执行Saga
return saga.execute();
} catch (SagaException e) {
log.error("订单创建Saga失败", e);
// 执行补偿操作
saga.compensate();
throw new BusinessException("订单创建失败");
}
}
}
3.3 消息队列异步化
java
// 订单创建消息生产者
@Component
@Slf4j
public class OrderEventProducer {
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 发送订单创建事件
*/
public void sendOrderCreatedEvent(Order order) {
OrderCreatedEvent event = new OrderCreatedEvent();
event.setOrderId(order.getId());
event.setUserId(order.getUserId());
event.setTotalAmount(order.getTotalAmount());
event.setItems(order.getItems());
event.setCreateTime(order.getCreatedAt());
rocketMQTemplate.convertAndSend("ORDER_CREATED_TOPIC", event);
log.info("订单创建事件发送成功: {}", order.getId());
}
}
// 库存扣减消费者
@Component
@RocketMQMessageListener(
topic = "ORDER_CREATED_TOPIC",
consumerGroup = "inventory-consumer-group"
)
@Slf4j
public class InventoryDeductionConsumer implements RocketMQListener<OrderCreatedEvent> {
@Autowired
private InventoryService inventoryService;
@Override
public void onMessage(OrderCreatedEvent event) {
try {
log.info("收到订单创建事件,开始扣减库存: {}", event.getOrderId());
inventoryService.deductStock(event.getOrderId(), event.getItems());
log.info("库存扣减成功: {}", event.getOrderId());
} catch (Exception e) {
log.error("库存扣减失败: {}", event.getOrderId(), e);
// 重试或人工处理
throw new RuntimeException("库存扣减失败", e);
}
}
}
四、🏗️ 第四阶段:微服务架构(日订单100万+)
4.1 领域驱动设计(DDD)
java
// 订单聚合根
@Entity
@AggregateRoot
@Data
public class Order {
@Id
private Long id;
private Long userId;
private BigDecimal totalAmount;
private OrderStatus status;
private List<OrderItem> items;
private Address shippingAddress;
private PaymentInfo paymentInfo;
/**
* 创建订单 - 领域逻辑
*/
public static Order create(Long userId, List<OrderItem> items, Address address) {
Order order = new Order();
order.id = IdGenerator.nextId();
order.userId = userId;
order.items = items;
order.shippingAddress = address;
order.status = OrderStatus.PENDING;
order.totalAmount = calculateTotalAmount(items);
// 领域事件
order.addDomainEvent(new OrderCreatedEvent(order.id, order.userId));
return order;
}
/**
* 支付订单
*/
public void pay(PaymentInfo paymentInfo) {
if (this.status != OrderStatus.PENDING) {
throw new IllegalStateException("订单状态异常");
}
this.paymentInfo = paymentInfo;
this.status = OrderStatus.PAID;
this.addDomainEvent(new OrderPaidEvent(this.id));
}
}
// 订单领域服务
@Service
@DomainService
@Slf4j
public class OrderDomainService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private DomainEventPublisher eventPublisher;
/**
* 处理订单创建
*/
@Transactional
public Order handleOrderCreation(CreateOrderCommand command) {
// 验证业务规则
validateBusinessRules(command);
// 创建订单聚合
Order order = Order.create(
command.getUserId(),
command.getItems(),
command.getShippingAddress()
);
// 保存聚合
orderRepository.save(order);
// 发布领域事件
eventPublisher.publishAll(order.getDomainEvents());
order.clearDomainEvents();
return order;
}
}
4.2 服务网格与治理
yaml
# Istio VirtualService - 订单服务路由
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: order-service
spec:
hosts:
- order-service
http:
- match:
- headers:
version:
exact: canary
route:
- destination:
host: order-service
subset: canary
weight: 10
- route:
- destination:
host: order-service
subset: stable
weight: 90
retries:
attempts: 3
perTryTimeout: 2s
timeout: 10s
# DestinationRule - 负载均衡策略
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: order-service
spec:
host: order-service
subsets:
- name: stable
labels:
version: stable
trafficPolicy:
loadBalancer:
simple: LEAST_CONN
- name: canary
labels:
version: canary
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
4.3 数据分片与读写分离
java
// 订单分片策略
@Component
@Slf4j
public class OrderShardingStrategy {
private static final int SHARD_COUNT = 16;
private static final int TABLE_COUNT_PER_SHARD = 64;
/**
* 根据用户ID计算分片
*/
public String calculateShard(Long userId) {
int shardIndex = (int) (userId % SHARD_COUNT);
return "order_db_" + shardIndex;
}
/**
* 根据订单ID计算表名
*/
public String calculateTableName(Long orderId) {
int tableIndex = (int) (orderId % TABLE_COUNT_PER_SHARD);
return "orders_" + tableIndex;
}
}
// 分片数据源路由
@Component
public class OrderDataSourceRouter extends AbstractRoutingDataSource {
@Autowired
private OrderShardingStrategy shardingStrategy;
@Override
protected Object determineCurrentLookupKey() {
Long userId = OrderContextHolder.getCurrentUserId();
if (userId == null) {
return "order_db_0"; // 默认分片
}
return shardingStrategy.calculateShard(userId);
}
}
五、📊 性能优化实战
5.1 缓存策略优化
java
// 多级缓存实现
@Service
@Slf4j
public class MultiLevelCacheService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 本地缓存
private Cache<String, Object> localCache = Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
/**
* 获取订单信息 - 多级缓存
*/
public Order getOrderWithCache(Long orderId) {
String cacheKey = "order:" + orderId;
// 1. 查询本地缓存
Order order = (Order) localCache.getIfPresent(cacheKey);
if (order != null) {
log.debug("命中本地缓存: {}", orderId);
return order;
}
// 2. 查询Redis缓存
order = (Order) redisTemplate.opsForValue().get(cacheKey);
if (order != null) {
log.debug("命中Redis缓存: {}", orderId);
localCache.put(cacheKey, order);
return order;
}
// 3. 查询数据库
order = orderRepository.findById(orderId);
if (order != null) {
// 异步写入缓存
CompletableFuture.runAsync(() -> {
redisTemplate.opsForValue().set(cacheKey, order, Duration.ofHours(1));
localCache.put(cacheKey, order);
});
}
return order;
}
}
5.2 数据库优化
sql
-- 订单表分片后索引优化
CREATE TABLE order_db_0.orders_0 (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL,
-- ... 其他字段
INDEX idx_user_id (user_id),
INDEX idx_status_created (status, created_at),
INDEX idx_user_created (user_id, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 读写分离配置
-- 写库
spring:
datasource:
write:
url: jdbc:mysql://master-db:3306/order_db_0
username: write_user
password: write_pass
-- 读库
spring:
datasource:
read:
url: jdbc:mysql://slave-db:3306/order_db_0
username: read_user
password: read_pass
六、🔧 监控与运维
6.1 全链路监控
yaml
# 应用监控配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
probes:
enabled: true
metrics:
export:
prometheus:
enabled: true
# 自定义业务指标
@Component
public class OrderMetrics {
private final MeterRegistry meterRegistry;
private final Counter orderCreatedCounter;
private final Timer orderProcessTimer;
private final Gauge activeOrdersGauge;
public OrderMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.orderCreatedCounter = Counter.builder("order.created")
.description("订单创建数量")
.register(meterRegistry);
this.orderProcessTimer = Timer.builder("order.process.duration")
.description("订单处理耗时")
.publishPercentiles(0.5, 0.95, 0.99)
.register(meterRegistry);
}
public void recordOrderCreated() {
orderCreatedCounter.increment();
}
}
6.2 日志追踪
java
@Aspect
@Component
@Slf4j
public class LoggingAspect {
@Around("execution(* com.ebusiness..service..*(..))")
public Object logMethodExecution(ProceedingJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
long startTime = System.currentTimeMillis();
try {
log.info("开始执行: {}.{}", className, methodName);
Object result = joinPoint.proceed();
long duration = System.currentTimeMillis() - startTime;
log.info("执行完成: {}.{}, 耗时: {}ms", className, methodName, duration);
return result;
} catch (Exception e) {
log.error("执行失败: {}.{}, 错误: {}", className, methodName, e.getMessage());
throw e;
}
}
}
七、🚀 架构演进总结
7.1 性能数据对比
架构阶段 | QPS | 平均响应时间 | 可用性 | 扩展性 |
---|---|---|---|---|
单体架构 | 500 | 100ms | 99.5% | 差 |
垂直拆分 | 5,000 | 50ms | 99.9% | 中等 |
分布式服务 | 50,000 | 30ms | 99.95% | 良好 |
微服务架构 | 500,000 | 20ms | 99.99% | 优秀 |
7.2 技术债务与演进成本
java
// 架构演进检查清单
@Component
public class ArchitectureReviewChecklist {
/**
* 检查是否需要进行架构演进
*/
public ArchitectureReviewResult reviewCurrentArchitecture(SystemMetrics metrics) {
List<String> recommendations = new ArrayList<>();
// QPS检查
if (metrics.getQps() > 1000 && metrics.getCurrentArchitecture() == Architecture.MONOLITH) {
recommendations.add("考虑垂直拆分,QPS已超过单体架构承载能力");
}
// 响应时间检查
if (metrics.getAvgResponseTime() > 100) {
recommendations.add("响应时间过长,考虑引入缓存和异步处理");
}
// 可用性检查
if (metrics.getAvailability() < 99.9) {
recommendations.add("可用性不足,需要引入容错机制和冗余设计");
}
return new ArchitectureReviewResult(recommendations, getRecommendedArchitecture(metrics));
}
private Architecture getRecommendedArchitecture(SystemMetrics metrics) {
if (metrics.getQps() < 1000) return Architecture.MONOLITH;
if (metrics.getQps() < 10000) return Architecture.VERTICAL_SPLIT;
if (metrics.getQps() < 100000) return Architecture.DISTRIBUTED;
return Architecture.MICROSERVICES;
}
}
💎 总结与最佳实践
架构演进原则
- 渐进式演进:不要一步到位,按需演进
- 数据驱动决策:基于性能指标决定演进时机
- 风险控制:每次演进都要有回滚方案
- 团队能力匹配:架构复杂度与团队能力相适应
技术选型建议
- 初创阶段:单体架构 + 简单缓存
- 成长阶段:服务拆分 + 消息队列
- 成熟阶段:微服务 + 服务网格
- 大规模阶段:云原生 + 多集群
💬 互动话题:你在电商平台架构演进中遇到过哪些挑战?是如何解决的?欢迎在评论区分享经验!
👉 下一篇预告 :《高并发秒杀系统设计:从理论到实践》
(点击关注第一时间获取更新通知)
🎁 文末福利
关注+私信回复"电商架构"获取:
- 📚 完整架构演进脑图(PDF版)
- 🛠️ 各阶段配置模板
- 📊 性能压测脚本
- 💻 监控Dashboard配置