这是我参与「第五届青训营」伴学笔记创作活动的第 8 天
如何设计
-
场景分析:
什么系统需要哪些功能,多大的并发量
-
存储设计:
数据如何组织(Sql,NoSql)
-
服务设计
业务功能实现与逻辑整合
-
可拓展性
解决设计缺陷,提高健壮性
通过以下三种方式可以对系统瓶颈进行分析:
- 火焰图
- 链路追踪
- 性能测试
保证系统可用性
设计秒杀系统
需求分析
秒杀系统需要涉及以下三个方面:
- 消费者端
- 商家端
- 线上电商环境
而秒杀业务则具有以下几个特点:
- 瞬时流量高
- 读多写少
- 实时性要求高
系统同时需要面对以下几种挑战:
设计系统
而从上文所提及的四个方面对秒杀系统进行设计:
-
场景:
- 功能:
- 秒杀活动发布
- 商品详情
- 秒杀下单
- 并发:
- qps 1w+
- TPS 1k+
- 功能:
-
存储:
存储采用三层解决方案:mysql+redis+localcache
-
服务:
将服务进行拆分,同时也包含服务需要的基础组件:
- 服务
- 用户服务
- 风控服务
- 活动服务
- 订单服务
- 基础组件
- ID生成
- 缓存组件
- MQ组件
- 限流组件
- 服务
-
服务拓展部分:
系统实现
为什么使用redis
秒杀系统,是典型的短时大量突发访问类问题。
而秒杀系统通常分为三个阶段,每个阶段redis的作用也不尽相同:
-
秒杀开始前
在这个阶段,用户会不断刷新商品详情页,这会导致详情页的瞬时请求量剧增。这个阶段的应对方案,一般是尽量把商品详情页的页面元素静态化,然后使用CDN或是浏览器把这些静态化的元素缓存起来,将流量拦截在服务端外,减轻服务器压力,在这个阶段不需要使用redis
-
秒杀开始
简单来说,这个阶段的操作就是三个:库存查验、库存扣减和订单处理。因为每个秒杀请求都会查询库存,而请求只有查到有库存余量后,后续的库存扣减和订单处理才会被执行。所以,这个阶段中最大的并发压力都在库存查验操作上。
为了支撑大量高并发的库存查验请求,我们需要在这个环节使用Redis保存库存量,这样一来,请求可以直接从Redis中读取库存并进行查验。
而在秒杀过程中,针对于订单操作我们应在数据库层面进行操作,而针对库存我们并不应该直接操作数据库
- 当数据库进行库存更新时,需要对redis中的库存数据进行同步,这个过程增加了额外的操作逻辑,也带来了额外的开销。
- 当过多请求直接修改数据库,由于对于行锁的争夺,数据可能并不能及时进行修改,从而导致下单量超过实际库存出现超售,而redis操作是单线程的,可以避免该问题的发生
所以,我们就需要直接在Redis中进行库存扣减。具体的操作是,当库存查验完成后,一旦库存有余量,我们就立即在Redis中扣减库存。而且,为了避免请求查询到旧的库存值,库存查验和库存扣减这两个操作需要保证原子性。
-
秒杀活动结束后:
在这个阶段,可能还会有部分用户刷新商品详情页,尝试等待有其他用户退单。而已经成功下单的用户会刷新订单详情,跟踪订单的进展。不过,这个阶段中的用户请求量已经下降很多了,服务器端一般都能支撑。而有关订单超时取消的部分,也可以利用mq进行解决
引用
部分内容来自:
- 「【实践课】手把手教你做系统设计」第五届字节跳动青训营 - 后端专场
- Redis支撑秒杀场景的关键技术和实践都有哪些