竞拍系统设计(秒杀系统知识迁移)(代码片段)

sengerlion sengerlion     2022-12-10     531

关键词:

自从上次整理了秒杀系统的文章(php+golang商品秒杀)后,知识迁移一新项目,商品竞拍。

技术:php、mysql、redis、laravel
业务对象:商品、场次、订单
竞拍过程:

一、实现商品、竞拍场次和订单的CRUD;
二、定时将秒杀场次、商品、库存等信息提前写入redis;
三、配置Redis持久化;
四、实现秒杀下单逻辑;
五、秒杀过程redis优化;
六、使用golang并发编程模拟秒杀。

一、实现商品、竞拍场次和订单的CRUD;

商品表:

 CREATE TABLE `goods` (
  `id` int(12) unsigned NOT NULL AUTO_INCREMENT COMMENT \'pk\',
  `num` varchar(64) NOT NULL COMMENT \'商品编号\',
  `users_id` int(12) unsigned NOT NULL COMMENT \'拥有者\',
  `create_users_id` int(12) unsigned NOT NULL COMMENT \'商品创建人\',
  `name` varchar(255) NOT NULL COMMENT \'商品名称\',
  `img` int(11) NOT NULL COMMENT \'封面图\',
  `price` decimal(10,2) unsigned NOT NULL COMMENT \'当前价格\',
  `area_id` int(11) NOT NULL COMMENT \'区域id\',
  `user_name` varchar(100) DEFAULT NULL COMMENT \'收货人名称\',
  `user_phone` varchar(11) DEFAULT NULL COMMENT \'收货人联系电话\',
  `user_address` varchar(255) DEFAULT NULL COMMENT \'收货人地址\',
  `express_id` int(11) DEFAULT NULL COMMENT \'物流ID\',
  `express_no` varchar(255) DEFAULT NULL COMMENT \'物流单号\',
  `is_auction` tinyint(1) NOT NULL DEFAULT \'1\' COMMENT \'是否可竞拍,1=》可 2=》不可\',
  `status` tinyint(1) unsigned NOT NULL DEFAULT \'1\' COMMENT \'状态1=>可交易 2=>待支付 3=>交易完成 4=>待发货 5=》配送中 6=>完成 7 =>待收款\',
  `next_time` timestamp NULL DEFAULT NULL COMMENT \'下次最早显示时间\',
  `trade_time` timestamp NULL DEFAULT NULL COMMENT \'下次可交易时间\',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT \'创建时间\',
  `updated_at` timestamp NULL DEFAULT NULL COMMENT \'更新时间\',
  `deleted_at` timestamp NULL DEFAULT NULL COMMENT \'删除时间\',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

竞拍场次表:

CREATE TABLE `auctions` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT \'ID\',
  `area` tinyint(4) NOT NULL,
  `name` varchar(64) DEFAULT NULL COMMENT \'场次名称\',
  `start` time NOT NULL COMMENT \'开始时间\',
  `end` time NOT NULL COMMENT \'结束时间\',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT \'创建时间\',
  `updated_at` timestamp NULL DEFAULT NULL COMMENT \'更新时间\',
  `deleted_at` timestamp NULL DEFAULT NULL COMMENT \'删除时间\',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT=\'拍卖场次表\';

订单表:

CREATE TABLE `orders` (
  `id` int(12) unsigned NOT NULL AUTO_INCREMENT COMMENT \'pk\',
  `serial_num` varchar(32) DEFAULT NULL COMMENT \'流水号,没交易前为空\',
  `goods_id` int(12) unsigned NOT NULL COMMENT \'商品id\',
  `sell_users_id` int(12) unsigned NOT NULL,
  `buy_users_id` int(12) unsigned DEFAULT NULL,
  `buy_price` decimal(10,2) NOT NULL COMMENT \'购买价格\',
  `pay_time` datetime DEFAULT NULL COMMENT \'支付时间\',
  `status` char(5) NOT NULL COMMENT \'状态10000=>待支付  20000=>支付超时 30000=>支付完成 30001=>配送中 50000=>完成\',
  `remark` varchar(255) DEFAULT NULL COMMENT \'备注\',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT \'创建时间\',
  `updated_at` timestamp NULL DEFAULT NULL COMMENT \'更新时间\',
  `deleted_at` timestamp NULL DEFAULT NULL COMMENT \'删除时间\',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

二、定时提前写入redis

1、竞拍场次定时提前写入并设置过期时间。

2、缓存数据结构设计有两个版本:

a、第一个版本的数据结构设计在商品列表查询时,无法排除自身商品信息并且分页。

  • 不同区域可秒杀的用户set (判断用户所属竞拍区)

    key: prefix + area_id + start + end + auctions_id, 
    value:uid 
    
  • 不同区域下的商品信息zset (可支持分页)

    key: prefix + area_id + start + end + auctions_id, 
    score:goods_id, 
    member:goods_detail
    
  • 库存字面量

      key: random  
      value:1 
  • 是否购买占位

     key: prefix + area_id + start + end  
     value:1 
为了满足排除自身的商品功能和分页,思考了一些实现方案:
(1) 完全放弃从缓存中获取竞拍商品信息,这样增加数据库压力,同时无法使用竞拍随机码。
(2)为每个用户单独存放一个排除自身商品信息的集合,这样会存放重复数据造成增加内容空间。
(3)查询到redis有一个SCAN命令来迭代获取数据,并可利用glob模式匹配,但是获取数量无法确定而无法分页。
以上(1)(3)点都被排除,我们从第(2)出发重新设计第二版数据结构,单独存放商品数据和用户可查询的商品id集合来减少重复,但又会出现keys过多的情况,需要进行优化。

b.第二个版本的数据结构设计

  • 用户可查询的商品id的zset (判断用户是否有可竞拍商品)
 key: prefix + area_id +users_id + auction_id+ start + end, 
 score:goods_id, 
 member:goods_id 
  • 商品信息string (可支持分页)
 key: prefix + area_id + auction_id + goods_id + start + end, 
 value:goods
  • 库存字面量
 key: random  
 value:1 
  • 是否购买占位
  key: prefix + area_id + start + end  
  value:1 

三、配置Redis持久化

持久化两种模式都开启:RDB(快照模式)+ AOF(日志模式)
配置文件:save/append_only
区别:两者数据保存间隔周期不同,RDB存储间隔大于AOF存储间隔

四、实现秒杀下单逻辑

1、查询场次和当前秒杀商品
查询redis中的缓存数据,当并发量大时可能出现:
缓存穿透:key值不存在,重复请求压垮数据库 => 布隆过滤器或设置缓存为空。
缓存击穿:key值存在但是失效,需重新请求数据库造成并发问题 => SETNX锁
缓存雪崩:缓存重启或集中失效,则都请求往DB => 过期时间设置分散

2、正式竞拍是单独的秒杀下单功能。

3、具体的下单逻辑:
登录校验 => 秒杀过程校验 => 通过队列进行异步下单同时返回订单号orderSN
秒杀过程中校验点如下:

秒杀时间:是否在秒杀时间内;
用户是否在该区有可竞拍商品
随机码:商品是否可秒杀;
是否已购买过:通过redis的SETNX设置Key=场次id_商品id_用户id来判断是否购买过。
秒杀库存数量:在获取对应库存信息前,将随机码作为key设置SETNX来实现并发锁,设置超时时间,秒杀成功或失败都释放该锁。

五、秒杀过程redis优化

因缓存数据结构的设计,可能会在redis存储大量的key,若通过keys命令查询会是O(n)复杂度,查询会卡顿而缓慢,redis有提供scan迭代来代替keys,但是根据本项目无需使用它。
优化大致有两个方面:
1、在提前将竞拍信息写入redis时,因key数量大,可采用redis的pipeline管道来提高写入效率
2、尽可能将场次和开始结束时间返回前端让其在查询或竞拍时传给后端,后端拼接key值获取数据的时间复杂度是O(1)。

六、使用golang并发编程模拟秒杀

图片请参考另外一篇文章:PHP+Golang 商品秒杀功能
================================================================

golang并发调度项目码云:

https://gitee.com/jasonlxs/se...

秒杀系统——秒杀功能设计理念(代码片段)

文章目录电商系统下单功能概述订单量:从0到1000(架构1)订单量:从1000到100万锁机制悲观锁乐观锁分布式锁消息队列消息队列:架构2从电商系统到秒杀系统流量限制热门资源隔离最终:架构3总结1.秒杀... 查看详情

秒杀系统——秒杀功能设计理念(代码片段)

文章目录电商系统下单功能概述订单量:从0到1000(架构1)订单量:从1000到100万锁机制悲观锁乐观锁分布式锁消息队列消息队列:架构2从电商系统到秒杀系统流量限制热门资源隔离最终:架构3总结1.秒杀... 查看详情

电商 秒杀系统 设计思路和实现方法(代码片段)

电商 秒杀系统 设计思路和实现方法2017年05月26日00:06:35阅读数:36621秒杀业务分析正常电子商务流程(1)查询商品;(2)创建订单;(3)扣减库存;(4)更新订单;(5)付款;(6)卖家发货秒杀业务的特性(1)低廉价格... 查看详情

一个秒杀系统的设计思考,超详细!(代码片段)

...购买同一商品并完成交易的过程。从架构视角来看,秒杀系统本质是一个高性能、高一致、高可用的三高系统。而打造并维护一个超大流量的秒杀系统需要进行哪些关注,就是本文讨论的话题。整体思考首先从高维度出发,整体... 查看详情

面试必考:秒杀系统的9个核心知识点,一次性打包给你(代码片段)

前言高并发下如何设计秒杀系统?这是一个高频面试题。这个问题看似简单,但是里面的水很深,它考查的是高并发场景下,从前端到后端多方面的知识。秒杀一般出现在商城的促销活动中,指定了一定数量&#... 查看详情

第二十篇商城系统-秒杀功能设计与实现(代码片段)

秒杀服务一、商品上架秒杀活动的结构图通过定时任务触发:/***定时上架秒杀商品信息*/@Slf4j@ComponentpublicclassSeckillSkuSchedule@AutowiredSeckillServiceseckillService;@AutowiredRedissonClientredissonClient;/****/@ 查看详情

第二十篇商城系统-秒杀功能设计与实现(代码片段)

秒杀服务一、商品上架秒杀活动的结构图通过定时任务触发:/***定时上架秒杀商品信息*/@Slf4j@ComponentpublicclassSeckillSkuSchedule@AutowiredSeckillServiceseckillService;@AutowiredRedissonClientredissonClient;/****/@ 查看详情

如何设计一个秒杀系统(代码片段)

...0c;并且会在约定的时间点同时在秒杀页面进行抢购。秒杀系统场景特点秒杀时大量用户会在同一时间同时进行抢购,网站瞬时访问流量激 查看详情

分布式抽奖秒杀系统,ddd架构设计和实现分享(代码片段)

作者:小傅哥博客:https://bugstack.cn沉淀、分享、成长,让自己和他人都能有所收获!😄一、用大项目,贯穿知识体系写CRUD、堆API、改屎山⛰,熬多少个996也只是成为重复的螺丝钉。如果你希望捅破现... 查看详情

十万级低成本超详细的秒杀高并发设计,快收藏起来(代码片段)

秒杀系统相信很多人见过,比如京东或者淘宝的秒杀,小米手机的秒杀,那么秒杀系统的后台是如何实现的呢?我们如何设计一个秒杀系统呢?对于秒杀系统应该考虑哪些问题?如何设计出健壮的秒杀系统... 查看详情

八个维度讲解秒杀系统架构分析与实战(代码片段)

点击上方“朱小厮的博客”,选择“设为星标”后台回复"书",获取后台回复“k8s”,可领取k8s资料1秒杀业务分析2秒杀技术挑战3秒杀架构原则4秒杀架构设计4.1前端层设计4.2站点层设计4.4数据库设计5大并发带来... 查看详情

秒杀系统设计(代码片段)

高并发下如何设计秒杀系统?这是一个高频面试题。这个问题看似简单,但是里面的水很深,它考查的是高并发场景下,从前端到后端多方面的知识。秒杀一般出现在商城的促销活动中,指定了一定数量(... 查看详情

秒杀系统设计的5个要点

...Github地址:​​https://github.com/Tyson0314/Java-learning​​秒杀系统涉及到的知识点高并发,cache,锁机制基于缓存 查看详情

不是吧,阿sir,你竟然三分钟就解释了高性能秒杀系统的设计思考(代码片段)

...购买同一商品并完成交易的过程。从架构视角来看,秒杀系统本质是一个高性能、高一致、高可用的三高系统。而打造并维护一个超大流量的秒杀系统需要进行哪些关注,就是本文讨论的话题。整体思考首先从高维度出发,整体... 查看详情

解密秒杀系统架构,不是所有的系统都能做秒杀!(代码片段)

摘要:教你如何设计一个秒杀系统架构:从电商系统架构到秒杀系统、从高并发“黑科技”与致胜奇招到服务器硬件优化,全方位立体掌握秒杀系统架构!!本文分享自华为云社区《实践出真知:全网最强... 查看详情

秒杀系统设计的5个要点

...要在诸多约束情况下,尽可能高效的解决问题。 秒杀系统涉及到的知识点高并发,cache,锁机制基于缓存架构redis,Memcached的先进先出队列。稍微 查看详情

从全局角度,如何设计一个秒杀系统?

大家好,我是树哥。秒杀系统的设计是高级职位面试中非常高频的一道题目,它可以较好地考察候选人的知识体系情况。对于我们来说,学习秒杀系统的设计,能够让我们学以致用,设计系统的时候考虑得更加全面。今天就让树... 查看详情

秒杀系统的设计与实现(限时抢购抢救接口单用户限制实现)(代码片段)

...器直接搞炸,要开始关心一些细节问题。现在设计的系统还有一些问题:我们应该在一定的时间内执行秒杀处理,不能再任意时间都接受秒杀请求。如何加入时间验证?对于稍微懂点电脑的,又会动歪脑筋的人来说开始通过... 查看详情