<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          競拍系統(tǒng)設(shè)計(jì)(秒殺系統(tǒng)知識遷移)

          共 6104字,需瀏覽 13分鐘

           ·

          2021-04-25 14:04

          作者:sengerlion

          來源:SegmentFault 思否社區(qū)




          自從上次整理了秒殺系統(tǒng)的文章(php+golang商品秒殺)后,知識遷移一新項(xiàng)目,商品競拍。

          技術(shù):php、mysql、redis、laravel
          業(yè)務(wù)對象:商品、場次、訂單
          競拍過程:

          一、實(shí)現(xiàn)商品、競拍場次和訂單的CRUD;
          二、定時(shí)將秒殺場次、商品、庫存等信息提前寫入redis;
          三、配置Redis持久化;
          四、實(shí)現(xiàn)秒殺下單邏輯;
          五、秒殺過程redis優(yōu)化;
          六、使用golang并發(fā)編程模擬秒殺。


          一、實(shí)現(xiàn)商品、競拍場次和訂單的CRUD;



          商品表:

          CREATE TABLE `goods` (
          `id` int(12) unsigned NOT NULL AUTO_INCREMENT COMMENT 'pk',
          `num` varchar(64) NOT NULL COMMENT '商品編號',
          `users_id` int(12) unsigned NOT NULL COMMENT '擁有者',
          `create_users_id` int(12) unsigned NOT NULL COMMENT '商品創(chuàng)建人',
          `contract_roles_id` int(10) unsigned NOT NULL COMMENT '商品合約級別外鍵',
          `name` varchar(255) NOT NULL COMMENT '商品名稱',
          `img` int(11) NOT NULL COMMENT '封面圖',
          `price` decimal(10,2) unsigned NOT NULL COMMENT '當(dāng)前價(jià)格',
          `area_id` int(11) NOT NULL COMMENT '區(qū)域id',
          `trade_num` int(11) unsigned NOT NULL COMMENT '交易次數(shù)',
          `user_name` varchar(100) DEFAULT NULL COMMENT '收貨人名稱',
          `user_phone` varchar(11) DEFAULT NULL COMMENT '收貨人聯(lián)系電話',
          `user_address` varchar(255) DEFAULT NULL COMMENT '收貨人地址',
          `express_id` int(11) DEFAULT NULL COMMENT '物流ID',
          `express_no` varchar(255) DEFAULT NULL COMMENT '物流單號',
          `is_auction` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否可競拍,1=》可 2=》不可',
          `status` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '狀態(tài)1=>可交易 2=>待支付 3=>交易完成 4=>待發(fā)貨 5=》配送中 6=>完成 7 =>待收款',
          `next_time` timestamp NULL DEFAULT NULL COMMENT '下次最早顯示時(shí)間',
          `trade_time` timestamp NULL DEFAULT NULL COMMENT '下次可交易時(shí)間',
          `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
          `updated_at` timestamp NULL DEFAULT NULL COMMENT '更新時(shí)間',
          `deleted_at` timestamp NULL DEFAULT NULL COMMENT '刪除時(shí)間',
          PRIMARY KEY (`id`) USING BTREE
          ) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

          競拍場次表:

          CREATE TABLE `auctions` (
          `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
          `area` tinyint(4) NOT NULL COMMENT '拍賣區(qū)域,1=>新手區(qū),2=>競拍區(qū),3=>星級區(qū)',
          `name` varchar(64) DEFAULT NULL COMMENT '場次名稱',
          `start` time NOT NULL COMMENT '開始時(shí)間',
          `end` time NOT NULL COMMENT '結(jié)束時(shí)間',
          `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
          `updated_at` timestamp NULL DEFAULT NULL COMMENT '更新時(shí)間',
          `deleted_at` timestamp NULL DEFAULT NULL COMMENT '刪除時(shí)間',
          PRIMARY KEY (`id`) USING BTREE
          ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='拍賣場次表';

          訂單表:

          CREATE TABLE `orders` (
          `id` int(12) unsigned NOT NULL AUTO_INCREMENT COMMENT 'pk',
          `serial_num` varchar(32) DEFAULT NULL COMMENT '流水號,沒交易前為空',
          `goods_id` int(12) unsigned NOT NULL COMMENT '商品id',
          `sell_users_id` int(12) unsigned NOT NULL COMMENT '競拍商品擁有者id',
          `buy_users_id` int(12) unsigned DEFAULT NULL COMMENT '購買商品用戶id',
          `buy_price` decimal(10,2) NOT NULL COMMENT '購買價(jià)格-成本價(jià)格',
          `pay_time` datetime DEFAULT NULL COMMENT '支付時(shí)間',
          `status` char(5) NOT NULL COMMENT '狀態(tài)10000=>待支付 20000=>支付超時(shí) 30000=>確認(rèn)支付 30001=>確認(rèn)收款 40000=>賣家申訴中 40001=>買家申訴中 45000=>申訴完成 50000=>完成',
          `contract_roles_id` int(10) NOT NULL COMMENT '購買時(shí)商品合約外鍵',
          `charge_rate` decimal(10,4) unsigned DEFAULT NULL COMMENT '手續(xù)費(fèi)',
          `remark` varchar(255) DEFAULT NULL COMMENT '備注-可以填寫申訴結(jié)果',
          `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
          `updated_at` timestamp NULL DEFAULT NULL COMMENT '更新時(shí)間',
          `deleted_at` timestamp NULL DEFAULT NULL COMMENT '刪除時(shí)間',
          PRIMARY KEY (`id`) USING BTREE
          ) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;


          二、定時(shí)提前寫入redis



          1、競拍場次時(shí)間是為每天固定的三個(gè)時(shí)間,定時(shí)提前寫入并設(shè)置過期時(shí)間。

          2、緩存數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)有兩個(gè)版本:

          a、第一個(gè)版本的數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)在商品列表查詢時(shí),無法排除自身商品信息并且分頁。

          • 不同區(qū)域可秒殺的用戶set (判斷用戶所屬競拍區(qū))
                 
            key: prefix + area_id + start + end + auctions_id,
            value:uid
          • 不同區(qū)域下的商品信息zset (可支持分頁)
                 
            key: prefix + area_id + start + end + auctions_id,
            score:goods_id,
            member:goods_detail
          • 庫存字面量
                 
            key: random
            value:1
          • 是否購買占位
                 
            key: prefix + area_id + start + end
            value:1

          為了滿足排除自身的商品功能和分頁,思考了一些實(shí)現(xiàn)方案:

          (1) 完全放棄從緩存中獲取競拍商品信息,這樣增加數(shù)據(jù)庫壓力,同時(shí)無法使用競拍隨機(jī)碼。
          (2)為每個(gè)用戶單獨(dú)存放一個(gè)排除自身商品信息的集合,這樣會存放重復(fù)數(shù)據(jù)造成增加內(nèi)容空間。
          (3)查詢到redis有一個(gè)SCAN命令來迭代獲取數(shù)據(jù),并可利用glob模式匹配,但是獲取數(shù)量無法確定而無法分頁。

          以上(1)(3)點(diǎn)都被排除,我們從第(2)出發(fā)重新設(shè)計(jì)第二版數(shù)據(jù)結(jié)構(gòu),單獨(dú)存放商品數(shù)據(jù)和用戶可查詢的商品id集合來減少重復(fù),但又會出現(xiàn)keys過多的情況,需要進(jìn)行優(yōu)化。

          b.第二個(gè)版本的數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)

          • 用戶可查詢的商品id的zset (判斷用戶是否有可競拍商品)

          key: prefix + area_id +users_id + auction_id+ start + end,
          score:goods_id,
          member:goods_id

          • 商品信息string (可支持分頁)

          key: prefix + area_id + auction_id + goods_id + start + end,
          value:goods

          • 庫存字面量

          key: random
          value:1

          • 是否購買占位

          key: prefix + area_id + start + end
          value:1




          三、配置Redis持久化


          持久化兩種模式都開啟:RDB(快照模式)+ AOF(日志模式)
          配置文件:save/append_only
          區(qū)別:兩者數(shù)據(jù)保存間隔周期不同,RDB存儲間隔大于AOF存儲間隔

          四、實(shí)現(xiàn)秒殺下單邏輯


          1、查詢場次和當(dāng)前秒殺商品:
          查詢r(jià)edis中的緩存數(shù)據(jù),當(dāng)并發(fā)量大時(shí)可能出現(xiàn):
          緩存穿透:key值不存在,重復(fù)請求壓垮數(shù)據(jù)庫 => 布隆過濾器或設(shè)置緩存為空。
          緩存擊穿:key值存在但是失效,需重新請求數(shù)據(jù)庫造成并發(fā)問題 => SETNX鎖
          緩存雪崩:緩存重啟或集中失效,則都請求往DB => 過期時(shí)間設(shè)置分散

          2、正式競拍是單獨(dú)的秒殺下單功能。

          3、具體的下單邏輯:
          登錄校驗(yàn) => 秒殺過程校驗(yàn) => 通過隊(duì)列進(jìn)行異步下單同時(shí)返回訂單號orderSN
          秒殺過程中校驗(yàn)點(diǎn)如下:
          秒殺時(shí)間:是否在秒殺時(shí)間內(nèi);
          用戶是否在該區(qū)有可競拍商品
          隨機(jī)碼:商品是否可秒殺;
          是否已購買過:通過redis的SETNX設(shè)置Key=場次id_商品id_用戶id來判斷是否購買過。
          秒殺庫存數(shù)量:在獲取對應(yīng)庫存信息前,將隨機(jī)碼作為key設(shè)置SETNX來實(shí)現(xiàn)并發(fā)鎖,設(shè)置超時(shí)時(shí)間,秒殺成功或失敗都釋放該鎖。

          五、秒殺過程redis優(yōu)化


          因緩存數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì),可能會在redis存儲大量的key,若通過keys命令查詢會是O(n)復(fù)雜度,查詢會卡頓而緩慢,redis有提供scan迭代來代替keys,但是根據(jù)本項(xiàng)目無需使用它。

          優(yōu)化大致有兩個(gè)方面:

          1、在提前將競拍信息寫入redis時(shí),因key數(shù)量大,可采用redis的pipeline管道來提高寫入效率
          2、盡可能將場次和開始結(jié)束時(shí)間返回前端讓其在查詢或競拍時(shí)傳給后端,后端拼接key值獲取數(shù)據(jù)的時(shí)間復(fù)雜度是O(1)。


          六、使用golang并發(fā)編程模擬秒殺


          圖片請參考另外一篇文章:

          https://segmentfault.com/a/1190000039349297


          golang并發(fā)調(diào)度項(xiàng)目碼云:
          https://gitee.com/jasonlxs/seckill/tree/master




          重磅!交流已成立


          公眾號運(yùn)營至今,離不開小伙伴們的支持。
          為了給小伙伴們提供一個(gè)互相交流的技術(shù)平臺,特地開通了公眾號交流群。
          群里有不少技術(shù)大神,不時(shí)會分享一些技術(shù)要點(diǎn),更有一些資源收藏愛好者不時(shí)分享一些優(yōu)質(zhì)的學(xué)習(xí)資料。(免費(fèi),不賣課?。?/span>
          需要進(jìn)群的朋友,可長按掃描下方二維碼,備注:GitHub科技


          ▲長按掃碼

          瀏覽 43
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人黄色在线看 | 久久久久无码精品亚洲日韩 | 国产免费黄色视频网站 | 午夜福利视频3000 | 黄色大片视频 |