詳解秒殺系統(tǒng)設(shè)計(jì)的5個(gè)要點(diǎn)
秒殺系統(tǒng)涉及到的知識(shí)點(diǎn)
- 高并發(fā),cache,鎖機(jī)制
- 基于緩存架構(gòu)redis,Memcached的先進(jìn)先出隊(duì)列。
- 稍微大一點(diǎn)的秒殺,肯定是分布式的集群的,并發(fā)來(lái)自于多個(gè)節(jié)點(diǎn)的JVM,synchronized所有在JVM上加鎖是不行了
- 數(shù)據(jù)庫(kù)壓力
- 秒殺超賣(mài)問(wèn)題
- 如何防止用戶(hù)來(lái)刷, 黑名單?IP限制?
- 利用memcached的帶原子性特性的操作做并發(fā)控制
秒殺簡(jiǎn)單設(shè)計(jì)方案
比如有10件商品要秒殺,可以放到緩存中,讀寫(xiě)時(shí)不要加鎖。 當(dāng)并發(fā)量大的時(shí)候,可能有25個(gè)人秒殺成功,這樣后面的就可以直接拋秒殺結(jié)束的靜態(tài)頁(yè)面。進(jìn)去的25個(gè)人中有15個(gè)人是不可能獲得商品的。所以可以根據(jù)進(jìn)入的先后順序只能前10個(gè)人購(gòu)買(mǎi)成功。后面15個(gè)人就拋商品已秒殺完。
比如某商品10件物品待秒。假設(shè)有100臺(tái)web服務(wù)器(假設(shè)web服務(wù)器是Nginx + Tomcat),n臺(tái)app服務(wù)器,n個(gè)數(shù)據(jù)庫(kù)
第一步 如果Java層做過(guò)濾,可以在每臺(tái)web服務(wù)器的業(yè)務(wù)處理模塊里做個(gè)計(jì)數(shù)器AtomicInteger(10)=待秒商品總數(shù),decreaseAndGet()>=0的繼續(xù)做后續(xù)處理,<0的直接返回秒殺結(jié)束頁(yè)面,這樣經(jīng)過(guò)第一步的處理只剩下100臺(tái)*10個(gè)=1000個(gè)請(qǐng)求。
第二步,memcached 里以商品id作為key的value放個(gè)10,每個(gè)web服務(wù)器在接到每個(gè)請(qǐng)求的同時(shí),向memcached服務(wù)器發(fā)起請(qǐng)求,利用memcached的decr(key,1)操作返回值>=0的繼續(xù)處理,其余的返回秒殺失敗頁(yè)面,這樣經(jīng)過(guò)第二步的處理只剩下100臺(tái)中最快速到達(dá)的10個(gè)請(qǐng)求。
第三步,向App服務(wù)器發(fā)起下單操作事務(wù)。
第四步,App服務(wù)器向商品所在的數(shù)據(jù)庫(kù)請(qǐng)求減庫(kù)存操作(操作數(shù)據(jù)庫(kù)時(shí)可以 "update table set count=count-1 where id=商品id and count>0;" update 成功記錄數(shù)為1,再向訂單數(shù)據(jù)庫(kù)添加訂單記錄,都成功后提交整個(gè)事務(wù),否則的話(huà)提示秒殺失敗,用戶(hù)進(jìn)入支付流程。
看看淘寶的秒殺
一、前端
面對(duì)高并發(fā)的搶購(gòu)活動(dòng),前端常用的三板斧是【擴(kuò)容】【靜態(tài)化】【限流】
擴(kuò)容:加機(jī)器,這是最簡(jiǎn)單的方法,通過(guò)增加前端池的整體承載量來(lái)抗峰值。
靜態(tài)化:將活動(dòng)頁(yè)面上的所有可以靜態(tài)的元素全部靜態(tài)化,并盡量減少動(dòng)態(tài)元素。通過(guò)CDN來(lái)抗峰值。
限流:一般都會(huì)采用IP級(jí)別的限流,即針對(duì)某一個(gè)IP,限制單位時(shí)間內(nèi)發(fā)起請(qǐng)求數(shù)量。或者活動(dòng)入口的時(shí)候增加游戲或者問(wèn)題環(huán)節(jié)進(jìn)行消峰操作。
有損服務(wù):最后一招,在接近前端池承載能力的水位上限的時(shí)候,隨機(jī)拒絕部分請(qǐng)求來(lái)保護(hù)活動(dòng)整體的可用性。
二、那么后端的數(shù)據(jù)庫(kù)在高并發(fā)和超賣(mài)下會(huì)遇到什么問(wèn)題呢
- 首先MySQL自身對(duì)于高并發(fā)的處理性能就會(huì)出現(xiàn)問(wèn)題,一般來(lái)說(shuō),MySQL的處理性能會(huì)隨著并發(fā)thread上升而上升,但是到了一定的并發(fā)度之后會(huì)出現(xiàn)明顯的拐點(diǎn),之后一路下降,最終甚至?xí)葐蝨hread的性能還要差。
- 其次,超賣(mài)的根結(jié)在于減庫(kù)存操作是一個(gè)事務(wù)操作,需要先select,然后insert,最后update -1。最后這個(gè)-1操作是不能出現(xiàn)負(fù)數(shù)的,但是當(dāng)多用戶(hù)在有庫(kù)存的情況下并發(fā)操作,出現(xiàn)負(fù)數(shù)這是無(wú)法避免的。
- 最后,當(dāng)減庫(kù)存和高并發(fā)碰到一起的時(shí)候,由于操作的庫(kù)存數(shù)目在同一行,就會(huì)出現(xiàn)爭(zhēng)搶InnoDB行鎖的問(wèn)題,導(dǎo)致出現(xiàn)互相等待甚至死鎖,從而大大降低MySQL的處理性能,最終導(dǎo)致前端頁(yè)面出現(xiàn)超時(shí)異常。
針對(duì)上述問(wèn)題,如何解決呢? 淘寶的高大上解決方案:
I:關(guān)閉死鎖檢測(cè),提高并發(fā)處理性能。
II:修改源代碼,將排隊(duì)提到進(jìn)入引擎層前,降低引擎層面的并發(fā)度。
III:組提交,降低server和引擎的交互次數(shù),降低IO消耗。
解決方案1: 將存庫(kù)從MySQL前移到Redis中,所有的寫(xiě)操作放到內(nèi)存中,由于Redis中不存在鎖故不會(huì)出現(xiàn)互相等待,并且由于Redis的寫(xiě)性能和讀性能都遠(yuǎn)高于MySQL,這就解決了高并發(fā)下的性能問(wèn)題。然后通過(guò)隊(duì)列等異步手段,將變化的數(shù)據(jù)異步寫(xiě)入到DB中。
優(yōu)點(diǎn):解決性能問(wèn)題
缺點(diǎn):沒(méi)有解決超賣(mài)問(wèn)題,同時(shí)由于異步寫(xiě)入DB,存在某一時(shí)刻DB和Redis中數(shù)據(jù)不一致的風(fēng)險(xiǎn)。
解決方案2: 引入隊(duì)列,然后將所有寫(xiě)DB操作在單隊(duì)列中排隊(duì),完全串行處理。當(dāng)達(dá)到庫(kù)存閥值的時(shí)候就不在消費(fèi)隊(duì)列,并關(guān)閉購(gòu)買(mǎi)功能。這就解決了超賣(mài)問(wèn)題。
優(yōu)點(diǎn):解決超賣(mài)問(wèn)題,略微提升性能。
缺點(diǎn):性能受限于隊(duì)列處理機(jī)處理性能和DB的寫(xiě)入性能中最短的那個(gè),另外多商品同時(shí)搶購(gòu)的時(shí)候需要準(zhǔn)備多條隊(duì)列。
解決方案3: 將寫(xiě)操作前移到MC中,同時(shí)利用MC的輕量級(jí)的鎖機(jī)制CAS來(lái)實(shí)現(xiàn)減庫(kù)存操作。
優(yōu)點(diǎn):讀寫(xiě)在內(nèi)存中,操作性能快,引入輕量級(jí)鎖之后可以保證同一時(shí)刻只有一個(gè)寫(xiě)入成功,解決減庫(kù)存問(wèn)題。
缺點(diǎn):沒(méi)有實(shí)測(cè),基于CAS的特性不知道高并發(fā)下是否會(huì)出現(xiàn)大量更新失???不過(guò)加鎖之后肯定對(duì)并發(fā)性能會(huì)有影響。
解決方案4: 將提交操作變成兩段式,先申請(qǐng)后確認(rèn)。然后利用Redis的原子自增操作,同時(shí)利用Redis的事務(wù)特性來(lái)發(fā)號(hào),保證拿到小于等于庫(kù)存閥值的號(hào)的人都可以成功提交訂單。然后數(shù)據(jù)異步更新到DB中。
優(yōu)點(diǎn):解決超賣(mài)問(wèn)題,庫(kù)存讀寫(xiě)都在內(nèi)存中,故同時(shí)解決性能問(wèn)題。
缺點(diǎn):由于異步寫(xiě)入DB,可能存在數(shù)據(jù)不一致。另可能存在少買(mǎi),也就是如果拿到號(hào)的人不真正下訂單,可能庫(kù)存減為0,但是訂單數(shù)并沒(méi)有達(dá)到庫(kù)存閥值。
總結(jié)
1、前端三板斧【擴(kuò)容】【限流】【靜態(tài)化】
2、后端兩條路【內(nèi)存】+【排隊(duì)】
Github地址:github.com/Tyson0314/j…
以上就是詳解秒殺系統(tǒng)設(shè)計(jì)的5個(gè)要點(diǎn)的詳細(xì)內(nèi)容,更多關(guān)于秒殺系統(tǒng)設(shè)計(jì)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
PostMan接口測(cè)試用例自動(dòng)轉(zhuǎn)成Python的測(cè)試腳本
PosMan做服務(wù)端的自動(dòng)化測(cè)試中,我們可以把Collection里面的測(cè)試用例導(dǎo)入出來(lái),它是JSON的文件,然后我們解析這些JSON文件,讓它自動(dòng)的轉(zhuǎn)成Python測(cè)試代碼,實(shí)現(xiàn)了PostMan里面的接口測(cè)試用例自動(dòng)的轉(zhuǎn)成了Python的測(cè)試腳本,而且?guī)Я藬嘌?/div> 2024-06-06
分享VSCOCE遠(yuǎn)程連接服務(wù)器的一次錯(cuò)誤記錄(推薦)
這篇文章主要介紹了VSCOCE遠(yuǎn)程連接服務(wù)器的一次錯(cuò)誤記錄,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04最新評(píng)論

