手把手教你做系统设计 | 青训营笔记

40 阅读2分钟

1,系统设计方法论

系统设计中遇到的问题:

  • 为什么要做系统设计
  • 系统设计的定义是什么
  • 怎么做系统设计,如何落地一个系统设计
  • 系统功能实现之后,如何分析瓶颈并优化
  • 如何验证系统的可用性和稳定性

为什么要做系统设计:
个人:

  • For面试
  • 个人能力提升
  • 扩展技术视野

工作:

  • 业务驱动
  • 系统重构
  • 突破和创新

如何评估一个系统:
可用性 安全性 扩展性 易用性 可维护性 性能 伸缩性 耦合性

系统设计的定义:
为了达成某种目的,通过个体组成整体的过程 系统:

  • 关联的个体
  • 规则运作
  • 组成工作的整体

设计:

  • 设想和计划
  • 目的
  • 过程安排

如何保证可用性和稳定性:

  • 链路梳理:核心链路 流量漏斗 强势依赖
  • 可观测性:链路追踪 核心监控 业务报警
  • 全链路测试:压力测试 负载测试 容量测试
  • 稳定性控制:系统限流 业务兜底 熔断降低
  • 容灾演练:混沌工程 应急手册 容灾预案

2. 电商秒杀业务介绍

秒杀业务的特点:

  • 瞬时流量高
  • 读多写少
  • 实时性要求高

秒杀的挑战:

  • 资源成本
  • 反欺诈
  • 高性能
  • 防止超卖
  • 流量管控
  • 扩展性
  • 鲁棒性

场景:
秒杀活动发布
秒杀商品详情
秒杀下单

万人参与秒杀
QPS 1w+ TPS 1k+

服务(Service):

  • 子服务:用户服务;风控服务;活动服务;订单服务
  • 基础组件:ID生成器(生成订单ID——分布式ID生成);缓存组建;MQ组件(保护系统——削峰);限流组件(保护系统)

扩展:

  • 流量隔离(与常规流量合理)
  • CDN(静态资源缓存,提高效率)
  • 缓存优化
  • 流量管控(拦截、过滤)
  • 数据库扩展
  • 服务水平扩展(负载均衡、反向代理)
  • MQ扩展(主从架构、多主多从架构)
  • Redis扩展
  • 服务垂直扩展

系统架构图

系统架构图.png

秒杀流程图.png

3. 课程实践

src/main/java/com/camp/promotion/service/impl/HPromotionServiceImpl.java

public List<CreatePromoProductModel> CreatePromoActivity(CreateActivityModel createActivityModel)

public HPromoProductModel getPromotionProductDetail(Long promoId, Long skuId, Long spuId)

src/main/java/com/camp/promotion/controller/CategoryController.java

public ResponseData<?> testLock() {
    // 把锁的创建放在try后,不用写finally了,自动调用close方法
    try (RedisDistributedLock lock = new RedisDistributedLock("test_key", 10000)) {
        if (lock.tryLock()) {
            return ResponseData.Success("ok");
        }
    } catch (Exception e) {
        throw new RuntimeException("lock fail");
    }
    ...

src/main/java/com/camp/promotion/mq/OrderPullConsumer.java

public void doConsumer() throws InterruptedException {
    while (isRunning.get()) {
        ...

        executorService.execute(() -> {
            try {
                // 线程池里做异步消费
                processOrder(messageExts);
            } catch (Exception e) {
                log.error("process order fail, e = ", e);
            }
        });

        ...
    }
}

@Transactional(rollbackFor = Exception.class)
public void processOrder(List<MessageExt> messageExts) {
    ...
    
    // 真正从数据库中扣减
    int updateStockRes = this.hPromoProductService.decreaseStock(orders.get(0).getActivityId(), orders.get(0).getSkuId(), decreaseCount);
    if (updateStockRes < 1) {
        log.error("process order fail, size = {}, data = {}", orders.size(), JSON.toJSONString(orders));
        this.deadQueue.addAll(orders);
        throw new BizException(ResponseEnum.CONSUMER_FAIL);
    }

    // 批量插入(优化了性能)
    int insertRes = this.hOrderService.batchInsert(orders);
    if (insertRes < orders.size()) {
        log.error("process order fail, size = {}, data = {}", orders.size(), JSON.toJSONString(orders));
        this.deadQueue.addAll(orders);
        throw new BizException(ResponseEnum.CONSUMER_FAIL);
    }
}