前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >猿创|可能是最快的高并发单机秒杀系统设计方案

猿创|可能是最快的高并发单机秒杀系统设计方案

作者头像
猿哥
发布2019-07-24 22:21:52
7660
发布2019-07-24 22:21:52
举报
文章被收录于专栏:Web技术布道师Web技术布道师

文章截图

点击图片,手动扩大图片即可清晰查看

下面的排版可能引起阅读不适

下面是我的答案,与 PHP 和 MySQL 没什么关系,因为本人认为高并发是不能到 PHP 处理和 MySQL 层面的,

目前比较理想的架构是 openresty + Redis,详见下文

推荐软硬件环境

1 Redis 最新稳定版

https://redis.io/download

$ wget http://download.redis.io/releases/redis-5.0.3.tar.gz $ tar xzf redis-5.0.3.tar.gz $ cd redis-5.0.3 $ make # 可以加上多核编译参数 -j2 表示使用 2 cpus $ sudo make install $ cd utis/ $ sudo ./install_server.sh # 一直回车 (Enter) $ sudo service --status-all |grep redis # 查看 redis 服务进程状态

2 Openresty 最新稳定版

http://openresty.org/en/installation.html

http://openresty.org/cn/installation.html(中文)

推荐安装方式:

http://openresty.org/en/linux-packages.html

http://openresty.org/cn/linux-packages.html(中文)

3 tree 和 htop

主要是便于查看文件树信息和进程信息

4 网络带宽临时调大至 10M/s-30M/s

峰值流量可能会很大

5 SSD 固态硬盘不可少

Redis 持久化必选项

实例分析

0 活动描述

现有商品 A(sku_id=1) 、B(sku_id=2) 、C(sku_id=3),要求 2018.12.15 当天的 10:30-11:00 开放秒杀数量: A(1000 件)、B(2000 件)、C(3000 件) 与 14:30-15:00 开放秒杀数量:A(1000 件)、B(2000 件)、C(3000 件),

每次秒杀活动持续 30 分钟,每人限购:A(1 件)、B(2 件)、C(3 件)

1 刷入商品信息(难度系数:★★)

步骤:

第一步,刷入 sku 秒杀数量的数据到 Redis 的 List 数据结构中

刷入 sku_id 为 1 的商品 A 到 ms1544841000_1544842800:sku1 和 ms1544841000_1544842800:sku_copy1(备份) 中(B、C 商品类似),其中1544841000_1544842800 表示活动开始的 unix 时间戳(精确到秒)和活动结束的 unix 时间戳(精确到秒),要求在活动开始前成功刷入数据,也就是分别在 10:30 之前和 14:30 之前,例如:

1,1,1,1,.....# 存入商品 sku_id 即可,但是也可以存入商品的其它信息,例如让用户秒杀到一样的价格,这时最好以 json 格式存储

第二步,设置列表的过期时间

使用 Redis 的 expireat 命令来指定 11:00 的 unix 时间戳(精确到秒)为过期时间,仅需要设置 key 为 ms1544841000_1544842800:sku1 即可,另一个 key 为 ms1544841000_1544842800:sku_copy1 仅用于记录

第三步,刷入历史活动信息列表到 Redis 的 key 为 act_hmap_20181215 的 hashmap 数据结构

注意,act_hmap_20181215 这个 key 是以天为单位的。

key:1_1544841000_1544842800 value:{"sku_id":1,"start":1544841000,"end":1544842800,"total":1000,"limit":1,"rest":1000} #其中 rest 表示剩余数量,用于提供给 API 接口,以及其它 sku 信息字段,不过我建议使用指定的 sku Redis key 来保存

2 前端展示秒杀活动信息(难度系数:★)

步骤:

第一步,前端通过 API 接口获取 2018.12.15 当天的活动列表 act_hmap_20181215,并按照 hashmap 的 key 排序

第二步,展示必要的 sku 信息字段

商品图片 URL 列表,自定义字段键值对,活动开始时间与结束时间等,建议活动以外的周边信息如 sku 详细信息与商铺信息应该放在其它 Redis key 中,以便于跟 MySQL 数据库同步

3 活动进行中(难度系数:★★★)

步骤:

第一步,秒杀资格检查+避免刷单

最好是让有秒杀资格的人来参与秒杀,存入到 Redis 缓存中,没有资格的人连秒杀的商品界面都不要展示出来,

为了避免机器刷单的情况,考虑加入 WAF (web 防火墙)和 单用户 Id 调用频率的控制问题,如指定用户 ID 出现异常行为,应该立刻把此用户 ID 禁用掉,或者展示图形验证码+短信验证码的形式,通过验证就可以再次秒杀。

第二步,避免重复下单

应该使用使用 act:1_1544841000_1544842800:user_12 这种形式的 Redis Key 来判断是否重复下单,Redis 的 setnx 可以帮你忙,

第三步,不要使用 MySQL

下单过程中,切记不可使用 MySQL,高并发的主要瓶颈之一,推荐架构:Openresty + Redis + MySQL(MySQL 最好放到另一台机器上,因为它太笨重了)

第四步,异步化订单处理

支付之后,系统需要生成秒杀订单数据(业务逻辑最重的环节),并调用第三方支付接口,这时可以先把信息放到 Redis 的 List 数据结构中,鉴于单机,所以这里不建议使用 Rabbit MQ,

因为它过重了,然后以恒定的速度向 MySQL 持久化订单信息以及同步 Redis 里面的秒杀订单数据,在此期间展示的秒杀订单状态是“支付结果处理中”,处理成功后,则在秒杀订单列表页展示对应的订单信息。

第五步,超量检测

由于使用了 Redis 的 List 数据结构,为了保证秒杀的成功率,秒杀成功则从里面 lpop 出指定数量的数据,应该只给用户的未支付秒杀订单 20 秒的倒计时支付时间,

如超过 20 秒未支付,则无法再次从本次活动中秒杀,并把没有秒杀成功的 sku 回收到该 List 中且最好把待回收(已锁定)数量也展示出来,因为使用了 List 数据结构,所以就算 lpop 到最后也不会出现超量的情况,但是却可能引发下面的问题:

问题1:明明前端展示还剩 20 件商品未秒杀完,为何我点击购买时却提示我秒杀完成

答:因为前端展示的数据跟服务器上面的数据并非实时同步的

4 活动结束后

这个就与并发没有什么关系了,主要是统计一下数据与核对订单信息什么的

同步更新的原文链接:http://note.youdao.com/noteshare?id=346f9e43a25b8fda1bb8f7c4722c9abd&sub=C629D330B273472AB9407E767F6B39A3

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PHP技术大全 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档