設(shè)計(jì)一個(gè)電商秒殺系統(tǒng),至少包含導(dǎo)購、交易和庫存系統(tǒng)的全鏈路簡易的整體方案,特別對(duì)于庫存處理細(xì)節(jié)上,希望給出比較完整的關(guān)鍵細(xì)節(jié)處理,需要有代碼配合的可以用偽代碼示例。方案上可以講大的設(shè)計(jì),也可以有小的解決方案,例如導(dǎo)購頁面如何為下游交易和庫存系統(tǒng)減壓,交易和庫存系統(tǒng)如何處理高并發(fā)問題,也可以有部分細(xì)節(jié)處理,如減庫存如何保證正確等等。
方案一
針對(duì)并發(fā)量比較大的情況,比如100萬用戶搶一個(gè)iphone,要扛 100 萬的 TPS,需要非常多的機(jī)器,不太現(xiàn)實(shí)。必須采用前端限流的辦法。
1. 靜態(tài)資源存放于CDN緩存
2.ngnix+lua限流,可根據(jù)在線人數(shù)計(jì)算概率,比如100萬請(qǐng)求只放過1萬人進(jìn)入搶購系統(tǒng),其他請(qǐng)求返回?fù)屬徥 ?/p>
3.利用CDN邊緣計(jì)算能力(此方法相當(dāng)于要跟運(yùn)營商定制服務(wù))
方案二
1.把秒殺系統(tǒng)獨(dú)立出來,部署單獨(dú)的秒殺服務(wù)器,以避免影響正常的交易系統(tǒng)。
2.秒殺活動(dòng)持續(xù)時(shí)間短,瞬時(shí)數(shù)據(jù)量大。為了不影響現(xiàn)有數(shù)據(jù)庫的正常業(yè)務(wù),可以建立新的庫或者表來處理
3.這種方式比較麻煩,秒殺活動(dòng)結(jié)束后,需要把數(shù)據(jù)同步回主業(yè)務(wù)庫
方案三
采用異步處理的方式,總體流程分為三步:接收請(qǐng)求、異步篩選、前端展示
1.因?yàn)槭钱惒胶Y選的方式,可以采用隊(duì)列對(duì)洪峰請(qǐng)求進(jìn)行過濾、排隊(duì)、篩選,避免后端系統(tǒng)瞬時(shí)并發(fā)壓力
2.缺點(diǎn)是用戶體驗(yàn)不好,搶購后需等待一段時(shí)間才能查詢到搶購結(jié)果
并發(fā)扣減庫存方案
一、采用數(shù)據(jù)庫行鎖
1.采用數(shù)據(jù)庫的行鎖機(jī)制,庫存扣到?jīng)]有為至,應(yīng)用根據(jù)更新行數(shù)判斷是否扣庫存成功
UPDATE inventory SET qty= qty- xxx where id=? and qty-xxx>0;
這種方式不能先把庫存查出來,再去計(jì)算,否則會(huì)有并發(fā)問題;
2.另一種辦法是直接設(shè)置數(shù)據(jù)庫的字段數(shù)據(jù)為無符號(hào)整數(shù),當(dāng)庫存數(shù)小于零時(shí)會(huì)執(zhí)行 SQL 語句失敗,通過攔截異常判斷
UPDATE inventory SET qty= qty- xxx where id=??
二、采用數(shù)據(jù)庫悲觀鎖
1.使用select .. for update語句查詢最新庫存
2.檢查庫存是否足夠
3.更新庫存提交事務(wù)
三、庫存放入redis緩存
1.庫存放到redis緩存中,在redis中進(jìn)行庫存的查詢、扣減
2.扣減時(shí)需要加并發(fā)鎖,獲取鎖成功后才能扣減庫存
3.缺點(diǎn)是如果有比較復(fù)雜的減庫存邏輯,或者需要使用事務(wù),就需要數(shù)據(jù)庫中完成減庫存。
加鎖方式:使用set nx命令 key為要扣減的商品編號(hào),value為當(dāng)前時(shí)間+鎖超時(shí)時(shí)間(比如3秒)執(zhí)行業(yè)務(wù)扣減庫存后,需要釋放鎖。
釋放鎖邏輯(delete key): 判斷一下value - 當(dāng)前時(shí)間是否已超過配置的鎖超時(shí)時(shí)間(比如3秒),如果超過則不刪除。
為什么要執(zhí)行以上判斷? ?由于key是有超時(shí)時(shí)間的,當(dāng)delete還沒有到達(dá)redis的時(shí)候(已經(jīng)發(fā)出了),key已經(jīng)由于超時(shí)delete掉。如果
這個(gè)時(shí)候有其他線程來獲取鎖,就會(huì)導(dǎo)致這個(gè)鎖會(huì)被delete掉