框架:laravel
秒杀组成部分:商品、秒杀场次、Redis、模拟秒杀
秒杀过程:
一、实现商品、秒杀场次、秒杀场次和商品关联的CRUD;
二、定时将秒杀场次、商品、库存等信息提前写入redis;
三、配置Redis持久化;
四、实现秒杀下单逻辑;
五、定时删除秒杀的过期信息并释放库存;
六、使用golang并发编程模拟秒杀。
PS:整个流程中,涉及异步并发的地方:定时存储数据到redis、秒杀生成订单、查询当前秒杀商品
一、各种表的CRUD
主商品表
CREATE TABLE `goods` ( `id` int(12) unsigned NOT NULL AUTO_INCREMENT COMMENT 'pk', `item_no` varchar(64) NOT NULL COMMENT '货号', `name` varchar(255) NOT NULL COMMENT '商品名称', `pic_path` varchar(255) DEFAULT NULL COMMENT '商品首图路径 yzy=>2018-11-19', `shops_id` int(12) unsigned NOT NULL COMMENT '店铺id', `market_price` decimal(11,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '市场价格', `shop_price` decimal(11,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '门店价', `warn_stock` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '预警库存', `goods_stock` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '总库存', `unit` char(10) NOT NULL COMMENT '单位', `tip` text COMMENT '促销信息', `is_sale` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '1=>上架 2=》不上架', `is_best` tinyint(1) unsigned NOT NULL DEFAULT '2' COMMENT '1=>精品 2=>非精品', `is_hot` tinyint(1) unsigned NOT NULL DEFAULT '2' COMMENT '1=>热销2=>非热销', `is_new` tinyint(1) unsigned NOT NULL DEFAULT '2' COMMENT '1=>新品 2=>非新品', `is_recom` tinyint(1) unsigned NOT NULL DEFAULT '2' COMMENT '1=>推荐 2=>不推荐', `is_vip` tinyint(1) NOT NULL COMMENT '是否为vip商品,1=》VIP 2=》普通', `goods_cats_id_one` int(11) unsigned NOT NULL COMMENT '商品分类一级id', `goods_cats_id_two` int(11) unsigned NOT NULL COMMENT '商品分类二级id', `goods_cats_id_three` int(11) unsigned NOT NULL COMMENT '商品分类三级id', `goods_describe` longtext NOT NULL COMMENT '描述内容 注:lxs=>调整字段名,类型为longtext', `brokerage` decimal(8,2) NOT NULL DEFAULT '0.00' COMMENT '推荐积分率(佣金),单位:%', `brokerage_rules` json DEFAULT NULL COMMENT '推荐积分(佣金)分配规则,单位:%,例如:{10,20,30} 第一个代表第一层', `status` char(3) NOT NULL DEFAULT '100' COMMENT '100=>未审核 200=>审核通过 400=>审核未通过', `sale_num` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '总销量', `sale_time` time DEFAULT NULL COMMENT '上架时间', `visit_num` int(11) unsigned DEFAULT '0' COMMENT '访问次数', `appraise_num` int(11) unsigned DEFAULT NULL COMMENT '评价总数', `key_words` varchar(255) DEFAULT NULL COMMENT 'SEO关键词', `remark` varchar(1024) 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=3 DEFAULT CHARSET=utf8;
子商品表
CREATE TABLE goods_items ( id int(12) unsigned NOT NULL AUTO_INCREMENT COMMENT 'pk', shops_id int(12) unsigned NOT NULL COMMENT '商铺id', goods_id int(12) unsigned NOT NULL COMMENT '商品id', item_no varchar(64) NOT NULL COMMENT '货号', market_price decimal(11,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '市场价格', shop_price decimal(11,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '门店价', warn_stock int(11) unsigned NOT NULL DEFAULT '0' COMMENT '预警库存', goods_stock int(11) unsigned NOT NULL DEFAULT '0' COMMENT '库存', status char(3) NOT NULL DEFAULT '1' COMMENT '1=>有效 2=>无效', sale_num int(11) unsigned NOT NULL DEFAULT '0' COMMENT '销量', goods_spec_items_id varchar(255) DEFAULT NULL COMMENT '规格参数值表的id 存储格式例如:''1:2:3'' 注:lxs=>修改为可空', 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=3 DEFAULT CHARSET=utf8;
秒杀场次表
CREATE TABLE `seckill_sessions` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'pk', `name` varchar(100) NOT NULL COMMENT '秒杀场次名称', `start_time` timestamp NOT NULL COMMENT '开始时间', `end_time` timestamp NOT NULL COMMENT '结束时间', `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1=>有效 2=》无效', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NULL DEFAULT NULL, `deleted_at` timestamp NULL DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
秒杀场次与商品关联表
CREATE TABLE `seckill_goods_items` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'pk', `seckill_sessions_id` int(11) unsigned NOT NULL COMMENT '秒杀场次id', `goods_id` int(11) unsigned NOT NULL COMMENT '商品id', `goods_items_id` int(11) unsigned NOT NULL COMMENT '子类商品id', `name` varchar(255) NOT NULL COMMENT '商品名称', `pic_path` varchar(255) NOT NULL COMMENT '商品图片', `shop_price` decimal(10,2) NOT NULL COMMENT '秒杀价格', `goods_stock` int(11) NOT NULL COMMENT '秒杀库存', `seckill_limit` int(11) NOT NULL COMMENT '秒杀数量限制', `sort` int(11) NOT NULL COMMENT '排序', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NULL DEFAULT NULL, `deleted_at` timestamp NULL DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4;
二、定时提前写入redis
1、使用List场次信息:
key:session_prefix + 场次开始时间戳 + 场地结束时间戳
value: 场次id+商品id
2、使用hash存储商品的json数据
key:goods_prefix
field:场地id+商品id
value:json_encode(商品信息+场次信息+随机码)
3、使用string存储库存信息
key:stock_prefix + 随机码
value:秒杀库存数量
4、注意以上的redis数据加上过期时间。
三、配置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中的信息过滤已经过期的信息,释放库存过程同时加锁。
六、使用golang并发编程模拟秒杀
golang并发调度项目码云:
https://gitee.com/jasonlxs/se...
具体结果贴图:
文章来源: segmentfault.com,作者:sengerlion,版权归原作者所有,如需转载,请联系作者。
原文链接:segmentfault.com/a/1190000039349297
(完)