这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天
本堂课重点内容:
- 系统设计方法论
- 电商秒杀业务介绍
- 课程实践
- 课程总结
1.系统设计方法论
1.0 系统设计的那些问题
1.1 为什么要做系统设计
解决问题!
1.2 系统设计的定义是什么
定义:为了达成某种目的,通过个体组成整体的过程
1.3 怎么做系统设计,如何落地一个系统
4s 分析法
1.4 系统功能实现之后,如何分析瓶颈并优化
- 火焰图分析
- 链路分析
- 全链路压测
- 火焰图分析。这个火焰图分析是针对单个实例的分析,就是会分析 CPU 的使用,内存的使用,会找到你代码上的一些瓶颈。
- 链路追踪,因为现在我们其实都是微服务时代,一次请求可能后面会有几十个服务,甚至上百个上千个服务。在这些服务里面,我们需要对同一个请求去做一个链路的追踪。要知道这个请求经过了哪些服务,在哪些服,在哪个服,在每个服务的耗时是多少。所以通过链路追踪可以分析出这一次请求是在哪个服务上,耗费的时间会比较大。
- 性能测试也是会挖掘出你整个系统的性能的不足。
1.5 如何验证系统的可用性和稳定性
- 链路梳理
- 链路梳理。我们在我们的微服务上,我们要梳理出来一条核心线,核心的链路。以电商来说,它的核心的链路,比如我们要看到电商的详情,要去计算价格,要去提单,要去下单,要去支付,这就是它的一个核心的链路。在核心链路之外的一些微服务,它就是一些非核心的服务。梳理出来之后,我们对于那些非核心的依赖,当它出错时,就可以就可以给它做一个降级,因为它并不影响到核心链路。我们对核心链路要去做一些重点的保障。
- 漏斗也比较好理解,比如我们可能会浏览很多商品,但其中比如我们只会把我们浏览的几个商品加入到购物车,在购物车里面,我们可能比如我们购物车里面有 10 个商品,但是我们可能只下单其中的几个,这就是流量的一些漏斗。
- 强弱依赖在梳理核心链路的时候已经介绍了,弱依赖可以加急,强依赖是不能加急的。
- 可观测性
可观测性,其实就是我们对我们的一个系统,要去要能观测到它的各种的指标,就是要有一双,要对系统能发现它,就相当于对系统有一个望远镜,可以看到它。这里的链路追踪前面也介绍了,我们要对一个词请求做一个全链路上微服务的追踪。除此之外,我们还要去做一些核心的指标的监控,在监控的基础上去对一些核心业务异常的去做一些报警。其实我们很多问题都是通过报警发现的,然后去及时的处理。
- 全链路测试
全链路测试,这里面有压力测试、负载测试、容量测试就是他们的侧重点,其实是不太一样的压力,我们要压到我们链路的一个临界点,甚至要超过临界点。要观测一下我们这些服务的一个表现,是不是还能提供满足可用性的一个服务。负载。要准确地测试出链路的负载容量,就是去测试出整体系统的一个容量的水位。比如双 11 的大促的时候,我们要比如我们要满足几亿人在线对吧,每秒交易几十万次,这就是它的一个容量。
- 稳定性控制
稳定性控制,这里就是我们要用一些手段和措施去保证我们系统的稳定性。
系统的限流,这个也会是一个非常有效的保护我们系统稳定性的一个手段。第二个是业务的兜底,这个兜底是指比如我们下游的一些依赖,它产生了,它返回了一些错误,我们从当前的服务可以给它返回一些兜底的数据。第三个也是熔断降级,这个也是老生常谈的东西。
- 容灾演练
容灾演练。首先是混沌工程,其实大家就可以给它理解成故障注入,也是去给它做一些通过故障注入的方式去做一些演练。
通过演练我们要沉淀出来一些应急的操作手册,假设我们线上真的出了一些问题,我们要按照我们演练的沉淀出来的应急手册去启动一些预案。第三部分就是容灾的预案,当我们出现一些故障,比如机房出现了故障,比如某个核心服务出现了故障,我们要启动我们容灾的预案。。
2.电商秒杀业务介绍
2.1 电商介绍
其实电商的本质,其实它就是交易。交易需要 3 个要素,一个是人,一个是货,一个是厂。哪怕我们去线下去购买东西,去商场,去超市,它也是这样的三个角色。比如线下超市和商场,这里面的厂,这是我们交易的一个环境。货我们在超市看到的一些商品,人、消费者在电商厂就变成了线上的一个电商系统,货就变成了商品,商家和供应链。人就是我们、去电商消费的一些消费者,用户也是流量的来源。
电商它其实发展到现在,它是经历了一个传统电商,社交电商,比如拼多多,还有以前的微商。第四到现在是内容电商,包括直播电商也是内容电商。它这样发展下来的一个底层的逻辑,社交电商、内容电商,它是加强了人与货的联系。比如我们通过直播电商,我们更容易去了解到这个货的一些信息,包括它是什么样子的,比如主播他试用了这些商品,他的上身的一些效果是怎样的?这会加速,会加强人与货之间的联系。
商品:具有交易价值和属性的信息载体
我们的商品是一定要有交易价值的,价值应该是买卖双方都认可的。比如你捡了一块石子,这个石子赔了你很多年,你觉得它是有价值的,值很多钱,但是别人不认同这个价值,但是所以它就不能拿来交易,它就不是商品。信息载体。属性也很好理解对吧。你的衣服也好,鞋子也好,它都有它的颜色,尺码,这些信息,包括厂家、生产地等等。
standard product unit 就是标准的产品单元,为什么要去做标准化的产品单元?因为现在的商品是太多了,比如以电商为例,它的商品它其实已经达到了千亿级别。如果我们不做统一标准化的管理,它其实是管理成本是非常高的。所以当事物发展到一定程度,它标准化、规范化一定是它的一个趋势。
stock keeping unit 库存保持单元就是一个可交,它是具有交易属性的这样的一个概念,它会有库存以及价格这样的一个信息。
2.2 秒杀业务的特点
比如双 11 它的一个秒杀大促,在之前没有之前都是0点之后才能开始下单的,它的流量一定是集中在0点时刻,它最大的特点就是在0点时刻的瞬时流量是非常高的,大多数其实都是读请求,读多写少。
读多写少。其实很多我们其实都是在查看商品,再去读商品的信息。包括秒杀前我们会不停地去做刷新,去要去等秒杀的按钮编程,可点击之后去进行,才能去进行一个写操作。
我们下完单一定是要看到下单的结果的,实时性要求是很高的
2.4 秒杀的挑战
- 资源有限性
首先我们的资源肯定不是无限的,如果我们的资源是无限的,我们有非常非常多的服务资源,我们可能都不需要去设计一些比较优雅的系统了,你反正资源是够的,我们去对资源就够了对吧?问题我们的资源是有限的,我们要用有限的资源去做去完成是吧?很大的一体量,很大的一些工作,体量很大的一些业务,用有限的资源去干大事好。
- 反欺诈
因为秒杀它的特点肯定价格会比较低对吧?低于常规的价格。这里就会有一些黄牛党或者有一些黑产,他去想用我们的秒杀他去进行一个非法的牟利,比如他秒杀到了,秒杀到很多商品之后,他可以去做一些二次的售卖,所以反欺诈也是秒杀系统里面非常重要的一个环节。
- 高性能
这是一个实时性非常高的系统,所以我们对秒杀的性能要求也是非常高的。
- 防止超卖
比如我们去卖茅台,几千块钱一瓶,可能我们打完折可能就变得比较便宜了,比如打了 5 折,可能商家人家提供了 100 件商品,结果我们超卖了 1000 件。超卖的这些部分就是一个非常多的资损,这就是一个非常严重的事故了。
- 流量管控
因为我们的商品是有限的,它的流量是瞬时,流量也是比较高的,所以我们要对一些无用的流量去做一些拦截,甚至是过滤。
- 扩展性
理想的系统一定是扩展性非常高的。
- 鲁棒性
这个鲁棒性其实就是系统的稳定性和可用性,就是一个系统的可用性不达标,这个一定是一个不优雅不优秀的系统。这是我们提到的一些秒杀的挑战。
2.5 如何设计秒杀系统
4s 分析法:
2.5.1 场景(Scenario)
| 功能 | 并发 |
|---|---|
| 秒杀活动发布 | 万人参与秒杀 |
| 秒杀商品详情 | QPS 1w+ |
| 秒杀下单 | TPS 1k+ |
2.5.2 存储(Storage)
首先我们从左上角开始,这是一个类目表,类目标怎么理解?比如我们去线下的商场,我们的食货品其实都是分区的,比如我们有食品区对吧,有零食区在零食区,还有一些膨化食品区域,肉根肉脯类的一些区域。
这些其实就是我们在电商系统上的类目。其实在最传统的电商的时代,我们其实都是通过类目去,通过类目去搜索商品,去下单的。这里面的核心字段就是几级的比有parent, ID 代表它的父类目, name 就是这个类目的名字, level 代表它是几级类目, be parent 它是不是父节点, space 就是一个状态, OK 这是这个类目的概念。然后类目它对应的是会有一些类目的属性,包括它的类目的 ID 以及 attribute k 就是它属性的一些 k 以及状态。
上面 h specific 这是他的一个规格表。这个规格比如我们去买一个手机,它有哪些规格,比如它的颜色是吧,它的容量大小,这都是它的一个规格。
还有一个规格的详情表,这里面对于每一个规格,它对应的比如颜色,可能有紫色对吧,有红色,有白色等等。这些信息会组成,会也组成商品的属性。在商品的属性里面,除了类目规格,它还有它本身的一些店铺的ID,它的title,它的图片以及它的详情。这是这些会组成一个商品的信息。其实也是我们前面提到一个 SPU s k u 就是对商品的一个可销售单元,这里面终点的字段就是价格,库存以及它对应的对应到的具体的一个规格的ID。
在左面,它是用户的一些表以及用户的地址表
在右下角,这是一个活动表,这个活动会有活动的名字,开始时间,结束时间,状态,活动以及商品。再加上SKU,这会组成一个活动的商品。表为什么会这样做?因为我们秒杀活动,它对应的库存以及它的产品是要挂在秒杀活动下的,所以库存它就变成了秒杀活动的一个逻辑库存。所以有了表的设计。这个表里面比较关键的字段就是秒杀的价格以及秒杀的库存,然后这些秒杀的商品再加上它原本的商品信息,再加上用户以及这些属性,会最终会构成一个商品表。
2.5.3 服务(Service)
| 子服务 | 基础组件 |
|---|---|
| 用户服务 | ID 生成器 |
| 风控服务 | 缓存组件 |
| 活动服务 | MQ 组件 |
| 订单服务 | 限流组件 |
我们服务有哪些?子服务也就是由哪些个体去组成整体。首先子服务是有用户服务、风控服务、活动服务以及订单服务。当然这里面并不是每一个服务都去,我都去做了一个具体的实现。
比如风控服务其实就是一个 mock 的服务,因为如果都是因为风控,本身就是一个比较大的话题,在咱们秒杀系统设计里面,其实就没有去对它进行一个展开。它我在系统设计里面还有一些基础的组件,包括 ID 生成器,去生成订单ID,因为存储MySQL,如果我们使用MySQL,基本上也是分库分表,就会涉及到一个分布式 ID 的生成。这里就是用了一个 ID 生成器。下一个是缓存的组件,就是我们操作缓存所用到的一个组件。第三个就是 MQ 的组件, MQ 其实就是为了保护我们的系统去做一个。
第四个是限流组件,限流也是为了保护我们系统去提高稳定性的一些组件。它其实是现在做系统设计,在微服务时代,它是常非常常用的一个中间件,它一般会提供一个削峰、异步以及解耦的这样的一些功能。
2.5.4 扩展(Scale)
流量控制限流(基于速率或信号) 拦截,过滤,机房流量配比
第四部分扩展。在这一部分其实也会涉及到比较多的概念,比如首先我们的流量秒杀系统的流量应该是和常规的电商的流量是要去做一个隔离的,为了防止秒杀流量过高,影响到其他的非秒杀商品的一个下单的这样的流量,常规的流量。
第二个是扩展到使用 CDN 去做一些静态资源的缓存。 CDN 其实是内容分发网络,其实它是一个提高性能,提高静态资源的访问非常有效的这样的一个工具,其实各大公司其实都采用到了,因为我们发起一个请求的时候,如果响应你请求的服务离你越近,肯定是响应时间就会越快对吧? CDN 就是离你非常近的这样的一些节点,还要去做缓存的一些优化,流量的一些管控,包括流量拦截和流量过滤。除此之外,还有比如我们要对数据库去做扩展,比如最基础的我们要做读写的分离,或者再扩展成分库、分表。
服务也要去做扩展,比如服务的水平扩展,可能这里会涉及到负载均衡。反向代理 m q 的扩展。 m q 本身我们也要保证它的是它的可用性和稳定性,这里比如有主从的架构,以及多主多从的架构,这是对 MQ 的一个扩展。
Redis 这里也是,比如读写分离,或者用它的一柱多从集群的这样的一个模式去保证它的可用性和稳定性。
最后一个就是服务的垂直扩展,这里大家就可以理解成给他去做微服务的一个拆分。
2.5.5 系统架构图
我们秒杀系统用户层,比如有他可以用网页去下单,可以用安卓、iOS 等手机端下单。
接入层因为是一我们系统设计其实是用了Nginx,在比较大的互联网应用里面,其实在吉Nginx上面其实还有一些类似 lvs 这样的一些组件,但是我们系统就没有用到了应用层,其实就是我们其实就可以理解为我们代码其实就是应用层的。我们要用应用层去接收请求对吧?要处理业务逻辑,这里就有我们前面所提到这些功能,以及那些组件。
基础层,这里就是Redis、 rocketm code、 MySQL 用到的一些基础的中间件。
3.课程实践
秒杀流程图
首先用户进入抢购页面,他点下单。在秒杀系统里面,我们会去做登录校验,用 user 服务去做登录校验,风控校验以及活动的状态信息校验,再去预扣库存。如果校验都通过之后,我们就去扣库存。当这些工作都完成之后,我们会把订单发送到 mq 里,去做一个削峰订单服务会去消费 mq,消费到 MQ 之后,它会去调起支付系统去做一个支付,也会去真正地去扣减一个 MySQL 里面的库存。如果订单,比如我们现在下单,它会有一个超时检查的,比如可能是 15 分钟或者 30 分钟。如果下完单,你没有支付,它会取消你订单。取消订单或者下单失败,我们也要去做一个库存的回补,把前面扣减的库存去回补到MySQL,刷新到Redis 里面。
4.课程总结
高性能系统的通用设计思想:
首先第一个就是服务无状态,现在大家应该都听到过什么云原生,什么serverless,其实说白了,服务无状态其实就是这个玩意儿,因为我们的服务是无状态的,我们可以在云原生的时代可以做横向扩展,可以用 K8S 去做非常快的横向扩展,比如从 100 个实例扩展到 1000 个。这是服务的无状态。无状态怎么理解?其实就是当前的应用服务不存储状态,不存储数据。
第二个是批量写入,刚才其实也看到了,我在很多地方用到了一个 insert batch,对吧?批量写入其实在消费者其实也是用了批量的,大家可以看一下这个参数 pool bash size。这也是用了一个批量获拉取消息,再去做一个处理。批量写入其实是降低我们系统压力的一个非常有效的方式,在很多高 qbs 的接口以及非常大数据量的一个 MySQL 的写入,其实都用到了批量写入,包括MySQL,它本身的一些设计上,它也在内部设计上,它也用了一些可能多个事物的一些批量写入,叫做提交。
第三个就是最终一致性。这个最终一致性其实就是解释了我们用 Redis 做缓存以及用 MQ 这些东西,其实都会产生新的数据副本去导致数据可能有短暂的不一致,但是最终其实都是会达到最终一致性。
个人总结
- 系统设计就是将各个服务、模块、扩展等个体,有机合理安排组成成一个复杂的整体,每个个体之间有机配合,各尽其职,以符合我们的需求。
- 4s 分析法设计系统
- 优化瓶颈,验证可用性和稳定性,保证可扩展性