1. 商品列表頁,用戶瀏覽商品
2. 點(diǎn)擊進(jìn)入某個(gè)商品的詳情頁
3. 進(jìn)入商品詳情頁后
• 秒殺未開始顯示秒殺倒計(jì)時(shí)
• 秒殺已開始顯示秒殺按鈕
• 秒殺已結(jié)束顯示秒殺結(jié)束
4. 用戶在商品詳情頁點(diǎn)擊秒殺按鈕后
① 驗(yàn)證商品id和秒殺唯一標(biāo)志是否合法 (秒殺唯一標(biāo)識(shí):暴露秒殺地址)
② 判斷秒殺時(shí)間是否開始
判斷商品的秒殺開始時(shí)間和結(jié)束時(shí)間,用當(dāng)前系統(tǒng)時(shí)間和他們做比較
③ 判斷秒殺是否搶光了
判斷Redis中該商品的庫存>0可以秒殺,<=0秒殺結(jié)束
④ 判斷用戶是否已經(jīng)秒殺過該商品
判斷Redis中的key是否存在,用戶秒殺后會(huì)在Redis中設(shè)置一個(gè)占位的key來標(biāo)識(shí)用戶已經(jīng)秒殺過該商品
5. 判斷當(dāng)前系統(tǒng)流量是否已經(jīng)超過閾值
• 通過Redis的List數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)
• 每有一個(gè)用戶請(qǐng)求,就將用戶的請(qǐng)求放入List
• 當(dāng)List的長(zhǎng)度達(dá)到我們?cè)O(shè)置的最大值后(通常設(shè)置為商品庫存數(shù)的100倍等)
• 拒絕后續(xù)用戶的訪問,減輕系統(tǒng)的壓力
• 用戶秒殺流程執(zhí)行結(jié)束后,不管是秒殺成功還是失敗,都需要將限流的List彈出一個(gè)元素,以便于讓后面的人可以再進(jìn)來一個(gè)
7. 進(jìn)行秒殺
① 減庫存
在redis中減庫存,采用redis減庫存 decrBy 方法(單線程的操作,不會(huì)產(chǎn)生數(shù)據(jù)沖突)
我們數(shù)據(jù)庫中并沒有直接減庫存,因?yàn)閿?shù)據(jù)庫性能瓶頸問題
最終我們采用定時(shí)任務(wù)每隔幾秒同步一次Redis庫存到數(shù)據(jù)庫,讓數(shù)據(jù)庫的庫存和redis的庫存同步
② 下訂單
• 異步下訂單,也是為了避免直接操作數(shù)據(jù)庫
• 采用隊(duì)列ActiveMQ下訂單
• 減庫存成功后,給MQ發(fā)一個(gè)消息
• 消息監(jiān)聽器接收到消息后在數(shù)據(jù)庫創(chuàng)建訂單
• 如果消息消費(fèi)不過來,可以設(shè)置concurrency="8" 8個(gè)消費(fèi)者,那么消費(fèi)消息的速度就會(huì)加快,不會(huì)產(chǎn)生消息的堆積
③ 告知前臺(tái)頁面秒殺結(jié)果
創(chuàng)建訂單成功或者失敗后,都把秒殺結(jié)果放入到redis中;
前臺(tái)頁面采用ajax輪詢方式查詢r(jià)edis獲取最終秒殺結(jié)果,給用戶提示。