現(xiàn)在生活中葡秒,秒殺已經(jīng)隨處可見炸站,尤其是在電商行業(yè)中腿堤。
這里,我將以自己的實(shí)際生活情況酗洒,學(xué)校圖書館搶購書包柜為例士修,講解一下秒殺系統(tǒng)。
秒殺系統(tǒng)分析
- 秒殺的場景決定了秒殺是一場速度的比拼樱衷,即“手快有棋嘲、手慢無”【毓穑活動(dòng)開始后沸移,大家都瘋狂的點(diǎn)擊鼠標(biāo)。想在第一時(shí)間將書包柜搶到,完成預(yù)訂雹锣。因此秒殺活動(dòng)開始的一瞬間會(huì)有大量的流量涌入网沾,幾倍、甚至于十幾倍的流量對(duì)系統(tǒng)的沖擊不可謂不大蕊爵。如果系統(tǒng)沒有足夠的capacity或應(yīng)對(duì)措施辉哥,很可能就被瞬時(shí)高流量給壓垮了。
- 突如其來的高流量在辆,給系統(tǒng)各個(gè)模塊都來了一連串的壓力证薇,系統(tǒng)可能會(huì)因此變慢,而且可能會(huì)彼此影響匆篓,影響可用性浑度。例如需要多次讀寫數(shù)據(jù)庫,隨著并發(fā)的壓力逐漸增大鸦概,數(shù)據(jù)庫更新的性能是逐漸下降的箩张,進(jìn)而反饋到用戶的可能就是整個(gè)秒殺系統(tǒng)流程性能差、響應(yīng)慢窗市。而面對(duì)響應(yīng)慢的系統(tǒng)先慷,很多用戶可能采取的措施就是反復(fù)刷新,多次嘗試咨察,這無疑又增大了對(duì)系統(tǒng)的壓力论熙。
上述種種給用戶帶來的往往是體驗(yàn)上的痛苦。如:網(wǎng)站響應(yīng)慢摄狱,點(diǎn)擊預(yù)訂按鈕沒反應(yīng)脓诡。好不容易可以操作了,卻發(fā)現(xiàn)秒殺活動(dòng)已經(jīng)結(jié)束媒役。
在這里祝谚,我不得不吐嘈一下學(xué)校的書包柜預(yù)訂系統(tǒng),大學(xué)三年來酣衷,從來就沒有正常運(yùn)行過交惯,一到搶購的那天深夜12點(diǎn),大家做的事就是等待一分鐘內(nèi)就崩潰的系統(tǒng)被修復(fù)穿仪,而且因?yàn)椴恢浪囊幻氡恍迯?fù)好席爽,很多人會(huì)等一夜。
基于以上秒殺場景下的痛點(diǎn)我在設(shè)計(jì)秒殺排隊(duì)系統(tǒng)在設(shè)計(jì)時(shí)主要考慮以下幾點(diǎn):
- 限流:當(dāng)秒殺活動(dòng)開始后啊片,只有少部分消費(fèi)者能搶購到秒殺商品拳昌,意味著其實(shí)大部分用戶的流量傳達(dá)到后臺(tái)服務(wù)后都是無效。如果能引導(dǎo)這大部分的流量钠龙,不讓這大部分的流量傳達(dá)到后臺(tái)服務(wù),其實(shí)對(duì)我們系統(tǒng)的壓力就很小了。因此設(shè)計(jì)思路之一就是碴里,僅讓能成功搶購到商品的流量(可以有一定余量)進(jìn)入我們的系統(tǒng)
- 削峰:進(jìn)入系統(tǒng)的有效流量雖然總量不一定是很大的沈矿,但卻是在很短的時(shí)間內(nèi)涌入的,因此會(huì)存在很高的瞬時(shí)流量峰值咬腋「牛總量相同的流量在1秒鐘進(jìn)入系統(tǒng),和在10分鐘均勻地進(jìn)入系統(tǒng)根竿,對(duì)系統(tǒng)的沖擊是相差很大的陵像。高峰值的流量往往能將系統(tǒng)壓垮。因此另一個(gè)設(shè)計(jì)思路是寇壳,如何將進(jìn)入系統(tǒng)的瞬時(shí)高流量拉平醒颖,使得系統(tǒng)可以在自己處理能力范圍內(nèi),將所有搶購的請(qǐng)求處理完畢壳炎。
- 異步處理:傳統(tǒng)的系統(tǒng)對(duì)于請(qǐng)求是同步處理的泞歉,即收到請(qǐng)求后立即處理并把結(jié)果返回給用戶。我們的系統(tǒng)有了削峰的設(shè)計(jì)后匿辩,請(qǐng)求不是被立刻處理的腰耙,因此就要求我們能將同步的服務(wù)改造成異步的。
- 可用性:我們?cè)O(shè)計(jì)時(shí)始終把系統(tǒng)的可用性放在重要的位置铲球,針對(duì)系統(tǒng)可能出現(xiàn)的各種狀況挺庞,都盡最大程度地保證高可用。
以下是我的設(shè)計(jì)思路:
代碼部分
- 對(duì)于客戶端請(qǐng)求進(jìn)行的初步處理稼病,使用PHP代碼進(jìn)行編寫选侨。
- 對(duì)客戶端請(qǐng)求進(jìn)行真正處理,即給用戶隨機(jī)分配箱子的代碼溯饵,使用JAVA進(jìn)行編寫侵俗。并使用隊(duì)列數(shù)據(jù)結(jié)構(gòu)和多線程進(jìn)行處理。
- 對(duì)于真正進(jìn)入Java進(jìn)行處理的請(qǐng)求丰刊,之前我們需要在PHP部分進(jìn)行兩次控制隘谣。第一次是隨機(jī)引導(dǎo)大部分的流量,不讓其進(jìn)入后臺(tái)服務(wù)啄巧,并對(duì)失效的請(qǐng)求返回提示信息寻歧,提示信息為:請(qǐng)稍后重新刷新。第二次是查看書包柜是否還有剩余秩仆,若沒有剩余码泛,就對(duì)此請(qǐng)求返回提示信息,提示信息為:書包柜已搶購?fù)戤叀?/li>
- 為了提高對(duì)數(shù)據(jù)庫的訪存速度澄耍,借助memcached key-value內(nèi)存存儲(chǔ)系統(tǒng)噪珊。將數(shù)據(jù)庫的存儲(chǔ)信息全部預(yù)存到memcached中晌缘。在memcached中數(shù)據(jù)的讀取與存儲(chǔ)速度遠(yuǎn)遠(yuǎn)高于mysql數(shù)據(jù)庫。
- 數(shù)據(jù)庫表結(jié)構(gòu)痢站,為了簡化只取兩列磷箕,表 箱子:ID和箱子具體信息。在本次討論中阵难,ID取1~10000岳枷,代表有10000個(gè)箱子。預(yù)訂表: ID和用戶信息呜叫。
- 在第二次控制中空繁,如何查看書包柜是否還有剩余,這是一個(gè)問題朱庆。顯然盛泡,如果每次都去讀后臺(tái)數(shù)據(jù)庫,那么我們討論的秒殺就沒有意義了椎工。我們可以在memcached設(shè)置一個(gè)標(biāo)志位饭于,初始值為0,表示箱子還有剩余维蒙,只有當(dāng)書包柜沒有剩余時(shí)掰吕,更新此標(biāo)志位的值為1。在第二次控制的時(shí)候颅痊,查看書包柜是否還有剩余殖熟,我們只需對(duì)memcached中標(biāo)志位進(jìn)行讀取判斷即可。
實(shí)際執(zhí)行過程
- 為了限流斑响,當(dāng)用戶在頁面點(diǎn)擊預(yù)訂按鈕后菱属,請(qǐng)求首先進(jìn)入PHP代碼處理,PHP代碼第一部分用于隨機(jī)控制真正進(jìn)入Java代碼處理的請(qǐng)求舰罚。
對(duì)于不能進(jìn)入Java的請(qǐng)求纽门,在PHP代碼里返回給用戶提示信息,提示其重新發(fā)起請(qǐng)求营罢。 - 隨機(jī)限流之后赏陵,對(duì)memcached中標(biāo)志位進(jìn)行讀取進(jìn)行第二次控制,若為0饲漾,則將此請(qǐng)求放行蝙搔,進(jìn)入Java代碼部分,若為1考传,則代表書包柜已被搶購?fù)戤叧孕停琍HP代碼返回給用戶提示信息,提示信息為:書包柜已搶購?fù)戤叀?/li>
- 經(jīng)過PHP兩次控制之后僚楞,真正能被處理的請(qǐng)求進(jìn)入Java代碼處理部分勤晚。在Java代碼中枉层,使用一個(gè)隊(duì)列來存儲(chǔ)請(qǐng)求。當(dāng)隊(duì)列長度超過一定值后赐写,就會(huì)對(duì)之后進(jìn)來的請(qǐng)求Java代碼進(jìn)行拒絕返干,并返回給PHP 代碼部分,PHP代碼部分再將拒絕結(jié)果返回給客戶端血淌,要求其稍后重試。在JAVA代碼部分财剖,使用多線程對(duì)請(qǐng)求進(jìn)行處理悠夯,以提高速度。
- 為了進(jìn)一步提高處理速度躺坟,可以采用多個(gè)隊(duì)列沦补。每個(gè)隊(duì)列分配一定范圍內(nèi)的ID任務(wù),如第一個(gè)隊(duì)列負(fù)責(zé)1~2000的書包柜分配咪橙,第二個(gè)隊(duì)列負(fù)責(zé)2001~4000的書包柜分配任務(wù)夕膀,以此類推。每次進(jìn)入java請(qǐng)求美侦,隨機(jī)分配其進(jìn)入任一隊(duì)列产舞,然后由此隊(duì)列按其任務(wù)順序分配書包柜。那么菠剩,當(dāng)有多個(gè)隊(duì)列時(shí)易猫,該如何設(shè)置memcached中的標(biāo)志位來表示書包柜是否搶購?fù)戤吥兀?br> 首先,初始值仍設(shè)為0具壮,代表書包柜還有剩余准颓。對(duì)于每個(gè)隊(duì)列,當(dāng)任務(wù)均已執(zhí)行完畢棺妓,如第一個(gè)隊(duì)列1~2000的書包柜均已分配完畢攘已,則對(duì)memcached中的標(biāo)志位進(jìn)行一次更新加1,當(dāng)標(biāo)志位為5時(shí)怜跑,代表書包柜分配完畢样勃。在PHP的第二次控制中,對(duì)memcached中標(biāo)志位進(jìn)行讀取妆艘,若為0彤灶,則將此請(qǐng)求放行,進(jìn)入Java代碼部分批旺,若為5幌陕,則代表書包柜已被搶購?fù)戤叄琍HP代碼返回給用戶提示信息汽煮,提示信息為:書包柜已搶購?fù)戤叢āT趫?zhí)行過程中棚唆,很可能某個(gè)的任務(wù)提前完成了,這時(shí)就可以將這個(gè)隊(duì)列消除心例。