java多线程    Java入门    vsftp    ftp    linux配置    centos    FRP教程    HBase    Html5缓存    webp    zabbix    分布式    neo4j图数据库    

电商秒杀系统设计

秒杀活动对稀缺或者特价的商品进行定时定量售卖,吸引成大量的消费者进行抢购,但又只有少部分消费者可以下单成功。因此,秒杀活动将在较短时间内产生比平时大数十倍,上百倍的页面访问流量和下单请求流量。

秒杀活动可以分为3个阶段:

秒杀前:用户不断刷新商品详情页,页面请求达到瞬时峰值。
秒杀开始:用户点击秒杀按钮,下单请求达到瞬时峰值。
秒杀后:一部分成功下单的用户不断刷新订单或者产生退单操作,大部分用户继续刷新商品详情页等待退单机会。

假设一个场景:今晚20:00秒杀100个iphone

1. CDN流量拦截

详情页在秒杀前5分钟大量流量进入,大家都在刷,用CDN做分发。避免服务器挂。

2. 利用读写分离Redis缓存拦截流量

静态的商品可以用CDN,但是那个开始秒杀的按钮在秒杀前20:00前一直是‘未开始’,到了20:00准时要变成’立即秒杀‘按钮
用个JS来刷这个按钮的状态。JS请求一个后端代码,只返回0未开始,1 开始了。

提前将秒杀商品缓存到读写分离Redis,并设置秒杀开始标记如下:

"goodsId_count": 100 //总数
"goodsId_start": 0   //开始标记
"goodsId_access": 0  //接受下单数

p1.秒杀开始前,服务集群读取goodsId_Start为0,直接返回未开始。
p2.数据控制模块将goodsId_start改为1,标志秒杀开始。
p3.服务集群缓存开始标记位并开始接受请求,并记录到Redis中goodsId_access,商品剩余数量为(goodsId_count - goodsId_access)。
p4.当接受下单数达到goodsId_count后,继续拦截所有请求,商品剩余数量为0。

可以看出,最后成功参与下单的请求只有少部分可以被接受

3. 利用主从版Redis缓存加速库存扣量

库存的扣减,是个秒杀的关键部分,利用redis集群redisson来实现分布式锁的机制进行唯一扣减。
避开多台服务器,同时扣减库存发生超卖情况。

具体请参考上一片关于分布式锁的说明。https://java-er.com/blog/redis-dist-lock/

4. 使用主从版Redis实现简单的消息队列异步下单入库

如果秒杀的时候服务器去操作数据库会导致数据库挂掉,在高并发场景下秒杀基本会在1分钟内完成全部库存扣减,商品卖光。

当秒杀服务将订单信息写入消息队列后,即可认为下单完成,避免直接操作数据库。

消息队列组件依然可以使用Redis实现,在R2中用list数据结构表示。

 orderList {
     [0] = {订单内容} 
     [1] = {订单内容}
     [2] = {订单内容}
     ...
 }

将订单内容写入Redis:
LPUSH orderList {订单内容}

异步下单模块从Redis中顺序获取订单信息,并将订单写入数据库。
BRPOP orderList 0
通过使用Redis作为消息队列,异步处理订单入库,有效的提高了用户的下单完成速度。

当异步处理下单完成,主接口读取订单信息反馈给客户。

5.秒杀防止无效流量和恶意刷新

  1. 前端 JS 控制下单按钮不能重复点击。
  2. 通过 nginx 服务器限流配置使同一 IP 频率限制(比如一秒不超过10次,一秒能刷10次,那是机器人),如果超过限制则返回 500 状态码。

参考资料
https://help.aliyun.com/document_detail/63920.html
https://learnku.com/articles/28338


This entry was posted in JAVA and tagged , , , . Bookmark the permalink.
月小升QQ 2651044202, 技术交流QQ群 178491360
首发地址:月小升博客https://java-er.com/blog/second-kill-system-design/
无特殊说明,文章均为月小升原创,欢迎转载,转载请注明本文地址,谢谢
您的评论是我写作的动力.

Leave a Reply