秒杀-常见系统设计

7,334 阅读6分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路

# 我们一起进大厂》系列-秒杀系统设计

Scenario 场景分析

• 具体场景有哪些? • 实际需求有什么? • 详细流程怎么样?

  1. 服务器、数据库等能承载的 QPS 有限,如数据库一般是单机 1000 QPS。需要根据业务预估并发量。

  2. 有限库存,不能超卖 库存是有限的,需要精准地保证,就是卖掉了 N 个商品。不能超卖,当然也不能少卖了。

  3. 使用脚本模拟用户购买,模拟出十几万个请求去抢购。

  4. 时间到了才能购买,提前一秒都不可以(以商家「京东」「淘宝」的时间为准)。

  5. 一个用户,只能购买 1 个或 N 个。

并发导致超卖的问题如何解决?

使用 UPDATE 语句自带的行锁

  1. 查询库存余量 SELECT stock FROM stock_info WHERE commodity_id = 189 AND seckill_id = 28;

  2. 扣减库存 UPDATE stock_info SET stock = stock - 1 WHERE commodity_id = 189 AND seckill_id = 28 AND stock > 0;

超卖问题解决了,其他问题呢? 对于抢购活动来说,可能几十万人抢 100 台 iPhone,实际大部分请求都是无效的,不需要下沉到 MySQL。

秒杀操作 - 库存预热 --直接通过 Redis 来判断并扣减库存

秒杀的本质,就是对库存的抢夺。 每个秒杀的用户来都去数据库查询库存校验库存,然后扣减库存,导致数据库崩溃。 MySQL 数据库单点能支撑 1000 QPS,但是 Redis 单点能支撑 10万 QPS,可以考 虑将库存信息加载到 Redis 中。

直接通过 Redis 来判断并扣减库存.

一种主要将数据存储于内存中的非关系型的键值对数据库 (NoSQL 的一种) ,但也可以将数据持久化

(Data Persistence) 到磁盘中。

支持多种数据非关系型的数据结构。 1.字符串/数字 (STRING) 2.哈希表 (HASH) 3.链表 (LIST) 4.集合 (SET) 5.有序集合 (ZSET)

单线程的数据库。通过IO多路复用实现并发。 支持数据的主备容灾 (Disaster Tolerance) 存储。

所有单个指令操作都是原子的,即要么完全执行成功,要么完全执行失败。多个指令也可以通过 Lua 脚本事务操作实现原子性。

因为都在内存中操作,性能极高,单机一般可支撑 10万数量级的 QPS。 可用作数据缓存 (Cache)、数据持久存储和消息队列 (Message Queue)。

通过 Lua 脚本执行原子操作

Lua 脚本功能是 Reids 在 2.6 版本中推出, 通过内嵌对 Lua 环境的支持, Redis 解决了长久以来不能高效地处理 CAS (check-and-set)命令的缺点, 并且可以通过组合使用多个命令, 轻松实现以前很难实现或者不能高效实现的模式。Lua 脚本是类似 Redis 事务,有一定的原子性,不会被其他命令插队,可以完成一些 Redis 事务性的操作。

消息队列(Message Queue,MQ)进行削峰

如果秒杀数量是1万台,或者10万台呢? 因为 Redis 和 MySQL 处理能力的巨大差异。实际下沉到MySQL 的量还是巨大,MySQL 无法承受。

解决思路

可不可以在通过 Redis 扣库存后,到 MySQL 的请求慢一点?

通过消息队列(Message Queue,MQ)进行削峰(PeakClipping)操作。

通过消息队列异步地创建订单(削峰)

如果消息队列出现部分投递失败怎么办?

Redis 中的库存量,可以比实际的库存量多一点,比如 1.5 倍或者 2倍。

image.png

库存扣减时机

下单时立即减库存。(可能被恶意下单)

用户体验最好,控制最精准,只要下单成功,利用数据库锁机制,用户一定能成功付款。 可能被恶意下单。下单后不付款,别人也买不了了。

先下单,不减库存。实际支付成功后减库存。

可以有效避免恶意下单。 对用户体验极差,因为下单时没有减库存,可能造成用户下单成功但无法付款。

下单后锁定库存,支付成功后,减库存。(20分钟锁定区?)

如何限购?

使用 Redis 提供的集合数据结构,将扣减 Redis 库存的用户 ID 写入。

付款和减库存的数据一致性()--如果是分布式的话 -- 分布式事务

Scale 拓展--如何优化系统--加分项

是否有遗漏什么功能?

image.png

防止刷爆商品页面 - cdn

CDN 的全称是 Content Delivery Network,即内容分发网络。

CDN 是依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。

防止刷爆商品页面 - cdn 前端限流 点击一次后,按钮短时间内置灰

部分请求直接跳转到「繁忙页」

防止刷爆商品页面

未开始抢购时,禁用抢购按钮。 如何计算倒计时?

  1. 打开页面获取活动开始时间,然后前端页面开始倒计时。
  2. 打开页面获取距离活动开始的时间差,然后前端页面开始倒计时。
  3. 前端轮询 (Poll) 服务器的时间,并获取距离活动开始的时间差。

image.png

新的问题

秒杀服务器挂掉,怎么办?(分布式问题)

尽量不要影响其他服务,尤其是非秒杀商品的正常购买。

服务雪崩 (Avalanche) -- 服务熔断机制

多个微服务之间调用的时候,假设 微服务A 调用 微服务B 和 微服务C,微服务B 和微服务C 又 调用其他的微服务,这就是所谓的”扇出 (Fan-out)”,如扇出的链路上某个微服务的调用响应 式过长或者不可用,对 微服务A 的调用就会占用越来越多的系统资源,进而引起系统雪崩,所 谓的”雪崩效应”。

服务雪崩效应是一种因“服务提供者”的不可用导致“服务消费着”的不可用并将这种不可用 逐渐放大的过程。

尽量不要影响其他服务,尤其是非秒杀商品的正常购买。

服务熔断 (Fuse or Circuit-breaker)

熔断机制是应对雪崩效应的一种微服务链路保护机制,当扇出链路的某个微服务不可用或者响应时 间太长时,熔断该节点微服务的调用,快速返回”错误”的响应信息。当检测到该节点微服务响应 正常后恢复调用链路。

Netflix Hystrix Alibaba Sentine

防止恶意刷请求或者爬虫请求

验证码机制

抢购-》填写验证码 -》 进入抢购服务 改进:识别是否机器人

限流机制

抢购-》是否来自同一个IP地址 -》 是否来自同一个用户id-》进入抢购服务

黑名单机制

1.黑名单IP地址 2.黑名单用户ID