Java工程实践案例分析:构建高可用的电商系统

举报
江南清风起 发表于 2025/07/18 23:10:23 2025/07/18
【摘要】 Java工程实践案例分析:构建高可用的电商系统 一、项目背景与核心指标指标目标备注日均订单1000 万峰值 5 倍突发可用性99.99 %全年不可用 < 53 minP99 下单延迟< 200 ms含风控与库存扣减数据一致性最终一致TCC + 消息表模式 二、整体技术架构┌──────────────┐ 静态化 ┌──────────────┐ 动态渲染 ┌────────────...

Java工程实践案例分析:构建高可用的电商系统


一、项目背景与核心指标

指标 目标 备注
日均订单 1000 万 峰值 5 倍突发
可用性 99.99 % 全年不可用 < 53 min
P99 下单延迟 < 200 ms 含风控与库存扣减
数据一致性 最终一致 TCC + 消息表模式

二、整体技术架构

┌──────────────┐  静态化  ┌──────────────┐  动态渲染  ┌──────────────┐
│  CDN/Edge    │────────▶│  BFF(Gateway)│────────▶│  业务微服务    │
└──────────────┘         └──────────────┘           (SpringBoot) │
                                                 └──────────────┘
┌──────────────┐         ┌──────────────┐         ┌──────────────┐
│  Nacos       │────────▶│  Sentinel    │────────▶│  Seata       │
│  配置/注册   │         │  限流熔断    │         │  分布式事务  │
└──────────────┘         └──────────────┘         └──────────────┘

三、领域模型与代码结构(DDD 六边形)

mall/
├── mall-portal-api     // 用户侧接口
├── mall-inventory-api  // 库存接口
├── mall-order-service  // 订单聚合根
├── mall-payment-service
└── mall-shared-domain  // 通用值对象

3.1 订单聚合根示例

package com.mall.order.domain.model;

import javax.persistence.*;
import java.util.List;

@Entity
@Table(name = "t_order")
public class Order {
    @Id
    private Long id;

    @Embedded
    private UserId buyerId;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "order_id")
    private List<OrderItem> items;

    @Enumerated(EnumType.STRING)
    private OrderStatus status;

    public void confirm() {
        if (status != OrderStatus.PENDING) {
            throw new IllegalStateException("Order is not pending");
        }
        this.status = OrderStatus.CONFIRMED;
        registerEvent(new OrderConfirmedEvent(this.id));
    }
}

四、高可用库存扣减:TCC + 消息表

4.1 库存 Try 接口

@LocalTCC
public interface InventoryTccService {

    @TwoPhaseBusinessAction(name = "deduct", commitMethod = "confirm", rollbackMethod = "cancel")
    boolean tryDeduct(@BusinessActionContextParameter(paramName = "skuId") Long skuId,
                      @BusinessActionContextParameter(paramName = "qty") Integer qty);

    boolean confirm(BusinessActionContext ctx);

    boolean cancel(BusinessActionContext ctx);
}

4.2 实现类:基于版本号乐观锁

@Service
public class InventoryTccServiceImpl implements InventoryTccService {

    @Autowired
    private JdbcTemplate jdbc;

    @Override
    public boolean tryDeduct(Long skuId, Integer qty) {
        int updated = jdbc.update(
            "update t_inventory set freeze_qty = freeze_qty + ? where sku_id = ? and available_qty >= ?",
            qty, skuId, qty
        );
        return updated == 1;
    }

    @Override
    public boolean confirm(BusinessActionContext ctx) {
        Long skuId = (Long) ctx.getActionContext("skuId");
        Integer qty = (Integer) ctx.getActionContext("qty");
        jdbc.update(
            "update t_inventory set available_qty = available_qty - ?, freeze_qty = freeze_qty - ? where sku_id = ?",
            qty, qty, skuId
        );
        return true;
    }

    @Override
    public boolean cancel(BusinessActionContext ctx) {
        Long skuId = (Long) ctx.getActionContext("skuId");
        Integer qty = (Integer) ctx.getActionContext("qty");
        jdbc.update(
            "update t_inventory set freeze_qty = freeze_qty - ? where sku_id = ?",
            qty, skuId
        );
        return true;
    }
}

4.3 消息表保证最终一致

CREATE TABLE t_inventory_msg (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  sku_id BIGINT NOT NULL,
  qty INT NOT NULL,
  status ENUM('NEW','DONE','FAIL') DEFAULT 'NEW',
  create_time DATETIME NOT NULL,
  UNIQUE KEY uniq_sku (sku_id, qty, create_time)
);

通过定时任务扫描 status='NEW' 行,幂等发送到 MQ,消费者更新缓存。


五、读写分离 + 分库分表:ShardingSphere

5.1 配置(YAML)

dataSources:
  ds_0:
    url: jdbc:mysql://10.0.0.11:3306/mall_order_0
  ds_1:
    url: jdbc:mysql://10.0.0.12:3306/mall_order_1
rules:
  - !SHARDING
    tables:
      t_order:
        actualDataNodes: ds_${0..1}.t_order_${0..7}
        tableStrategy:
          standard:
            shardingColumn: buyer_id
            shardingAlgorithmName: order_inline
        keyGenerateStrategy:
          column: id
          keyGeneratorName: snowflake
    shardingAlgorithms:
      order_inline:
        type: INLINE
        props:
          algorithm-expression: t_order_${buyer_id % 8}

5.2 读写分离 Hint

HintManager hint = HintManager.getInstance();
hint.setWriteRouteOnly();   // 强制主库
// 业务代码...
hint.close();

六、Sentinel 限流与热点参数防护

6.1 引入依赖

<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

6.2 热点参数限流规则(动态配置)

spring:
  cloud:
    sentinel:
      datasource:
        hotspot:
          nacos:
            server-addr: nacos:8848
            data-id: hotspot-order
            rule-type: param-flow

6.3 代码埋点

@GetMapping("/order/{skuId}")
@SentinelResource(value = "createOrder",
                  blockHandler = "createOrderBlock",
                  fallback = "createOrderFallback")
public ApiResp<OrderDTO> createOrder(@PathVariable Long skuId,
                                     @RequestParam(defaultValue = "1") Integer qty) {
    return orderAppService.create(skuId, qty);
}

public ApiResp<OrderDTO> createOrderBlock(Long skuId, Integer qty, BlockException e) {
    return ApiResp.fail("系统繁忙,请稍后重试");
}

七、灰度发布:基于 Nacos 标签路由

7.1 服务元数据

spring:
  cloud:
    nacos:
      discovery:
        metadata:
          version: v2025.07.canary

7.2 路由规则(YAML DSL)

strategy: V
routes:
  - predicates:
      - Headers=canary,true
    weight: 100
    tags:
      version: v2025.07.canary

八、监控与故障演练

8.1 指标采集

  • JVM : Micrometer → Prometheus → Grafana
  • 业务 : 订单创建 QPS、库存扣减失败率
  • 中间件 : Seata 事务回滚次数、Sentinel 限流 QPS

8.2 Chaos-Blade 演练脚本

# 网络延迟 200 ms
blade create network delay --time 200 --interface eth0 --timeout 60

# MySQL 主库 CPU 满载
blade create cpu fullload --cpu-percent 100 --timeout 120

九、关键代码仓库

模块 GitHub 地址 备注
mall-order-service github.com/mall/order TCC+ShardingSphere
mall-inventory-service github.com/mall/inventory 乐观锁+消息表
mall-infra github.com/mall/infra Sentinel/Nacos 配置

十、结语

高可用不是“加机器”,而是可验证的故障容错设计
通过 DDD 限界上下文隔离、TCC 保证库存强一致、ShardingSphere 水平扩展、Sentinel 动态防护,以及灰度发布降低爆炸半径,电商系统才能在 1000 万级订单场景下存活。
下一步,我们将引入 Serverless 弹性伸缩异步事件总线 Pulsar,持续演进。

image.png

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。