文章目录
- [基于Spring Cloud Alibaba的微服务电商项目全流程实战(高并发+高可用+一致性保障)](#基于Spring Cloud Alibaba的微服务电商项目全流程实战(高并发+高可用+一致性保障))
-
- 一、需求分析
-
- [1. 业务需求](#1. 业务需求)
- [2. 技术需求](#2. 技术需求)
- 二、数据库表设计(按服务拆分)
-
- [1. 数据库拆分原则](#1. 数据库拆分原则)
- [2. 核心表结构(MySQL)](#2. 核心表结构(MySQL))
-
- [三、技术栈选型(Spring Cloud Alibaba生态)](#三、技术栈选型(Spring Cloud Alibaba生态))
- 四、微服务架构设计
-
- [1. 架构分层(从上到下)](#1. 架构分层(从上到下))
- [2. 服务拆分原则](#2. 服务拆分原则)
- [3. 核心链路调用流程](#3. 核心链路调用流程)
- 五、核心微服务开发实现
-
- [1. 通用基础配置(所有服务依赖)](#1. 通用基础配置(所有服务依赖))
-
- [(1)pom.xml核心依赖(Spring Boot 2.7.x + Spring Cloud Alibaba 2021.0.4.0)](#(1)pom.xml核心依赖(Spring Boot 2.7.x + Spring Cloud Alibaba 2021.0.4.0))
- (2)bootstrap.yml(连接Nacos配置中心)
- [2. 用户服务(user-service)](#2. 用户服务(user-service))
-
- [3. 商品服务(product-service)](#3. 商品服务(product-service))
-
- [(1)核心功能:商品缓存(Cache Aside Pattern)](#(1)核心功能:商品缓存(Cache Aside Pattern))
- [4. 库存服务(inventory-service)](#4. 库存服务(inventory-service))
-
- [5. 订单服务(order-service)](#5. 订单服务(order-service))
-
- [6. 支付服务(pay-service)](#6. 支付服务(pay-service))
-
- 六、服务注册与配置中心(Nacos实战)
-
- [1. Nacos部署(Docker方式)](#1. Nacos部署(Docker方式))
- [2. Nacos配置中心使用](#2. Nacos配置中心使用)
-
- [七、网关层设计(Sentinel Gateway)](#七、网关层设计(Sentinel Gateway))
-
- [1. 网关配置(application.yml)](#1. 网关配置(application.yml))
- [2. 统一鉴权过滤器](#2. 统一鉴权过滤器)
- 八、分布式事务一致性保障(Seata实战)
-
- [1. Seata部署(Docker)](#1. Seata部署(Docker))
- [2. Seata配置(registry.conf)](#2. Seata配置(registry.conf))
- [3. 微服务集成Seata(application.yml)](#3. 微服务集成Seata(application.yml))
- [4. 分布式事务模式选择](#4. 分布式事务模式选择)
- 九、缓存问题全解(Redis+一致性+防雪崩)
-
- [1. 缓存三大问题解决方案](#1. 缓存三大问题解决方案)
- [2. 缓存一致性(Cache Aside Pattern)](#2. 缓存一致性(Cache Aside Pattern))
- 十、中间件选型与使用
-
- [1. RocketMQ(消息队列)](#1. RocketMQ(消息队列))
-
- [2. Redis(缓存+分布式锁)](#2. Redis(缓存+分布式锁))
-
- [3. Sharding-JDBC(分库分表)](#3. Sharding-JDBC(分库分表))
-
- 十一、核心业务实现
-
- [1. 订单超时自动取消(两种方案对比)](#1. 订单超时自动取消(两种方案对比))
- [2. 库存防超卖(三重保障)](#2. 库存防超卖(三重保障))
- 十二、特殊场景优化(秒杀/高并发)
-
- [1. 秒杀场景优化方案](#1. 秒杀场景优化方案)
-
- [2. 接口幂等性(防重复提交)](#2. 接口幂等性(防重复提交))
- 十三、环境配置与部署(Docker+K8s)
-
- [1. Docker镜像构建(Dockerfile)](#1. Docker镜像构建(Dockerfile))
- [2. K8s部署配置(order-service-deployment.yaml)](#2. K8s部署配置(order-service-deployment.yaml))
- [3. 部署流程](#3. 部署流程)
- 十四、监控与运维
-
- [1. 全链路监控(Prometheus+Grafana)](#1. 全链路监控(Prometheus+Grafana))
-
- [2. 日志收集(ELK)](#2. 日志收集(ELK))
- [3. 告警机制](#3. 告警机制)
- 总结
基于Spring Cloud Alibaba的微服务电商项目全流程实战(高并发+高可用+一致性保障)
若对您有帮助的话,请点赞收藏加关注哦,您的关注是我持续创作的动力!有问题请私信或联系邮箱:funian.gm@gmail.com
一、需求分析
1. 业务需求
| 核心模块 |
核心功能 |
| 用户服务 |
注册/登录(JWT鉴权)、用户信息管理、地址管理 |
| 商品服务 |
商品CRUD、分类管理、商品上下架、库存关联 |
| 订单服务 |
订单创建、订单状态流转、订单查询、超时取消 |
| 库存服务 |
库存扣减、库存锁定、库存回滚、防超卖 |
| 支付服务 |
对接支付宝/微信支付、支付回调、退款处理 |
| 秒杀服务 |
秒杀商品发布、限流削峰、异步下单 |
| 网关服务 |
路由转发、限流熔断、统一鉴权、日志收集 |
2. 技术需求
- 高并发:支持秒杀场景10万QPS,普通下单1万QPS
- 高可用:服务可用性99.99%,核心链路无单点故障
- 一致性:分布式事务保证订单-库存-支付数据一致
- 可扩展:支持水平扩容,应对流量峰值
- 安全性:接口幂等性、防SQL注入、防缓存穿透/击穿/雪崩
- 可监控:全链路监控、告警机制(响应时间>3s告警)
二、数据库表设计(按服务拆分)
1. 数据库拆分原则
- 每个微服务独立数据库,避免跨库联查
- 核心表设计冗余字段(如订单表存商品名称/价格,避免查商品库)
- 分库分表:订单表、商品表按规则拆分(Sharding-JDBC)
2. 核心表结构(MySQL)
(1)用户服务数据库(user_db)
| 表名 |
核心字段 |
索引设计 |
| user |
id(PK)、username、password(加密)、phone、status |
username(唯一)、phone(唯一) |
| user_address |
id(PK)、user_id(FK)、receiver、phone、address |
user_id(普通索引) |
(2)商品服务数据库(product_db)
| 表名 |
核心字段 |
索引设计 |
| product |
id(PK)、name、price、stock、status、category_id |
category_id(普通)、name(模糊索引) |
| product_category |
id(PK)、name、parent_id、level |
parent_id(普通) |
(3)订单服务数据库(order_db)
| 表名 |
核心字段 |
索引设计 |
| order_main |
id(PK)、order_sn(订单号)、user_id、total_amount、status、create_time |
order_sn(唯一)、user_id(普通)、create_time(普通) |
| order_item |
id(PK)、order_id(FK)、product_id、product_name、price、quantity |
order_id(普通)、product_id(普通) |
| message_queue |
id(PK)、order_id、message、status(0未发送1已发送)、create_time |
order_id(普通)、status(普通) |
(4)库存服务数据库(inventory_db)
| 表名 |
核心字段 |
索引设计 |
| inventory |
id(PK)、product_id、stock、locked_stock(锁定库存) |
product_id(唯一) |
| inventory_log |
id(PK)、product_id、operate_type(1扣减2回滚)、quantity、order_id |
product_id(普通)、order_id(普通) |
(5)支付服务数据库(pay_db)
| 表名 |
核心字段 |
索引设计 |
| payment |
id(PK)、order_sn、user_id、pay_amount、pay_type(1支付宝2微信)、status |
order_sn(唯一)、user_id(普通) |
| refund |
id(PK)、payment_id(FK)、refund_amount、status、refund_time |
payment_id(普通) |
三、技术栈选型(Spring Cloud Alibaba生态)
| 技术分层 |
选型组件 |
核心作用 |
| 微服务框架 |
Spring Cloud Alibaba |
微服务生态核心(整合各类组件) |
| 注册中心 |
Nacos |
服务注册与发现(支持健康检查) |
| 配置中心 |
Nacos Config |
动态配置、环境隔离(dev/test/prod) |
| 网关 |
Sentinel Gateway |
路由转发、限流、熔断、鉴权 |
| RPC通信 |
Dubbo |
高性能RPC调用(替代OpenFeign,支持负载均衡) |
| 熔断降级 |
Sentinel |
服务熔断、降级、限流(支持注解式配置) |
| 分布式事务 |
Seata |
保证订单-库存-支付一致性(TCC/AT模式) |
| 缓存 |
Redis(集群) |
商品缓存、分布式锁、会话缓存 |
| 消息队列 |
RocketMQ |
异步通信、延迟队列(订单超时)、削峰 |
| 数据库 |
MySQL(主从复制) |
业务数据存储(主写从读) |
| 分库分表 |
Sharding-JDBC |
订单表/商品表水平拆分(应对大数据量) |
| 分布式锁 |
Redisson |
库存扣减防超卖、秒杀锁 |
| 鉴权 |
JWT |
无状态登录鉴权(替代Session) |
| 监控 |
Prometheus+Grafana |
全链路指标监控(QPS/响应时间/错误率) |
| 日志 |
ELK(Elasticsearch+Logstash+Kibana) |
日志收集与分析 |
| 部署 |
Docker+K8s |
容器化部署、自动扩缩容 |
四、微服务架构设计
1. 架构分层(从上到下)
复制代码
客户端层(APP/小程序/PC)→ CDN(静态资源加速)→ 网关层(Sentinel Gateway)→ 微服务层 → 中间件层 → 基础设施层
2. 服务拆分原则
- 单一职责:每个服务只负责一个核心领域(如订单服务只处理订单相关)
- 高内聚低耦合:服务内部逻辑紧密,服务间通过接口通信
- 数据自治:每个服务独立管理自己的数据库,不跨库操作
- 可独立部署:服务之间无依赖,支持单独扩容/升级
3. 核心链路调用流程
复制代码
下单流程:用户→网关→订单服务(创建订单)→ Dubbo调用库存服务(预扣库存)→ Dubbo调用支付服务(发起支付)→ 支付回调→订单服务(更新状态)→ 库存服务(确认扣减)
五、核心微服务开发实现
1. 通用基础配置(所有服务依赖)
(1)pom.xml核心依赖(Spring Boot 2.7.x + Spring Cloud Alibaba 2021.0.4.0)
xml
复制代码
<!-- Spring Cloud Alibaba 核心依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.4.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Nacos 注册中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Nacos 配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- Dubbo RPC -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!-- Sentinel 熔断降级 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- Seata 分布式事务 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
(2)bootstrap.yml(连接Nacos配置中心)
yaml
复制代码
spring:
application:
name: order-service # 服务名(对应Nacos配置)
cloud:
nacos:
discovery:
server-addr: 192.168.1.100:8848 # Nacos注册中心地址
config:
server-addr: 192.168.1.100:8848 # Nacos配置中心地址
file-extension: yaml # 配置文件格式
namespace: dev # 环境隔离(dev/test/prod)
group: ORDER_GROUP # 配置分组(按服务分组)
dubbo:
registry:
address: nacos://192.168.1.100:8848 # Dubbo基于Nacos服务发现
protocol:
name: dubbo
port: -1 # 随机端口
2. 用户服务(user-service)
(1)核心功能:JWT鉴权
java
复制代码
// JWT工具类
@Component
public class JwtUtil {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expire}")
private long expire;
// 生成Token
public String generateToken(Long userId) {
Date now = new Date();
Date expireDate = new Date(now.getTime() + expire * 1000);
return Jwts.builder()
.setSubject(userId.toString())
.setIssuedAt(now)
.setExpiration(expireDate)
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
}
// 验证Token
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
// 从Token中获取用户ID
public Long getUserIdFromToken(String token) {
Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
return Long.parseLong(claims.getSubject());
}
}
(2)登录接口
java
复制代码
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private JwtUtil jwtUtil;
@PostMapping("/login")
public Result<String> login(@RequestBody LoginDTO loginDTO) {
// 验证用户名密码(省略加密校验逻辑)
User user = userService.getUserByUsername(loginDTO.getUsername());
if (user == null || !user.getPassword().equals(loginDTO.getPassword())) {
return Result.fail("用户名或密码错误");
}
// 生成JWT Token
String token = jwtUtil.generateToken(user.getId());
return Result.success(token);
}
}
3. 商品服务(product-service)
(1)核心功能:商品缓存(Cache Aside Pattern)
java
复制代码
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductMapper productMapper;
@Autowired
private StringRedisTemplate redisTemplate;
private static final String CACHE_KEY_PRODUCT = "product:";
// 查询商品详情(缓存优先)
@Override
public Product getProductById(Long productId) {
// 1. 查缓存
String key = CACHE_KEY_PRODUCT + productId;
String json = redisTemplate.opsForValue().get(key);
if (StrUtil.isNotBlank(json)) {
return JSONUtil.toBean(json, Product.class);
}
// 2. 缓存未命中,查数据库
Product product = productMapper.selectById(productId);
if (product != null) {
// 3. 存入缓存(过期时间1小时,加随机值防雪崩)
redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(product),
3600 + new Random().nextInt(600), TimeUnit.SECONDS);
} else {
// 4. 缓存空值(防穿透)
redisTemplate.opsForValue().set(key, "", 60, TimeUnit.SECONDS);
}
return product;
}
// 更新商品(更新数据库+删除缓存)
@Override
@Transactional
public boolean updateProduct(Product product) {
// 1. 更新数据库
boolean success = productMapper.updateById(product) > 0;
if (success) {
// 2. 删除缓存(避免缓存脏数据)
String key = CACHE_KEY_PRODUCT + product.getId();
redisTemplate.delete(key);
}
return success;
}
}
4. 库存服务(inventory-service)
(1)核心功能:库存扣减(防超卖+分布式锁)
java
复制代码
@Service
public class InventoryServiceImpl implements InventoryService {
@Autowired
private InventoryMapper inventoryMapper;
@Autowired
private RedissonClient redissonClient;
private static final String LOCK_KEY_INVENTORY = "lock:inventory:";
// 预扣库存(TCC模式的Try方法)
@Override
public boolean deductStock(Long productId, Integer quantity, String orderId) {
// 1. 分布式锁(Redisson),防止并发超卖
RLock lock = redissonClient.getLock(LOCK_KEY_INVENTORY + productId);
lock.lock(30, TimeUnit.SECONDS); // 锁超时30秒
try {
// 2. 查库存(带行锁,避免幻读)
Inventory inventory = inventoryMapper.selectByProductIdForUpdate(productId);
if (inventory == null || inventory.getStock() < quantity) {
return false; // 库存不足
}
// 3. 预扣库存(锁定库存增加,可用库存减少)
inventory.setStock(inventory.getStock() - quantity);
inventory.setLockedStock(inventory.getLockedStock() + quantity);
// 4. 记录库存日志(用于回滚)
InventoryLog log = new InventoryLog();
log.setProductId(productId);
log.setQuantity(quantity);
log.setOrderId(orderId);
log.setOperateType(1); // 1=扣减
inventoryLogMapper.insert(log);
return inventoryMapper.updateById(inventory) > 0;
} finally {
lock.unlock(); // 释放锁
}
}
// 确认扣减(TCC模式的Confirm方法)
@Override
public boolean confirmDeduct(Long productId, Integer quantity) {
// 无需操作,TCC最终确认(实际可清理日志)
return true;
}
// 回滚库存(TCC模式的Cancel方法)
@Override
public boolean cancelDeduct(Long productId, Integer quantity, String orderId) {
RLock lock = redissonClient.getLock(LOCK_KEY_INVENTORY + productId);
lock.lock(30, TimeUnit.SECONDS);
try {
// 回滚库存:可用库存增加,锁定库存减少
Inventory inventory = inventoryMapper.selectById(productId);
inventory.setStock(inventory.getStock() + quantity);
inventory.setLockedStock(inventory.getLockedStock() - quantity);
// 记录回滚日志
InventoryLog log = new InventoryLog();
log.setProductId(productId);
log.setQuantity(quantity);
log.setOrderId(orderId);
log.setOperateType(2); // 2=回滚
inventoryLogMapper.insert(log);
return inventoryMapper.updateById(inventory) > 0;
} finally {
lock.unlock();
}
}
}
5. 订单服务(order-service)
(1)核心功能:创建订单(整合Seata TCC分布式事务)
java
复制代码
// 订单TCC接口(本地事务接口)
public interface OrderTccService {
// Try:创建订单(待支付)+ 预扣库存
@TwoPhaseBusinessAction(name = "createOrderTcc", commitMethod = "confirm", rollbackMethod = "cancel")
boolean tryCreateOrder(@BusinessActionContextParameter(paramName = "orderDTO") OrderDTO orderDTO, BusinessActionContext context);
// Confirm:确认订单(支付成功后)
boolean confirm(BusinessActionContext context);
// Cancel:取消订单(支付失败/超时)
boolean cancel(BusinessActionContext context);
}
@Service
public class OrderTccServiceImpl implements OrderTccService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderItemMapper orderItemMapper;
// Dubbo远程调用库存服务
@DubboReference
private InventoryService inventoryService;
@Autowired
private RocketMQTemplate rocketMQTemplate;
@Override
@Transactional
public boolean tryCreateOrder(OrderDTO orderDTO, BusinessActionContext context) {
// 1. 生成订单号
String orderSn = IdUtil.fastSimpleUUID();
// 2. 创建主订单(状态:待支付)
OrderMain orderMain = new OrderMain();
orderMain.setOrderSn(orderSn);
orderMain.setUserId(orderDTO.getUserId());
orderMain.setTotalAmount(orderDTO.getTotalAmount());
orderMain.setStatus(0); // 0=待支付
orderMapper.insert(orderMain);
// 3. 创建订单项
for (OrderItemDTO itemDTO : orderDTO.getItems()) {
OrderItem orderItem = new OrderItem();
orderItem.setOrderId(orderMain.getId());
orderItem.setProductId(itemDTO.getProductId());
orderItem.setProductName(itemDTO.getProductName());
orderItem.setPrice(itemDTO.getPrice());
orderItem.setQuantity(itemDTO.getQuantity());
orderItemMapper.insert(orderItem);
}
// 4. 远程调用库存服务预扣库存(Dubbo)
boolean deductSuccess = inventoryService.deductStock(
orderDTO.getItems().get(0).getProductId(), // 简化:单商品订单,多商品需循环
orderDTO.getItems().get(0).getQuantity(),
orderSn
);
if (!deductSuccess) {
throw new RuntimeException("库存不足");
}
// 5. 发送延迟队列(订单超时取消,30分钟延迟)
rocketMQTemplate.send("order-delay-topic",
MessageBuilder.withPayload(orderSn)
.setHeader(RocketMQHeaders.DELAY_TIME_LEVEL, 9) // RocketMQ延迟级别9=30分钟
.build());
// 6. 保存订单号到上下文(用于Confirm/Cancel)
context.setActionContext("orderSn", orderSn);
return true;
}
@Override
@Transactional
public boolean confirm(BusinessActionContext context) {
// 支付成功,更新订单状态为"已支付"
String orderSn = (String) context.getActionContext("orderSn");
OrderMain orderMain = orderMapper.selectByOrderSn(orderSn);
orderMain.setStatus(1); // 1=已支付
orderMain.setPayTime(new Date());
return orderMapper.updateById(orderMain) > 0;
}
@Override
@Transactional
public boolean cancel(BusinessActionContext context) {
// 支付失败/超时,取消订单+回滚库存
String orderSn = (String) context.getActionContext("orderSn");
// 1. 更新订单状态为"已取消"
OrderMain orderMain = orderMapper.selectByOrderSn(orderSn);
orderMain.setStatus(-1); // -1=已取消
orderMapper.updateById(orderMain);
// 2. 远程调用库存服务回滚库存
OrderItem orderItem = orderItemMapper.selectByOrderId(orderMain.getId()).get(0);
inventoryService.cancelDeduct(orderItem.getProductId(), orderItem.getQuantity(), orderSn);
return true;
}
}
(2)订单超时取消(监听RocketMQ延迟队列)
java
复制代码
@Component
@RocketMQMessageListener(topic = "order-delay-topic", consumerGroup = "order-delay-consumer")
public class OrderDelayConsumer implements RocketMQListener<String> {
@Autowired
private OrderMainMapper orderMainMapper;
@Autowired
private OrderTccService orderTccService;
@Override
public void onMessage(String orderSn) {
// 1. 查询订单状态
OrderMain orderMain = orderMainMapper.selectByOrderSn(orderSn);
if (orderMain == null) {
return;
}
// 2. 若订单仍为"待支付",触发取消逻辑
if (orderMain.getStatus() == 0) {
// 模拟Seata Cancel操作(实际通过Seata事务上下文触发)
BusinessActionContext context = new BusinessActionContext();
context.setActionContext("orderSn", orderSn);
orderTccService.cancel(context);
System.out.println("订单" + orderSn + "超时未支付,已自动取消");
}
}
}
6. 支付服务(pay-service)
(1)核心功能:对接支付宝支付
java
复制代码
@Service
public class AlipayServiceImpl implements PayService {
@Autowired
private PaymentMapper paymentMapper;
@DubboReference
private OrderTccService orderTccService;
@Value("${alipay.appId}")
private String appId;
@Value("${alipay.privateKey}")
private String privateKey;
@Value("${alipay.publicKey}")
private String publicKey;
@Value("${alipay.notifyUrl}")
private String notifyUrl;
// 发起支付宝支付
@Override
public String createAlipayOrder(String orderSn, Long userId, BigDecimal amount) {
try {
// 1. 构建支付宝客户端
AlipayClient client = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do",
appId, privateKey, "json", "UTF-8", publicKey, "RSA2");
// 2. 构建支付请求
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setReturnUrl("http://localhost:8080/pay/return"); // 同步回调地址
request.setNotifyUrl(notifyUrl); // 异步回调地址
// 3. 封装请求参数
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", orderSn); // 订单号(与订单服务一致)
bizContent.put("total_amount", amount); // 支付金额
bizContent.put("subject", "电商订单支付"); // 订单标题
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY"); // 支付产品码
request.setBizContent(bizContent.toString());
// 4. 发起请求,获取支付链接
AlipayTradePagePayResponse response = client.pageExecute(request);
if (response.isSuccess()) {
// 5. 记录支付记录
Payment payment = new Payment();
payment.setOrderSn(orderSn);
payment.setUserId(userId);
payment.setPayAmount(amount);
payment.setPayType(1); // 1=支付宝
payment.setStatus(0); // 0=待支付
paymentMapper.insert(payment);
return response.getBody(); // 返回支付宝支付页面HTML
} else {
throw new RuntimeException("支付宝支付创建失败:" + response.getMsg());
}
} catch (Exception e) {
throw new RuntimeException("支付异常", e);
}
}
// 支付宝异步回调(验证支付结果)
@Override
public String handleAlipayNotify(Map<String, String> params) {
try {
// 1. 验证签名
boolean signVerified = AlipaySignature.rsaCheckV1(
params, publicKey, "UTF-8", "RSA2");
if (!signVerified) {
return "fail"; // 签名验证失败
}
// 2. 验证支付状态
String tradeStatus = params.get("trade_status");
if (!"TRADE_SUCCESS".equals(tradeStatus)) {
return "fail";
}
// 3. 获取订单信息
String orderSn = params.get("out_trade_no");
String tradeNo = params.get("trade_no"); // 支付宝交易号
BigDecimal payAmount = new BigDecimal(params.get("total_amount"));
// 4. 更新支付记录状态
Payment payment = paymentMapper.selectByOrderSn(orderSn);
if (payment == null || payment.getStatus() != 0) {
return "fail"; // 支付记录不存在或已支付
}
payment.setStatus(1); // 1=已支付
payment.setPayTime(new Date());
payment.setTradeNo(tradeNo);
paymentMapper.updateById(payment);
// 5. 触发订单TCC Confirm操作(确认订单)
BusinessActionContext context = new BusinessActionContext();
context.setActionContext("orderSn", orderSn);
orderTccService.confirm(context);
return "success"; // 回调成功
} catch (Exception e) {
return "fail";
}
}
}
六、服务注册与配置中心(Nacos实战)
1. Nacos部署(Docker方式)
bash
复制代码
# 拉取Nacos镜像
docker pull nacos/nacos-server:v2.2.3
# 启动Nacos(单机模式)
docker run -d \
-p 8848:8848 \
-e MODE=standalone \
-e SPRING_DATASOURCE_PLATFORM=mysql \
-e MYSQL_SERVICE_HOST=192.168.1.100 \
-e MYSQL_SERVICE_PORT=3306 \
-e MYSQL_SERVICE_DB_NAME=nacos_config \
-e MYSQL_SERVICE_USER=root \
-e MYSQL_SERVICE_PASSWORD=123456 \
--name nacos \
nacos/nacos-server:v2.2.3
2. Nacos配置中心使用
(1)创建配置文件
- 命名规则:
${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
- 示例:
order-service-dev.yaml(订单服务dev环境配置)
- 配置内容:
yaml
复制代码
# 数据库配置
spring:
datasource:
url: jdbc:mysql://192.168.1.100:3306/order_db?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# Redis配置
redis:
host: 192.168.1.100
port: 6379
password: 123456
database: 0
# JWT配置
jwt:
secret: abc1234567890xyz
expire: 86400 # 24小时
# Sentinel配置
sentinel:
transport:
dashboard: 192.168.1.100:8080 # Sentinel控制台地址
(2)动态刷新配置
在需要动态刷新的类上添加@RefreshScope注解:
java
复制代码
@RestController
@RequestMapping("/order")
@RefreshScope // 动态刷新配置
public class OrderController {
@Value("${order.timeout:30}") // 默认30分钟
private Integer orderTimeout;
// 接口使用orderTimeout配置
}
七、网关层设计(Sentinel Gateway)
1. 网关配置(application.yml)
yaml
复制代码
spring:
cloud:
sentinel:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**filters:
- StripPrefix=1 # 去掉/api前缀
- name: SentinelGatewayFilter # Sentinel限流过滤器
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
filters:
- StripPrefix=1
- name: SentinelGatewayFilter
rules:
# 限流规则:按路径限流(订单服务最大QPS=1000)
- resource: order-service
limitApp: default
grade: 1 # 1=QPS限流
count: 1000 # 最大QPS
intervalSec: 1 # 统计时间窗口(秒)
# 限流规则:按用户限流(单用户最大QPS=100)
- resource: user-service
limitApp: ${spring.application.name}
grade: 1
count: 100
intervalSec: 1
controlBehavior: 2 # 2=匀速排队
2. 统一鉴权过滤器
java
复制代码
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Autowired
private JwtUtil jwtUtil;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 跳过登录接口
String path = exchange.getRequest().getPath().value();
if (path.contains("/user/login")) {
return chain.filter(exchange);
}
// 2. 获取Token
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (StrUtil.isBlank(token) || !token.startsWith("Bearer ")) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
token = token.substring(7);
// 3. 验证Token
if (!jwtUtil.validateToken(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 4. 解析用户ID,存入请求头
Long userId = jwtUtil.getUserIdFromToken(token);
exchange.getRequest().mutate().header("userId", userId.toString()).build();
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1; // 执行顺序:先鉴权,再限流
}
}
八、分布式事务一致性保障(Seata实战)
1. Seata部署(Docker)
bash
复制代码
# 拉取Seata镜像
docker pull seataio/seata-server:1.6.1
# 启动Seata Server(TC事务协调器)
docker run -d \
-p 8091:8091 \
-e SEATA_IP=192.168.1.100 \
-e SEATA_PORT=8091 \
-e SEATA_CONFIG_NAME=file:/root/seata-config/registry \
-v /root/seata-config:/root/seata-config \
--name seata-server \
seataio/seata-server:1.6.1
2. Seata配置(registry.conf)
yaml
复制代码
registry {
type = "nacos" # 注册中心用Nacos
nacos {
application = "seata-server"
serverAddr = "192.168.1.100:8848"
group = "SEATA_GROUP"
namespace = "dev"
username = "nacos"
password = "nacos"
}
}
config {
type = "nacos" # 配置中心用Nacos
nacos {
serverAddr = "192.168.1.100:8848"
namespace = "dev"
group = "SEATA_GROUP"
username = "nacos"
password = "nacos"
}
}
3. 微服务集成Seata(application.yml)
yaml
复制代码
seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: order_tx_group # 事务组(需与Seata配置一致)
registry:
type: nacos
nacos:
server-addr: 192.168.1.100:8848
group: SEATA_GROUP
namespace: dev
config:
type: nacos
nacos:
server-addr: 192.168.1.100:8848
group: SEATA_GROUP
namespace: dev
service:
vgroup-mapping:
order_tx_group: default # 事务组映射
client:
rm:
report-success-enable: true
4. 分布式事务模式选择
| 模式 |
适用场景 |
优点 |
缺点 |
| TCC |
核心链路(下单-库存-支付) |
强一致性、性能高 |
代码侵入性高(需写Try/Confirm/Cancel) |
| AT |
非核心链路(如订单通知) |
无侵入性、易实现 |
弱一致性(最终一致)、依赖数据库事务 |
| 可靠消息最终一致 |
异步场景(如日志同步) |
解耦、性能高 |
一致性延迟、需处理消息丢失 |
九、缓存问题全解(Redis+一致性+防雪崩)
1. 缓存三大问题解决方案
| 问题 |
解决方案 |
代码示例 |
| 缓存穿透(查不存在的数据) |
布隆过滤器+缓存空值 |
java // 布隆过滤器初始化 @PostConstruct public void initBloomFilter() { List<Long> productIds = productMapper.selectAllProductIds(); BloomFilter<Long> filter = BloomFilter.create(Funnels.longFunnel(), productIds.size(), 0.001); for (Long id : productIds) { filter.put(id); } redisTemplate.opsForValue().set("bloom:product", filter); } // 查询前校验布隆过滤器 if (!filter.mightContain(productId)) { return null; } |
| 缓存击穿(热点key过期) |
互斥锁+热点数据永不过期 |
java // 互斥锁解决击穿 String lockKey = "lock:product:" + productId; RLock lock = redissonClient.getLock(lockKey); lock.tryLock(5, 30, TimeUnit.SECONDS); try { // 再次查缓存,避免重复查库 String json = redisTemplate.opsForValue().get(cacheKey); if (StrUtil.isNotBlank(json)) { return JSONUtil.toBean(json, Product.class); } // 查库并更新缓存... } finally { lock.unlock(); } |
| 缓存雪崩(大量key同时过期) |
过期时间加随机值+Redis集群 |
java // 过期时间加随机值 int expire = 3600 + new Random().nextInt(600); redisTemplate.opsForValue().set(cacheKey, json, expire, TimeUnit.SECONDS); |
2. 缓存一致性(Cache Aside Pattern)
- 读流程:先查缓存→缓存命中直接返回→缓存未命中查数据库→存入缓存
- 写流程:先更数据库→再删缓存(而非更新缓存)
- 为什么删缓存而非更新?避免并发场景下的缓存脏数据(如A更新数据库,B更新缓存,A再删缓存,导致缓存是B的旧数据)
十、中间件选型与使用
1. RocketMQ(消息队列)
(1)核心使用场景
- 异步通信:订单创建后通知用户、日志收集
- 延迟队列:订单超时取消(30分钟延迟)
- 削峰填谷:秒杀场景异步下单(避免直接压垮数据库)
(2)关键配置
yaml
复制代码
rocketmq:
name-server: 192.168.1.100:9876
producer:
group: order-producer-group
send-message-timeout: 3000
consumer:
group: order-consumer-group
message-model: CLUSTERING # 集群消费模式
2. Redis(缓存+分布式锁)
(1)Redis集群部署(3主3从)
bash
复制代码
# 用Docker Compose部署Redis集群(省略复杂配置,实际生产用官方集群工具)
version: '3'
services:
redis-master1:
image: redis:6.2.6
command: redis-server --port 6379 --requirepass 123456
ports:
- "6379:6379"
redis-slave1:
image: redis:6.2.6
command: redis-server --port 6380 --requirepass 123456 --slaveof redis-master1 6379
ports:
- "6380:6380"
# 其他主从节点配置省略...
(2)Redisson分布式锁
java
复制代码
@Autowired
private RedissonClient redissonClient;
// 秒杀场景分布式锁
public boolean seckill(Long productId, Long userId) {
String lockKey = "lock:seckill:" + productId;
RLock lock = redissonClient.getLock(lockKey);
try {
// 尝试加锁,5秒超时,30秒自动释放
boolean locked = lock.tryLock(5, 30, TimeUnit.SECONDS);
if (!locked) {
return false; // 秒杀失败(已被抢完)
}
// 查库存→扣库存→创建订单(省略业务逻辑)
return true;
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
3. Sharding-JDBC(分库分表)
(1)订单表分库分表配置(application.yml)
yaml
复制代码
spring:
shardingsphere:
datasource:
names: db0,db1 # 两个分库
db0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.1.100:3306/order_db0?useSSL=false
username: root
password: 123456
db1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.1.100:3306/order_db1?useSSL=false
username: root
password: 123456
rules:
sharding:
tables:
order_main: # 订单主表
actual-data-nodes: db${0..1}.order_main_${202401..202412} # 分库分表规则(2库12表)
database-strategy: # 分库策略:按用户ID哈希
standard:
sharding-column: user_id
sharding-algorithm-name: order_db_inline
table-strategy: # 分表策略:按创建时间分月
standard:
sharding-column: create_time
sharding-algorithm-name: order_table_inline
sharding-algorithms:
order_db_inline:
type: INLINE
props:
algorithm-expression: db${user_id % 2} # 用户ID%2→db0/db1
order_table_inline:
type: INLINE
props:
algorithm-expression: order_main_${date_format(create_time,'yyyyMM')} # 按年月分表
十一、核心业务实现
1. 订单超时自动取消(两种方案对比)
| 方案 |
实现方式 |
优点 |
缺点 |
推荐场景 |
| RocketMQ延迟队列 |
订单创建时发送延迟消息,到期消费 |
可靠性高、延迟精度高 |
依赖RocketMQ集群 |
核心订单场景(推荐) |
| Redis过期键通知 |
订单创建时设置Redis键,监听过期事件 |
实现简单、无中间件依赖 |
过期通知可能延迟、不保证100%送达 |
非核心场景(如优惠券过期) |
2. 库存防超卖(三重保障)
- 数据库层面:库存扣减时加行锁(
select ... for update)
- 缓存层面:Redis分布式锁(Redisson)
- 业务层面:库存预扣+TCC回滚(支付失败回滚库存)
十二、特殊场景优化(秒杀/高并发)
1. 秒杀场景优化方案
(1)架构层面
- 限流:网关限流(Sentinel)+ 服务限流(Sentinel注解)
- 削峰:RocketMQ异步下单(避免直接操作数据库)
- 缓存预热:秒杀商品库存提前加载到Redis(避免缓存穿透)
- 隔离:秒杀服务独立部署(避免影响核心服务)
(2)代码层面
java
复制代码
@Service
public class SeckillServiceImpl implements SeckillService {
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private RedissonClient redissonClient;
@Autowired
private RocketMQTemplate rocketMQTemplate;
private static final String SECKILL_STOCK_KEY = "seckill:stock:";
private static final String SECKILL_USER_KEY = "seckill:user:"; // 防重复秒杀
@Override
@SentinelResource(value = "seckill", blockHandler = "seckillBlockHandler")
public Result<String> seckill(Long productId, Long userId) {
String stockKey = SECKILL_STOCK_KEY + productId;
String userKey = SECKILL_USER_KEY + productId + ":" + userId;
// 1. 防重复秒杀(Redis判断用户是否已秒杀)
Boolean hasSeckill = redisTemplate.hasKey(userKey);
if (Boolean.TRUE.equals(hasSeckill)) {
return Result.fail("您已参与秒杀,请勿重复提交");
}
// 2. 扣减Redis库存(原子操作,避免超卖)
Long stock = redisTemplate.opsForValue().decrement(stockKey);
if (stock == null || stock < 0) {
// 库存不足,回滚Redis库存
redisTemplate.opsForValue().increment(stockKey);
return Result.fail("秒杀已结束,库存不足");
}
// 3. 记录秒杀用户(防止重复)
redisTemplate.opsForValue().set(userKey, "1", 24, TimeUnit.HOURS);
// 4. 发送异步消息,创建订单(削峰填谷)
SeckillDTO seckillDTO = new SeckillDTO();
seckillDTO.setProductId(productId);
seckillDTO.setUserId(userId);
rocketMQTemplate.send("seckill-order-topic",
MessageBuilder.withPayload(seckillDTO).build());
return Result.success("秒杀成功,订单正在创建");
}
// Sentinel限流降级回调
public Result<String> seckillBlockHandler(Long productId, Long userId, BlockException e) {
return Result.fail("当前秒杀人数过多,请稍后再试");
}
}
2. 接口幂等性(防重复提交)
- 实现方式:基于订单号/请求ID去重(Redis)
- 代码示例:
java
复制代码
// 幂等性注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
long expire() default 300; // 过期时间(秒)
}
// 幂等性切面
@Component
@Aspect
public class IdempotentAspect {
@Autowired
private StringRedisTemplate redisTemplate;
@Around("@annotation(idempotent)")
public Object around(ProceedingJoinPoint joinPoint, Idempotent idempotent) throws Throwable {
// 1. 获取请求ID(从请求头或参数中)
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String requestId = request.getHeader("Request-Id");
if (StrUtil.isBlank(requestId)) {
return Result.fail("Request-Id不能为空");
}
// 2. 构建Redis键
String key = "idempotent:" + requestId;
// 3. 尝试设置Redis键(原子操作)
Boolean success = redisTemplate.opsForValue().setIfAbsent(key, "1", idempotent.expire(), TimeUnit.SECONDS);
if (Boolean.FALSE.equals(success)) {
return Result.fail("请勿重复提交");
}
// 4. 执行目标方法
return joinPoint.proceed();
}
}
// 接口使用
@PostMapping("/createOrder")
@Idempotent(expire = 60) // 60秒内防重复提交
public Result<String> createOrder(@RequestBody OrderDTO orderDTO) {
// 下单逻辑
}
十三、环境配置与部署(Docker+K8s)
1. Docker镜像构建(Dockerfile)
dockerfile
复制代码
# 基础镜像
FROM openjdk:11-jre-slim
# 工作目录
WORKDIR /app
# 复制jar包
COPY target/order-service-1.0.0.jar app.jar
# 暴露端口
EXPOSE 8080
# 启动命令
ENTRYPOINT ["java", "-jar", "app.jar", "--spring.profiles.active=prod"]
2. K8s部署配置(order-service-deployment.yaml)
yaml
复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: e-commerce
spec:
replicas: 3 # 3个副本(高可用)
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: order-service:1.0.0
ports:
- containerPort: 8080
resources:
limits:
cpu: "1"
memory: "1Gi"
requests:
cpu: "0.5"
memory: "512Mi"
livenessProbe: # 健康检查
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: order-service
namespace: e-commerce
spec:
selector:
app: order-service
ports:
- port: 80
targetPort: 8080
type: ClusterIP # 集群内部访问
3. 部署流程
bash
复制代码
# 1. 打包Jar包
mvn clean package -Dmaven.test.skip=true
# 2. 构建Docker镜像
docker build -t order-service:1.0.0 .
# 3. 推送镜像到仓库(Harbor)
docker tag order-service:1.0.0 192.168.1.100:8080/e-commerce/order-service:1.0.0
docker push 192.168.1.100:8080/e-commerce/order-service:1.0.0
# 4. K8s部署
kubectl apply -f order-service-deployment.yaml
# 5. 查看部署状态
kubectl get pods -n e-commerce
十四、监控与运维
1. 全链路监控(Prometheus+Grafana)
(1)微服务集成Prometheus
xml
复制代码
<!-- pom.xml依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
(2)application.yml配置
yaml
复制代码
management:
endpoints:
web:
exposure:
include: health,info,prometheus # 暴露监控端点
metrics:
tags:
application: ${spring.application.name} # 增加应用名称标签
endpoint:
health:
show-details: always # 显示健康详情
(3)Grafana面板配置
- 导入Spring Boot监控模板(ID:12856)
- 监控指标:QPS、响应时间、错误率、JVM内存、数据库连接数
2. 日志收集(ELK)
- Logstash:收集微服务日志(Docker日志挂载到宿主机)
- Elasticsearch:存储日志数据
- Kibana:可视化日志查询与分析
3. 告警机制
- 配置Prometheus告警规则(如响应时间>3s、错误率>5%)
- 集成AlertManager,通过邮件/钉钉/短信发送告警
总结
本文基于Spring Cloud Alibaba生态,详细讲解了微服务电商项目的全流程开发,从需求分析、数据库设计、技术选型,到核心服务开发、分布式事务、缓存优化、高并发处理,再到部署运维,覆盖了电商项目的核心痛点(如分布式一致性、库存超卖、订单超时、高并发秒杀)。
关键亮点:
- 基于Seata TCC模式保证核心链路一致性
- 多重缓存策略解决缓存穿透/击穿/雪崩问题
- RocketMQ延迟队列实现订单超时取消
- 分布式锁+数据库行锁双重防超卖
- K8s容器化部署保证高可用
实际开发中,需根据业务规模调整架构(如小体量项目可简化分库分表、Seata用AT模式),同时定期进行故障演练(如Chaos Monkey模拟服务宕机),验证熔断、降级、兜底逻辑的有效性。