关于php:PHPGolang-商品秒杀功能

9次阅读

共计 5070 个字符,预计需要花费 13 分钟才能阅读完成。

框架: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…

具体后果贴图:

正文完
 0