框架: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...
具體結果貼圖: