当前位置: 首页 > 后端技术 > PHP

拍卖系统设计(秒杀系统知识传授)

时间:2023-03-30 00:39:14 PHP

自从上篇文章秒杀系统(php+golang产品秒杀),知识传授的新项目,商品拍卖。技术:php、mysql、redis、laravel业务对象:商品、session、订单拍卖流程:1.实现商品、拍卖session、订单的增删改查;2、定时将闪购时段、商品、库存等信息提前写入redis;3.1.配置Redis持久化;4.实现秒杀下单逻辑;5、redis秒杀进程优化;6、使用golang并发编程模拟秒杀。1、实现商品、拍卖、订单的CRUD;商品表:CREATETABLE`goods`(`id`int(12)unsignedNOTNULLAUTO_INCREMENTCOMMENT'pk',`num`varchar(64)NOTNULLCOMMENT'goodsnumber',`users_id`int(12)unsignedNOTNULLCOMMENT'owner',`create_users_id`int(12)unsignedNOTNULLCOMMENT'productcreator',`name`varchar(255)NOTNULLCOMMENT'productname',`img`int(11)NOTNULLCOMMENT'coverimage',`price`decimal(10,2)unsignedNOTNULLCOMMENT'currentprice',`area_id`int(11)NOTNULLCOMMENT'areaid',`user_name`varchar(100)DEFAULTNULLCOMMENT'收货人姓名',`user_phone`varchar(11)DEFAULTNULLCOMMENT'收货人联系电话',`user_address`varchar(255)DEFAULTNULLCOMMENT'收货人地址',`express_id`int(11)DEFAULTNULLCOMMENT'物流编号',`express_no`varchar(255)DEFAULTNULLCOMMENT'物流单号',`is_auction`tinyint(1)NOTNULLDEFAULT'1'COMMENT'是否可以竞拍,1=》可用2=》不可用',`status`tinyint(1)unsignedNOTNULLDEFAULT'1'COMMENT'状态1=>可交易2=>待付款3=>交易完成4=>待发货5=》发货6=>已完成7=>待付款',`next_time`timestampNULLDEFAULTNULLCOMMENT'下次最早显示时间',`trade_time`timestampNULLDEFAULTNULLCOMMENT'下次可交易时间',`created_at`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',`updated_at`timestampNULLDEFAULTNULLCOMMENT'Updatedtime',`deleted_at`timestampNULLDEFAULTNULLCOMMENT'Deletedtime',PRIMARYKEY(`id`)USINGBTREE)ENGINE=InnoDBAUTO_INCREMENT=111DEFAULTCHARSET=utf8ROW_FORMAT=DYNAMIC;拍卖表:CREATETABLE`auctions`(`id`int(11)NOTNULLAUTO_INCREMENTCOMMENT'ID',`area`tinyint(4)NOTNULL,`name`varchar(64)DEFAULTNULLCOMMENT'sessionname',`start`timeNOTNULLCOMMENT'开始时间',`end`timeNOTNULLCOMMENT'结束时间',`created_at`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',`updated_at`timestampNULLDEFAULTNULLCOMMENT'更新时间',`deleted_at`timestampNULLDEFAULTNULLCOMMENT'删除时间',PRIMARYKEY(`id`)USINGBTREE)ENGINE=InnoDBAUTO_INCREMENT=10DEFAULTCHARSET=utf8ROW_FORMAT=DYNAMICCOMMENT='拍卖会话表';订单表:创建TABLE`orders`(`id`int(12)unsignedNOTNULLAUTO_INCREMENTCOMMENT'pk',`serial_num`varchar(32)DEFAULTNULLCOMMENT'序列号,交易前为空',`goods_id`int(12)unsignedNOTNULLCOMMENT'productid',`sell_users_id`int(12)unsignedNOTNULL,`buy_users_id`int(12)unsignedDEFAULTNULL,`buy_price`decimal(10,2)NOTNULLCOMMENT'buyprice',`pay_time`datetimeDEFAULTNULLCOMMENT'付款时间',`status`char(5)NOTNULLCOMMENT'状态10000=>待付款20000=>付款超时30000=>付款完成30001=>发货50000=>完成',`remark`varchar(255)DEFAULTNULLCOMMENT'remark',`created_at`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',`updated_at`timestampNULLDEFAULTNULLCOMMENT'更新时间',`deleted_at`timestampNULLDEFAULTNULLCOMMENT'删除时间',PRIMARYKEY(`id`)USINGBTREE)ENGINE=InnoDBAUTO_INCREMENT=23DEFAULTCHARSET=utf8ROW_FORMAT=DYNAMIC;二、定时提前写入redis1、拍卖会话定时提前写入并设置过期时间2、缓存数据结构设计有两个版本:a.第一版的数据结构设计在查询商品列表时不能排除自身商品信息和分页。不同区域可秒杀用户集合(判断用户所属拍卖区域)key:prefix+area_id+start+end+auctions_id,value:不同区域uid商品信息zset(支持分页)key:prefix+area_id+start+end+auctions_id,score:goods_id,member:goods_detailInventoryliteralkey:randomvalue:1是否购买placeholderkey:prefix+area_id+start+endvalue:1为了满足排除其功能自己的产品和分页,已经考虑了一些实现方案:(1)完全放弃从缓存中获取拍卖产品信息,这会增加数据库的压力,同时不能使用拍卖随机码。(2)对每个用户,存储一个不包含自己产品信息的集合,会存储重复数据,增加内容空间。(3)发现redis有SCAN命令迭代获取数据,可以使用glob模式匹配,但是无法确定获取次数,无法进行分页。以上(1)、(3)点均被排除。我们从第(2)点开始,重新设计第二版数据结构,将商品数据和用户查询的商品id集合分开存放,减少重复,但是key会太多,这种情况下需要优化。b.第二版数据结构设计是用户可以查询的商品id的zset(判断用户是否有可以拍卖的商品)key:prefix+area_id+users_id+auction_id+start+end,score:goods_id,member:goods_id商品信息字符串(可支持分页)key:prefix+area_id+auction_id+goods_id+start+end,value:goodsinventoryliteralkey:randomvalue:1是否购买placeholderkey:prefix+area_id+start+endvalue:13.配置Redis持久化和持久化两种模式都开启:RDB(快照模式)+AOF(日志模式)配置文件:save/append_only区别:两种数据存储间隔不同,RDB存储间隔更大比AOF存储间隔4.实现秒杀单逻辑1.查询事件数和当前秒杀产品查询redis中的缓存数据。当并发量大时,可能会出现:缓存穿透:key值不存在,重复请求压垮数据库=>Bloomfilterorsetcachetoempty。缓存崩溃:key值存在但失效,需要重新请求数据库导致并发问题=>SETNX锁缓存雪崩:缓存重启或集中失效,所有请求都到DB=>过期时间设置分散2,官方拍卖是单独的秒杀单功能。3、具体订单逻辑:登录验证=>秒杀流程验证=>通过队列异步下单,秒杀过程中返回订单号orderSN。验证点如下:秒杀时间:是否在秒杀时间内;用户是否在该区域有可拍卖物品的随机码:物品是否可以秒卖;是否已购买:通过redisSETNX设置Key=sessionid_productid_userid来判断是否已购买。秒杀库存数量:在获取对应库存信息前,以随机码为key设置SETNX实现并发锁,设置超时时间,秒杀成功或失败时释放锁。5.redis在秒杀过程中的优化由于缓存数据结构的设计,redis中可能会存储大量的key。如果通过keys命令查询,复杂度为O(n),查询会卡顿变慢。Redis提供了扫描迭代而不是键,但是根据这个项目没有必要使用它。优化大致有两方面:1.拍卖信息提前写入redis时,由于key较多,可以利用redis的pipeline来提高写入效率。查询或竞价时传给后端,后端拼接键值获取数据的时间复杂度为O(1)。6.使用golang并发编程模拟秒杀图片请参考另一篇文章:PHP+Golang产品秒杀函数========================================================================Golang并发调度项目码云:https://gitee.com/jasonlxs/se...