如何设计一个秒杀系统
Table of Contents
本文章是极客时间 《如何设计一个秒杀系统》 的学习笔记
1 开篇词 秒杀系统都有哪些关键点
秒杀系统主要解决两个问题:并发度和并发写。
并发读的优化理念:尽量减少用户到服务端来“读”数据,或者让他们读更少的数据。
并发写的优化理念:在数据库层面独立出来一个库,做特殊处理。
实践原则:
- 用户请求的数据尽量少: 动静分离。
- 请求数尽量少: 根据 UID、IP 限流。
- 路径尽量短,依赖尽量少。
- 不要有单点。
优化路径:
- 前端秒杀页面:
- 动静分离
- 限流(比如限制页面刷新或者点击)
- 中间代理:
- 限流,nginx 限制请求并发
- 分流,对请求 hash
- 负载均衡和横向扩容
- 后端服务
- 限流防刷
- 横向扩容
- 业务分离,不影响正常业务
- 异步处理,如消息队列
- 数据层:
- 分库分表
- 读写分离
- 缓存读写,异步落盘
- 业务分离
架构特性:
- 高性能:数据动静分离、热点发现与隔离、请求的削峰和分层过滤、服务端极致优化
- 一致性:减库存
- 高可用:Plan B
2 01 设计秒杀系统时应该注意的 5 个架构原则
架构原则:4要 1 不要:
- 数据要尽量少,减少 CPU 消耗。
- 请求数要尽量少。减少加载时间。实践:合并 css 和 js 文件。
- 路径要尽量短,减少节点消耗。
- 依赖要尽量少。
- 不要有单点。避免服务状态和机器绑定,即服务无状态化。
3 02 如何才能做好动静分离
如何缓存静态数据:
- 把静态数据缓存到离用户最近的地方。
- 静态化改造就要要直接缓存 HTTP 链接。
- 使用 nginx 等更擅长处理大并发静态文件的 web 服务请求做反向代理。
如何做动静分离:
- URL 唯一化。
- 分离浏览者相关的因素。
- 分离时间因素。
- 异步化地域因素。
- 去掉 cookie。
动态数据处理方案:
- ESI 方案:web 代理请求动态内容。服务端性能有影响,但是用户体验好。
- CSI 方案:浏览器单独发起异步 JS 请求。服务端性能更好,但是用户端演示,体验稍差。
静态资源存储的方案:
- 实体机单机部署。
- 优点:没有网络瓶颈、能提升命中率,减少数据压缩和序列化、减少 cache 失效压力。
- 缺点:物理机器浪费,提高了运维复杂度。
- 统一 cache 层。
- 优点:减少运维成本,方便接入其他静态化系统,共享内存,减少物理机成本。
- 缺点:cache 内部交换网络瓶颈,不要存在单点。
- 上 CDN
- 优点:离用户近,效果更好。
- 缺点:失效问题,命中率问题,发布更新问题。
- 选择 CDN 二级 cache:
- 靠近访问量比较集中的地区。
- 离主站相对较远
- 节点到主站间的网络好且稳定
- 节点容量比较大。
4 03 二八原则:有针对性的处理好系统的“热点”
- 热点数据
- 静态热点数据,买家报名
- 动态热点数据
- 热点发现,异步系统分析数据后预热
- 热点反馈,热点保护,热点数据隔离
- 热点操作:限流、缓存热点数据。
5 04 流量削峰这事应该怎么做
削峰思路:
- 排队:消息队列
- 答题:防刷,延缓请求。
- 分层过滤:过滤无效请求
6 05 影响性能的因素有哪些?又该如何提高系统的性能
性能指标:
- QPS
- RT
查看 CPU 瓶颈:JProfiler 和 Yourkit
7 06 秒杀系统“减库存”设计的核心逻辑
减库存操作:
- 下单减库存:恶意下单
- 付款减库存:超卖
- 预扣减库存:
- 缺点:恶意下单
- 解决:买家打标,最大购买件数,重复下单不付款的操作次数进行限制。
大型秒杀推荐使用下单减库存的方式:
- 通过事务保证减后库存不能为负数,否则就回滚。
- 字节设置数据库字段为无符号整数,减后数据库字段小于 0 就报错。
使用 case when 语句
UPDATE item SET inventory= CASE WHEN inventory>=xxx THEN inventroy-xxx ELSE inventory END
减库存优化:
- 使用 redis:适用简单场景
- 使用 mysql:
- 应用层排队:按照商品设置队列,单个商品为一个队列。
- 数据库层排队:阿里做了 InnoDB 补丁。
8 07 准备 Plan B:如何设计兜底方案
- 降级,非核心功能
- 限流,
- 拒绝服务