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

190 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 11 天

前言

这是我将参加青训营期间的收获进行整理和总结,同时便于日后复习和查阅。如果能给各位小伙伴提供些帮助,也是我的荣幸,希望大家可以多多赐教,一起学习和交流。

本篇文章内容:

  • 系统设计方法论
  • 电商秒杀业务介绍
  • 课程实践

系统设计方法论

为什么要做系统设计

  • 个人:

    • 来自面试
    • 提升个人能力
    • 拓展技术视野
  • 工作:

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

系统设计的定义

定义:为了达成某种目的,通过个体组成整体的过程。

  • 系统:

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

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

如何做系统设计

  • 4S分析法

    场景、存储、服务、扩展

    • 01.场景分析(Scenarion) :什么系统,需要哪些功能,多大的数据量
    • 02.存储设计(Storage) :数据如何组织、Sql存储、NoSql存储
    • 03.服务设计(Service) :业务功能实现和逻辑整合
    • 04.可扩展性(Scale) :解决设计缺陷,提高鲁棒性、扩展性

如何发现系统的瓶颈

  • 火焰图分析:是性能分析的利器,通过它可以快速定位性能瓶颈点。
  • 链路追踪:用于评估节点之间关系(连接)的数据分析技术
  • 全链路压测:被称为系统整体容量保障的核武器。 全链路压测可以实现生产环境的压测服务,模拟真实的生产峰值场景,以发现真实的线上瓶颈并实现监控分析。 全链路压测可以实现精准的容量规划,确保线上系统的正常运行。

如何保证系统可用性和稳定型

  • 链路梳理

    • 核心链路
    • 流量漏斗
    • 强弱依赖
  • 可观测性

    • 链路追踪
    • 核心监控
    • 业务报警
  • 全链路测

    • 压力测试
    • 负载测试
    • 容量测试
  • 稳定性控制

    • 系统限流
    • 业务兜底
    • 熔断降级
  • 容灾演练

    • 混沌工程
    • 应急手册
    • 容灾预案

电商秒杀业务介绍

电商介绍

商品:具有交易价值和属性的信息载体。

SPU : Standard Product Unit(标准化产品单元),区分品种。是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。通俗点讲,属性值、特性相同的商品就可以称为一个SPU。 SKU : Stock Keeping Unit(库存量单位),区分单品。可以是以件、盒、托盘等为单位,通常表示:规格、颜色、款式。

秒杀业务的特点:

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

秒杀的挑战

  • 资源有限性
  • 反欺诈性
  • 高性能
  • 防止超卖
  • 流量管控
  • 扩展性
  • 鲁棒性(系统稳定性)

设计秒杀系统

4S分析

  • 场景(Scenario):

    • 功能:

      • 秒杀活动发布
      • 秒杀商品详情
      • 秒杀下单
    • 并发

      • 万人参与秒杀
      • QRS 1w+(每秒请求数,就是说服务器在一秒的时间内处理了多少个请求。)
      • TPS 1K+(服务器每秒处理的事务数,TPS是软件测试结果的测量单位。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数。)
  • 存储

    • MySQL —>Redis —>Localcache
  • 服务

    • 子服务:

      • 用户服务
      • 风控服务
      • 活动服务
      • 订单服务
    • 基础组件

      • ID生成器
      • 缓存组件
      • MQ组件
      • 限流组件
  • 扩展

    • 流量隔离、CDN、缓存优化、流量管控
    • 数据库扩展、MQ扩展、Redis扩展、服务水平扩展、服务垂直扩展

系统架构图:微信截图_20230205133916.png

秒杀流程图:秒杀系统流程.png

课程实践

部分相关代码:

import com.camp.promotion.convertet.Converter;
import com.camp.promotion.model.CreateActivityModel;
import lombok.Data;
​
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.function.Function;
​
@Data
public class CreateActivityRequest implements Converter<CreateActivityRequest, CreateActivityModel> {
​
    /**
     * 活动名称
     */
    @NotNull(message = "promoName不能为null")
    private String promoName;
    /**
     * 开始时间
     */
    @NotNull(message = "开始时间不能为null")
    private Long startTime;
    /**
     * 结束时间
     */
    @NotNull(message = "结束时间不能为null")
    private Long endTime;
    /**
     * 参与秒杀的商品
     */
    @NotEmpty(message = "秒杀商品不能为空")
    private List<CreatePromoProductRequest> promoProducts;
​
​
    @Override
    public CreateActivityModel convert(Function<CreateActivityRequest, CreateActivityModel> f) {
        return f.apply(this);
    }
}
import com.camp.promotion.convertet.ConvertFunction;
import com.camp.promotion.convertet.Converter;
import com.camp.promotion.model.CreateOrderModel;
import lombok.Data;
​
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.function.Function;
​
@Data
public class CreateOrderRequest implements Converter<CreateOrderRequest, CreateOrderModel> {
​
    /**
     * 用户id
     */
    @NotNull(message = "用户id不能为null")
    private Long userId;
    /**
     * 活动id
     */
    @NotNull(message = "秒杀活动id不能为null")
    private Long promoId;
    /**
     * 活动spu id
     */
    @NotNull(message = "spuId不能为null")
    private Long spuId;
    /**
     * 活动sku id
     */
    @NotNull(message = "skuId不能为null")
    private Long skuId;
    /**
     * 数量
     */
    @Min(1)
    @NotNull(message = "quantity不能为null")
    private Integer quantity;
    /**
     * 价格
     */
    @Min(0)
    @NotNull(message = "promoPrice不能为null")
    private Integer promoPrice;
    /**
     * 总价
     */
    @Min(0)
    @NotNull(message = "totalAmount不能为null")
    private Integer totalAmount;
    /**
     * 收货地址id
     */
    @NotNull(message = "addressId不能为null")
    private Long addressId;
    /**
     * 收货地址
     */
    @NotBlank(message = "shippingAddress不能为null")
    private String shippingAddress;
​
​
    @Override
    public CreateOrderModel convert(Function<CreateOrderRequest, CreateOrderModel> f) {
        return f.apply(this);
    }
}
import lombok.Data;
​
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
​
@Data
public class CreatePromoProductRequest {
​
    /**
     * 活动spu id
     */
    @NotNull(message = "spuId不能为null")
    private Long spuId;
    /**
     * 活动sku id
     */
    @NotNull(message = "skuId不能为null")
    private Long skuId;
    /**
     * 数量
     */
    @Min(1)
    @NotNull(message = "promoStock不能为null")
    private Integer promoStock;
    /**
     * 价格
     */
    @Min(0)
    @NotNull(message = "promoPrice不能为null")
    private Integer promoPrice;
}

引用:

  • 代码地址: 链接:pan.baidu.com/s/1Yc7TvP6C… 提取码:o4kk
  • 【实践课】手把手教你做系统设计 - 第五届字节跳动青训营