PHP+Golang 商品秒殺功能

框架:laravel
秒殺組成部分:商品、秒殺場次、Redis、模擬秒殺
秒殺過程:

1、實現商品、秒殺場次、秒殺場次和商品關聯的CRUD;
2、定時將秒殺場次、商品、庫存等信息提早寫入redis;
3、配置Redis持久化;
4、實現秒殺下單邏輯;
5、定時刪除秒殺的過時信息並釋放庫存;
6、使用golang併發編程模擬秒殺。laravel

PS:整個流程中,涉及異步併發的地方:定時存儲數據到redis、秒殺生成訂單、查詢當前秒殺商品git

1、各類表的CRUDgolang

主商品表redis

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;

秒殺場次與商品關聯表json

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;

2、定時提早寫入redis緩存

一、使用List場次信息:
key:session_prefix + 場次開始時間戳 + 場地結束時間戳
value: 場次id+商品idsession

二、使用hash存儲商品的json數據
key:goods_prefix
field:場地id+商品id
value:json_encode(商品信息+場次信息+隨機碼)併發

三、使用string存儲庫存信息
key:stock_prefix + 隨機碼
value:秒殺庫存數量

四、注意以上的redis數據加上過時時間。

3、配置Redis持久化

持久化兩種模式都開啓:RDB(快照模式)+ AOF(日誌模式)
配置文件:save/append_only
區別:二者數據保存間隔週期不一樣,RDB存儲間隔大於AOF存儲間隔

4、實現秒殺下單邏輯

一、查詢場次和當前秒殺商品
查詢redis中的緩存數據,當併發量大時可能出現:
緩存穿透:key值不存在,重複請求壓垮數據庫 => 布隆過濾器或設置緩存爲空。
緩存擊穿:key值存在可是失效,需從新請求數據庫形成併發問題 => SETNX鎖
緩存雪崩:緩存重啓或集中失效,則都請求往DB => 過時時間設置分散

二、正式秒殺有兩種方式:正常的購物下單流程和單獨的秒殺下單功能,這裏選擇後者,這種方式可提升併發量和響應速度。
三、具體的下單邏輯:
登陸校驗 => 秒殺過程校驗 => 經過隊列進行異步下單同時返回訂單號orderSN
秒殺過程當中校驗點以下:

秒殺時間:是否在秒殺時間內;
隨機碼:商品是否可秒殺;
購買數量限制:商品每次可購買數量;
是否已購買過:經過redis的SETNX設置Key=場次id_商品id_用戶id來判斷是否購買過。
秒殺庫存數量:在獲取對應庫存信息前,將隨機碼做爲key設置SETNX來實現併發鎖,設置超時時間,秒殺成功或失敗都釋放該鎖。

5、定時刪除秒殺的過時信息並釋放庫存

讀取redis中的信息過濾已通過期的信息,釋放庫存過程同時加鎖。

6、使用golang併發編程模擬秒殺

golang併發調度項目碼雲:

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

具體結果貼圖:

redis中的秒殺數據

1000併發搶100單

redis庫存結果

相關文章
相關標籤/搜索