文章目录
- 基于Spring Cloud Alibaba的微服务电商项目全流程实战(高并发+高可用+一致性保障)
- 一、需求分析
- 二、数据库表设计(按服务拆分)
- 1. 数据库拆分原则
- 2. 核心表结构(MySQL)
- (1)用户服务数据库(user_db)
- (2)商品服务数据库(product_db)
- (3)订单服务数据库(order_db)
- (4)库存服务数据库(inventory_db)
- (5)支付服务数据库(pay_db)
- 三、技术栈选型(Spring Cloud Alibaba生态)
- 四、微服务架构设计
- 1. 架构分层(从上到下)
- 2. 服务拆分原则
- 3. 核心链路调用流程
- 五、核心微服务开发实现
- 1. 通用基础配置(所有服务依赖)
- (1)pom.xml核心依赖(Spring Boot 2.7.x + Spring Cloud Alibaba 2021.0.4.0)
- (2)bootstrap.yml(连接Nacos配置中心)
- 2. 用户服务(user-service)
- 3. 商品服务(product-service)
- (1)核心功能:商品缓存(Cache Aside Pattern)
- 4. 库存服务(inventory-service)
- 5. 订单服务(order-service)
- (1)核心功能:创建订单(整合Seata TCC分布式事务)
- (2)订单超时取消(监听RocketMQ延迟队列)
- 6. 支付服务(pay-service)
- 六、服务注册与配置中心(Nacos实战)
- 1. Nacos部署(Docker方式)
- 2. Nacos配置中心使用
- 七、网关层设计(Sentinel Gateway)
- 1. 网关配置(application.yml)
- 2. 统一鉴权过滤器
- 八、分布式事务一致性保障(Seata实战)
- 1. Seata部署(Docker)
- 2. Seata配置(registry.conf)
- 3. 微服务集成Seata(application.yml)
- 4. 分布式事务模式选择
- 九、缓存问题全解(Redis+一致性+防雪崩)
- 1. 缓存三大问题解决方案
- 2. 缓存一致性(Cache Aside Pattern)
- 十、中间件选型与使用
- 1. RocketMQ(消息队列)
- 2. Redis(缓存+分布式锁)
- (1)Redis集群部署(3主3从)
- (2)Redisson分布式锁
- 3. Sharding-JDBC(分库分表)
- (1)订单表分库分表配置(application.yml)
- 十一、核心业务实现
- 1. 订单超时自动取消(两种方案对比)
- 2. 库存防超卖(三重保障)
- 十二、特殊场景优化(秒杀/高并发)
- 1. 秒杀场景优化方案
- 2. 接口幂等性(防重复提交)
- 十三、环境配置与部署(Docker+K8s)
- 1. Docker镜像构建(Dockerfile)
- 2. K8s部署配置(order-service-deployment.yaml)
- 3. 部署流程
- 十四、监控与运维
- 1. 全链路监控(Prometheus+Grafana)
- (1)微服务集成Prometheus
- (2)application.yml配置
- (3)Grafana面板配置
- 2. 日志收集(ELK)
- 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)
<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>
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
(2)bootstrap.yml(连接Nacos配置中心)
spring:application:name: order-service cloud:nacos:discovery:server-addr: 192.168.1.100:8848 config:server-addr: 192.168.1.100:8848 file-extension: yaml namespace: dev group: ORDER_GROUP
dubbo:registry:address: nacos://192.168.1.100:8848 protocol:name: dubboport: -1
2. 用户服务(user-service)
(1)核心功能:JWT鉴权
@Component
public class JwtUtil {@Value("${jwt.secret}")private String secret;@Value("${jwt.expire}")private long expire;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();}public boolean validateToken(String token) {try {Jwts.parser().setSigningKey(secret).parseClaimsJws(token);return true;} catch (Exception e) {return false;}}public Long getUserIdFromToken(String token) {Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();return Long.parseLong(claims.getSubject());}
}
(2)登录接口
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate 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("用户名或密码错误");}String token = jwtUtil.generateToken(user.getId());return Result.success(token);}
}
3. 商品服务(product-service)
(1)核心功能:商品缓存(Cache Aside Pattern)
@Service
public class ProductServiceImpl implements ProductService {@Autowiredprivate ProductMapper productMapper;@Autowiredprivate StringRedisTemplate redisTemplate;private static final String CACHE_KEY_PRODUCT = "product:";@Overridepublic Product getProductById(Long productId) {String key = CACHE_KEY_PRODUCT + productId;String json = redisTemplate.opsForValue().get(key);if (StrUtil.isNotBlank(json)) {return JSONUtil.toBean(json, Product.class);}Product product = productMapper.selectById(productId);if (product != null) {redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(product), 3600 + new Random().nextInt(600), TimeUnit.SECONDS);} else {redisTemplate.opsForValue().set(key, "", 60, TimeUnit.SECONDS);}return product;}@Override@Transactionalpublic boolean updateProduct(Product product) {boolean success = productMapper.updateById(product) > 0;if (success) {String key = CACHE_KEY_PRODUCT + product.getId();redisTemplate.delete(key);}return success;}
}
4. 库存服务(inventory-service)
(1)核心功能:库存扣减(防超卖+分布式锁)
@Service
public class InventoryServiceImpl implements InventoryService {@Autowiredprivate InventoryMapper inventoryMapper;@Autowiredprivate RedissonClient redissonClient;private static final String LOCK_KEY_INVENTORY = "lock:inventory:";@Overridepublic boolean deductStock(Long productId, Integer quantity, String orderId) {RLock lock = redissonClient.getLock(LOCK_KEY_INVENTORY + productId);lock.lock(30, TimeUnit.SECONDS); try {Inventory inventory = inventoryMapper.selectByProductIdForUpdate(productId);if (inventory == null || inventory.getStock() < quantity) {return false; }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(1); inventoryLogMapper.insert(log);return inventoryMapper.updateById(inventory) > 0;} finally {lock.unlock(); }}@Overridepublic boolean confirmDeduct(Long productId, Integer quantity) {return true;}@Overridepublic 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); inventoryLogMapper.insert(log);return inventoryMapper.updateById(inventory) > 0;} finally {lock.unlock();}}
}
5. 订单服务(order-service)
(1)核心功能:创建订单(整合Seata TCC分布式事务)
public interface OrderTccService {@TwoPhaseBusinessAction(name = "createOrderTcc", commitMethod = "confirm", rollbackMethod = "cancel")boolean tryCreateOrder(@BusinessActionContextParameter(paramName = "orderDTO") OrderDTO orderDTO, BusinessActionContext context);boolean confirm(BusinessActionContext context);boolean cancel(BusinessActionContext context);
}@Service
public class OrderTccServiceImpl implements OrderTccService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate OrderItemMapper orderItemMapper;@DubboReferenceprivate InventoryService inventoryService;@Autowiredprivate RocketMQTemplate rocketMQTemplate;@Override@Transactionalpublic boolean tryCreateOrder(OrderDTO orderDTO, BusinessActionContext context) {String orderSn = IdUtil.fastSimpleUUID();OrderMain orderMain = new OrderMain();orderMain.setOrderSn(orderSn);orderMain.setUserId(orderDTO.getUserId());orderMain.setTotalAmount(orderDTO.getTotalAmount());orderMain.setStatus(0); orderMapper.insert(orderMain);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);}boolean deductSuccess = inventoryService.deductStock(orderDTO.getItems().get(0).getProductId(), orderDTO.getItems().get(0).getQuantity(),orderSn);if (!deductSuccess) {throw new RuntimeException("库存不足");}rocketMQTemplate.send("order-delay-topic", MessageBuilder.withPayload(orderSn).setHeader(RocketMQHeaders.DELAY_TIME_LEVEL, 9) .build());context.setActionContext("orderSn", orderSn);return true;}@Override@Transactionalpublic boolean confirm(BusinessActionContext context) {String orderSn = (String) context.getActionContext("orderSn");OrderMain orderMain = orderMapper.selectByOrderSn(orderSn);orderMain.setStatus(1); orderMain.setPayTime(new Date());return orderMapper.updateById(orderMain) > 0;}@Override@Transactionalpublic boolean cancel(BusinessActionContext context) {String orderSn = (String) context.getActionContext("orderSn");OrderMain orderMain = orderMapper.selectByOrderSn(orderSn);orderMain.setStatus(-1); orderMapper.updateById(orderMain);OrderItem orderItem = orderItemMapper.selectByOrderId(orderMain.getId()).get(0);inventoryService.cancelDeduct(orderItem.getProductId(), orderItem.getQuantity(), orderSn);return true;}
}
(2)订单超时取消(监听RocketMQ延迟队列)
@Component
@RocketMQMessageListener(topic = "order-delay-topic", consumerGroup = "order-delay-consumer")
public class OrderDelayConsumer implements RocketMQListener<String> {@Autowiredprivate OrderMainMapper orderMainMapper;@Autowiredprivate OrderTccService orderTccService;@Overridepublic void onMessage(String orderSn) {OrderMain orderMain = orderMainMapper.selectByOrderSn(orderSn);if (orderMain == null) {return;}if (orderMain.getStatus() == 0) {BusinessActionContext context = new BusinessActionContext();context.setActionContext("orderSn", orderSn);orderTccService.cancel(context);System.out.println("订单" + orderSn + "超时未支付,已自动取消");}}
}
6. 支付服务(pay-service)
(1)核心功能:对接支付宝支付
@Service
public class AlipayServiceImpl implements PayService {@Autowiredprivate PaymentMapper paymentMapper;@DubboReferenceprivate 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;@Overridepublic String createAlipayOrder(String orderSn, Long userId, BigDecimal amount) {try {AlipayClient client = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",appId, privateKey, "json", "UTF-8", publicKey, "RSA2");AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();request.setReturnUrl("http://localhost:8080/pay/return"); request.setNotifyUrl(notifyUrl); 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());AlipayTradePagePayResponse response = client.pageExecute(request);if (response.isSuccess()) {Payment payment = new Payment();payment.setOrderSn(orderSn);payment.setUserId(userId);payment.setPayAmount(amount);payment.setPayType(1); payment.setStatus(0); paymentMapper.insert(payment);return response.getBody(); } else {throw new RuntimeException("支付宝支付创建失败:" + response.getMsg());}} catch (Exception e) {throw new RuntimeException("支付异常", e);}}@Overridepublic String handleAlipayNotify(Map<String, String> params) {try {boolean signVerified = AlipaySignature.rsaCheckV1(params, publicKey, "UTF-8", "RSA2");if (!signVerified) {return "fail"; }String tradeStatus = params.get("trade_status");if (!"TRADE_SUCCESS".equals(tradeStatus)) {return "fail";}String orderSn = params.get("out_trade_no");String tradeNo = params.get("trade_no"); BigDecimal payAmount = new BigDecimal(params.get("total_amount"));Payment payment = paymentMapper.selectByOrderSn(orderSn);if (payment == null || payment.getStatus() != 0) {return "fail"; }payment.setStatus(1); payment.setPayTime(new Date());payment.setTradeNo(tradeNo);paymentMapper.updateById(payment);BusinessActionContext context = new BusinessActionContext();context.setActionContext("orderSn", orderSn);orderTccService.confirm(context);return "success"; } catch (Exception e) {return "fail";}}
}
六、服务注册与配置中心(Nacos实战)
1. Nacos部署(Docker方式)
docker pull nacos/nacos-server:v2.2.3
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环境配置) - 配置内容:
spring:datasource:url: jdbc:mysql://192.168.1.100:3306/order_db?useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver
redis:host: 192.168.1.100port: 6379password: 123456database: 0
jwt:secret: abc1234567890xyzexpire: 86400
sentinel:transport:dashboard: 192.168.1.100:8080
(2)动态刷新配置
在需要动态刷新的类上添加@RefreshScope注解:
@RestController
@RequestMapping("/order")
@RefreshScope
public class OrderController {@Value("${order.timeout:30}") private Integer orderTimeout;
}
七、网关层设计(Sentinel Gateway)
1. 网关配置(application.yml)
spring:cloud:sentinel:gateway:routes:- id: user-serviceuri: lb://user-servicepredicates:- Path=/api/user/**filters:- StripPrefix=1 - name: SentinelGatewayFilter - id: order-serviceuri: lb://order-servicepredicates:- Path=/api/order/**filters:- StripPrefix=1- name: SentinelGatewayFilterrules:- resource: order-servicelimitApp: defaultgrade: 1 count: 1000 intervalSec: 1 - resource: user-servicelimitApp: ${spring.application.name}grade: 1count: 100intervalSec: 1controlBehavior: 2
2. 统一鉴权过滤器
@Component
public class AuthFilter implements GlobalFilter, Ordered {@Autowiredprivate JwtUtil jwtUtil;@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {String path = exchange.getRequest().getPath().value();if (path.contains("/user/login")) {return chain.filter(exchange);}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);if (!jwtUtil.validateToken(token)) {exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);return exchange.getResponse().setComplete();}Long userId = jwtUtil.getUserIdFromToken(token);exchange.getRequest().mutate().header("userId", userId.toString()).build();return chain.filter(exchange);}@Overridepublic int getOrder() {return -1; }
}
八、分布式事务一致性保障(Seata实战)
1. Seata部署(Docker)
docker pull seataio/seata-server:1.6.1
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)
registry {type = "nacos" nacos {application = "seata-server"serverAddr = "192.168.1.100:8848"group = "SEATA_GROUP"namespace = "dev"username = "nacos"password = "nacos"}
}config {type = "nacos" nacos {serverAddr = "192.168.1.100:8848"namespace = "dev"group = "SEATA_GROUP"username = "nacos"password = "nacos"}
}
3. 微服务集成Seata(application.yml)
seata:enabled: trueapplication-id: ${spring.application.name}tx-service-group: order_tx_group registry:type: nacosnacos:server-addr: 192.168.1.100:8848group: SEATA_GROUPnamespace: devconfig:type: nacosnacos:server-addr: 192.168.1.100:8848group: SEATA_GROUPnamespace: devservice: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)关键配置
rocketmq:name-server: 192.168.1.100:9876producer:group: order-producer-groupsend-message-timeout: 3000consumer:group: order-consumer-groupmessage-model: CLUSTERING
2. Redis(缓存+分布式锁)
(1)Redis集群部署(3主3从)
version: '3'
services:redis-master1:image: redis:6.2.6command: redis-server --port 6379 --requirepass 123456ports:- "6379:6379"redis-slave1:image: redis:6.2.6command: redis-server --port 6380 --requirepass 123456 --slaveof redis-master1 6379ports:- "6380:6380"
(2)Redisson分布式锁
@Autowired
private RedissonClient redissonClient;
public boolean seckill(Long productId, Long userId) {String lockKey = "lock:seckill:" + productId;RLock lock = redissonClient.getLock(lockKey);try {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)
spring:shardingsphere:datasource:names: db0,db1 db0:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.1.100:3306/order_db0?useSSL=falseusername: rootpassword: 123456db1:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.1.100:3306/order_db1?useSSL=falseusername: rootpassword: 123456rules:sharding:tables:order_main: actual-data-nodes: db${0..1}.order_main_${202401..202412} database-strategy: standard:sharding-column: user_idsharding-algorithm-name: order_db_inlinetable-strategy: standard:sharding-column: create_timesharding-algorithm-name: order_table_inlinesharding-algorithms:order_db_inline:type: INLINEprops:algorithm-expression: db${user_id % 2} order_table_inline:type: INLINEprops: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)代码层面
@Service
public class SeckillServiceImpl implements SeckillService {@Autowiredprivate StringRedisTemplate redisTemplate;@Autowiredprivate RedissonClient redissonClient;@Autowiredprivate 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;Boolean hasSeckill = redisTemplate.hasKey(userKey);if (Boolean.TRUE.equals(hasSeckill)) {return Result.fail("您已参与秒杀,请勿重复提交");}Long stock = redisTemplate.opsForValue().decrement(stockKey);if (stock == null || stock < 0) {redisTemplate.opsForValue().increment(stockKey);return Result.fail("秒杀已结束,库存不足");}redisTemplate.opsForValue().set(userKey, "1", 24, TimeUnit.HOURS);SeckillDTO seckillDTO = new SeckillDTO();seckillDTO.setProductId(productId);seckillDTO.setUserId(userId);rocketMQTemplate.send("seckill-order-topic", MessageBuilder.withPayload(seckillDTO).build());return Result.success("秒杀成功,订单正在创建");}public Result<String> seckillBlockHandler(Long productId, Long userId, BlockException e) {return Result.fail("当前秒杀人数过多,请稍后再试");}
}
2. 接口幂等性(防重复提交)
- 实现方式:基于订单号/请求ID去重(Redis)
- 代码示例:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {long expire() default 300;
}
@Component
@Aspect
public class IdempotentAspect {@Autowiredprivate StringRedisTemplate redisTemplate;@Around("@annotation(idempotent)")public Object around(ProceedingJoinPoint joinPoint, Idempotent idempotent) throws Throwable {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();String requestId = request.getHeader("Request-Id");if (StrUtil.isBlank(requestId)) {return Result.fail("Request-Id不能为空");}String key = "idempotent:" + requestId;Boolean success = redisTemplate.opsForValue().setIfAbsent(key, "1", idempotent.expire(), TimeUnit.SECONDS);if (Boolean.FALSE.equals(success)) {return Result.fail("请勿重复提交");}return joinPoint.proceed();}
}
@PostMapping("/createOrder")
@Idempotent(expire = 60)
public Result<String> createOrder(@RequestBody OrderDTO orderDTO) {
}
十三、环境配置与部署(Docker+K8s)
1. Docker镜像构建(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)
apiVersion: apps/v1
kind: Deployment
metadata:name: order-servicenamespace: e-commerce
spec:replicas: 3 selector:matchLabels:app: order-servicetemplate:metadata:labels:app: order-servicespec:containers:- name: order-serviceimage: order-service:1.0.0ports:- containerPort: 8080resources:limits:cpu: "1"memory: "1Gi"requests:cpu: "0.5"memory: "512Mi"livenessProbe: httpGet:path: /actuator/healthport: 8080initialDelaySeconds: 60periodSeconds: 10readinessProbe:httpGet:path: /actuator/healthport: 8080initialDelaySeconds: 30periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:name: order-servicenamespace: e-commerce
spec:selector:app: order-serviceports:- port: 80targetPort: 8080type: ClusterIP
3. 部署流程
mvn clean package -Dmaven.test.skip=true
docker build -t order-service:1.0.0 .
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
kubectl apply -f order-service-deployment.yaml
kubectl get pods -n e-commerce
十四、监控与运维
1. 全链路监控(Prometheus+Grafana)
(1)微服务集成Prometheus
<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配置
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模拟服务宕机),验证熔断、降级、兜底逻辑的有效性。