秒殺系統(tǒng)架構(gòu)優(yōu)化思路

一翼悴、秒殺業(yè)務(wù)為什么難做
1)im系統(tǒng)缚够,例如qq或者微博,每個人都讀自己的數(shù)據(jù)(好友列表鹦赎、群列表谍椅、個人信息);
2)微博系統(tǒng)古话,每個人讀你關(guān)注的人的數(shù)據(jù)雏吭,一個人讀多個人的數(shù)據(jù);
3)秒殺系統(tǒng)陪踩,庫存只有一份杖们,所有人會在集中的時間讀和寫這些數(shù)據(jù),多個人讀一個數(shù)據(jù)肩狂。

例如:小米手機(jī)每周二的秒殺摘完,可能手機(jī)只有1萬部,但瞬時進(jìn)入的流量可能是幾百幾千萬傻谁。
又例如:12306搶票孝治,票是有限的,庫存一份,瞬時流量非常多谈飒,都讀相同的庫存岂座。讀寫沖突,鎖非常嚴(yán)重杭措,這是秒殺業(yè)務(wù)難的地方费什。那我們怎么優(yōu)化秒殺業(yè)務(wù)的架構(gòu)呢?

二手素、優(yōu)化方向
優(yōu)化方向有兩個(今天就講這兩個點(diǎn)):
(1)將請求盡量攔截在系統(tǒng)上游(不要讓鎖沖突落到數(shù)據(jù)庫上去)吕喘。傳統(tǒng)秒殺系統(tǒng)之所以掛,請求都壓倒了后端數(shù)據(jù)層刑桑,數(shù)據(jù)讀寫鎖沖突嚴(yán)重,并發(fā)高響應(yīng)慢募舟,幾乎所有請求都超時祠斧,流量雖大,下單成功的有效流量甚小拱礁。以12306為例琢锋,一趟火車其實(shí)只有2000張票,200w個人來買呢灶,基本沒有人能買成功吴超,請求有效率為0。
(2)充分利用緩存鸯乃,秒殺買票鲸阻,這是一個典型的讀多些少的應(yīng)用場景,大部分請求是車次查詢缨睡,票查詢鸟悴,下單和支付才是寫請求。一趟火車其實(shí)只有2000張票奖年,200w個人來買细诸,最多2000個人下單成功,其他人都是查詢庫存陋守,寫比例只有0.1%震贵,讀比例占99.9%,非常適合使用緩存來優(yōu)化水评。好猩系,后續(xù)講講怎么個“將請求盡量攔截在系統(tǒng)上游”法,以及怎么個“緩存”法之碗,講講細(xì)節(jié)蝙眶。

三、常見秒殺架構(gòu)
常見的站點(diǎn)架構(gòu)基本是這樣的(絕對不畫忽悠類的架構(gòu)圖)

(1)瀏覽器端,最上層幽纷,會執(zhí)行到一些JS代碼
(2)站點(diǎn)層式塌,這一層會訪問后端數(shù)據(jù),拼html頁面返回給瀏覽器
(3)服務(wù)層友浸,向上游屏蔽底層數(shù)據(jù)細(xì)節(jié)峰尝,提供數(shù)據(jù)訪問
(4)數(shù)據(jù)層,最終的庫存是存在這里的收恢,mysql是一個典型(當(dāng)然還有會緩存)
這個圖雖然簡單武学,但能形象的說明大流量高并發(fā)的秒殺業(yè)務(wù)架構(gòu),大家要記得這一張圖伦意。
后面細(xì)細(xì)解析各個層級怎么優(yōu)化火窒。

四、各層次優(yōu)化細(xì)節(jié)
第一層驮肉,客戶端怎么優(yōu)化(瀏覽器層熏矿,APP****層)
問大家一個問題,大家都玩過微信的搖一搖搶紅包對吧离钝,每次搖一搖票编,就會往后端發(fā)送請求么?回顧我們下單搶票的場景卵渴,點(diǎn)擊了“查詢”按鈕之后慧域,系統(tǒng)那個卡呀,進(jìn)度條漲的慢呀浪读,作為用戶昔榴,我會不自覺的再去點(diǎn)擊“查詢”,對么碘橘?繼續(xù)點(diǎn)论泛,繼續(xù)點(diǎn),點(diǎn)點(diǎn)點(diǎn)蛹屿。屁奏。。有用么错负?平白無故的增加了系統(tǒng)負(fù)載坟瓢,一個用戶點(diǎn)5次,80%的請求是這么多出來的犹撒,怎么整折联?
(a)產(chǎn)品層面,用戶點(diǎn)擊“查詢”或者“購票”后识颊,按鈕置灰诚镰,禁止用戶重復(fù)提交請求奕坟;
(b)JS層面,限制用戶在x秒之內(nèi)只能提交一次請求清笨;
APP層面月杉,可以做類似的事情,雖然你瘋狂的在搖微信抠艾,其實(shí)x秒才向后端發(fā)起一次請求苛萎。這就是所謂的“將請求盡量攔截在系統(tǒng)上游”,越上游越好检号,瀏覽器層腌歉,APP層就給攔住,這樣就能擋住80%+的請求齐苛,這種辦法只能攔住普通用戶(但99%的用戶是普通用戶)對于群內(nèi)的高端程序員是攔不住的翘盖。firebug一抓包,http長啥樣都知道凹蜂,js是萬萬攔不住程序員寫for循環(huán)最仑,調(diào)用http接口的,這部分請求怎么處理炊甲?

第二層,站點(diǎn)層面的請求攔截
怎么攔截欲芹?怎么防止程序員寫for循環(huán)調(diào)用卿啡,有去重依據(jù)么?ip菱父?cookie-id颈娜?…想復(fù)雜了,這類業(yè)務(wù)都需要登錄浙宜,用uid即可官辽。在站點(diǎn)層面,對uid進(jìn)行請求計(jì)數(shù)和去重粟瞬,甚至不需要統(tǒng)一存儲計(jì)數(shù)同仆,直接站點(diǎn)層內(nèi)存存儲(這樣計(jì)數(shù)會不準(zhǔn),但最簡單)裙品。一個uid俗批,5秒只準(zhǔn)透過1個請求,這樣又能攔住99%的for循環(huán)請求市怎。
5s只透過一個請求岁忘,其余的請求怎么辦?緩存区匠,頁面緩存干像,同一個uid,限制訪問頻度,做頁面緩存麻汰,x秒內(nèi)到達(dá)站點(diǎn)層的請求速客,均返回同一頁面。同一個item的查詢什乙,例如車次挽封,做頁面緩存,x秒內(nèi)到達(dá)站點(diǎn)層的請求臣镣,均返回同一頁面辅愿。如此限流,既能保證用戶有良好的用戶體驗(yàn)(沒有返回404)又能保證系統(tǒng)的健壯性(利用頁面緩存忆某,把請求攔截在站點(diǎn)層了)点待。
頁面緩存不一定要保證所有站點(diǎn)返回一致的頁面,直接放在每個站點(diǎn)的內(nèi)存也是可以的弃舒。優(yōu)點(diǎn)是簡單癞埠,壞處是http請求落到不同的站點(diǎn),返回的車票數(shù)據(jù)可能不一樣聋呢,這是站點(diǎn)層的請求攔截與緩存優(yōu)化苗踪。

好,這個方式攔住了寫for循環(huán)發(fā)http請求的程序員削锰,有些高端程序員(黑客)控制了10w個肉雞通铲,手里有10w個uid,同時發(fā)請求(先不考慮實(shí)名制的問題器贩,小米搶手機(jī)不需要實(shí)名制)颅夺,這下怎么辦,站點(diǎn)層按照uid限流攔不住了蛹稍。

第三層 ****服務(wù)層來攔截(反正就是不要讓請求落到數(shù)據(jù)庫上去)
服務(wù)層怎么攔截吧黄?大哥,我是服務(wù)層唆姐,我清楚的知道小米只有1萬部手機(jī)拗慨,我清楚的知道一列火車只有2000張車票,我透10w個請求去數(shù)據(jù)庫有什么意義呢奉芦?沒錯胆描,請求隊(duì)列!
對于寫請求仗阅,做請求隊(duì)列昌讲,每次只透有限的寫請求去數(shù)據(jù)層(下訂單,支付這樣的寫業(yè)務(wù))
1w部手機(jī)减噪,只透1w個下單請求去db
3k張火車票短绸,只透3k個下單請求去db
如果均成功再放下一批车吹,如果庫存不夠則隊(duì)列里的寫請求全部返回“已售完”。

對于讀請求醋闭,怎么優(yōu)化窄驹?cache抗,不管是memcached還是redis证逻,單機(jī)抗個每秒10w應(yīng)該都是沒什么問題的乐埠。如此限流,只有非常少的寫請求囚企,和非常少的讀緩存mis的請求會透到數(shù)據(jù)層去丈咐,又有99.9%的請求被攔住了。

當(dāng)然龙宏,還有業(yè)務(wù)規(guī)則上的一些優(yōu)化棵逊。回想12306所做的银酗,分時分段售票辆影,原來統(tǒng)一10點(diǎn)賣票,現(xiàn)在8點(diǎn)黍特,8點(diǎn)半蛙讥,9點(diǎn),...每隔半個小時放出一批:將流量攤勻灭衷。
其次次慢,數(shù)據(jù)粒度的優(yōu)化:你去購票,對于余票查詢這個業(yè)務(wù)今布,票剩了58張,還是26張拭抬,你真的關(guān)注么部默,其實(shí)我們只關(guān)心有票和無票?流量大的時候造虎,做一個粗粒度的“有票”“無票”緩存即可傅蹂。
第三,一些業(yè)務(wù)邏輯的異步:例如下單業(yè)務(wù)與 支付業(yè)務(wù)的分離算凿。這些優(yōu)化都是結(jié)合 業(yè)務(wù) 來的份蝴,我之前分享過一個觀點(diǎn)“一切脫離業(yè)務(wù)的架構(gòu)設(shè)計(jì)都是耍流氓”架構(gòu)的優(yōu)化也要針對業(yè)務(wù)。

好了氓轰,最后是數(shù)據(jù)庫層
瀏覽器攔截了80%婚夫,站點(diǎn)層攔截了99.9%并做了頁面緩存,服務(wù)層又做了寫請求隊(duì)列與數(shù)據(jù)緩存署鸡,每次透到數(shù)據(jù)庫層的請求都是可控的案糙。db基本就沒什么壓力了限嫌,閑庭信步,單機(jī)也能扛得住时捌,還是那句話怒医,庫存是有限的,小米的產(chǎn)能有限奢讨,透這么多請求來數(shù)據(jù)庫沒有意義稚叹。
全部透到數(shù)據(jù)庫,100w個下單拿诸,0個成功扒袖,請求有效率0%。透3k個到數(shù)據(jù)佳镜,全部成功僚稿,請求有效率100%。

五蟀伸、總結(jié)
上文應(yīng)該描述的非常清楚了蚀同,沒什么總結(jié)了,對于秒殺系統(tǒng)啊掏,再次重復(fù)下我個人經(jīng)驗(yàn)的兩個架構(gòu)優(yōu)化思路:
(1)盡量將請求攔截在系統(tǒng)上游(越上游越好)蠢络;
(2)讀多寫少的常用多使用緩存(緩存抗讀壓力);
瀏覽器和APP:做限速
站點(diǎn)層:按照uid做限速迟蜜,做頁面緩存
服務(wù)層:按照業(yè)務(wù)做寫請求隊(duì)列控制流量刹孔,做數(shù)據(jù)緩存
數(shù)據(jù)層:閑庭信步
并且:結(jié)合業(yè)務(wù)做優(yōu)化

六、Q&A
問題1****娜睛、按你的架構(gòu)髓霞,其實(shí)壓力最大的反而是站點(diǎn)層,假設(shè)真實(shí)有效的請求數(shù)有1000****萬畦戒,不太可能限制請求連接數(shù)吧方库,那么這部分的壓力怎么處理?
答:每秒鐘的并發(fā)可能沒有1kw障斋,假設(shè)有1kw纵潦,解決方案2個:
(1)站點(diǎn)層是可以通過加機(jī)器擴(kuò)容的,最不濟(jì)1k臺機(jī)器來唄垃环。
(2)如果機(jī)器不夠邀层,拋棄請求,拋棄50%(50%直接返回稍后再試)遂庄,原則是要保護(hù)系統(tǒng)寥院,不能讓所有用戶都失敗。

問題2****涛目、“控制了10w****個肉雞只磷,手里有10w****個uid****经磅,同時發(fā)請求” ****這個問題怎么解決哈?
答:上面說了钮追,服務(wù)層寫請求隊(duì)列控制

問題3****:****限制訪問頻次的緩存预厌,是否也可以用于搜索?例如A****用戶搜索了“手機(jī)”元媚,B****用戶搜索“手機(jī)”轧叽,優(yōu)先使用A****搜索后生成的緩存頁面?
答:這個是可以的刊棕,這個方法也經(jīng)常用在“動態(tài)”運(yùn)營活動頁炭晒,例如短時間推送4kw用戶app-push運(yùn)營活動,做頁面緩存甥角。

問題4****:如果隊(duì)列處理失敗网严,如何處理?肉雞把隊(duì)列被撐爆了怎么辦嗤无?
答:處理失敗返回下單失敗震束,讓用戶再試。隊(duì)列成本很低当犯,爆了很難吧垢村。最壞的情況下,緩存了若干請求之后嚎卫,后續(xù)請求都直接返回“無票”(隊(duì)列里已經(jīng)有100w請求了嘉栓,都等著,再接受請求也沒有意義了)

問題5****:站點(diǎn)層過濾的話拓诸,是把uid****請求數(shù)單獨(dú)保存到各個站點(diǎn)的內(nèi)存中么侵佃?如果是這樣的話,怎么處理多臺服務(wù)器集群經(jīng)過負(fù)載均衡器將相同用戶的響應(yīng)分布到不同服務(wù)器的情況呢奠支?還是說將站點(diǎn)層的過濾放到負(fù)載均衡前馋辈?
答:可以放在內(nèi)存,這樣的話看似一臺服務(wù)器限制了5s一個請求胚宦,全局來說(假設(shè)有10臺機(jī)器)首有,其實(shí)是限制了5s 10個請求燕垃,解決辦法:
1)加大限制(這是建議的方案枢劝,最簡單)
2)在nginx層做7層均衡,讓一個uid的請求盡量落到同一個機(jī)器上

問題6****:服務(wù)層過濾的話卜壕,隊(duì)列是服務(wù)層統(tǒng)一的一個隊(duì)列您旁?還是每個提供服務(wù)的服務(wù)器各一個隊(duì)列?如果是統(tǒng)一的一個隊(duì)列的話轴捎,需不需要在各個服務(wù)器提交的請求入隊(duì)列前進(jìn)行鎖控制鹤盒?
答:可以不用統(tǒng)一一個隊(duì)列蚕脏,這樣的話每個服務(wù)透過更少量的請求(總票數(shù)/服務(wù)個數(shù)),這樣簡單侦锯。統(tǒng)一一個隊(duì)列又復(fù)雜了驼鞭。

問題7****:秒殺之后的支付完成,以及未支付取消占位尺碰,如何對剩余庫存做及時的控制更新****挣棕?
答:數(shù)據(jù)庫里一個狀態(tài),未支付亲桥。如果超過時間洛心,例如45分鐘,庫存會重新會恢復(fù)(大家熟知的“回倉”)题篷,給我們搶票的啟示是词身,開動秒殺后,45分鐘之后再試試看番枚,說不定又有票喲~

問題8****:不同的用戶****瀏覽同一個商品 ****落在不同的緩存實(shí)例****顯示的庫存完全不一樣 ****請問老師怎么做緩存數(shù)據(jù)一致****或者是允許臟讀法严?
答:目前的架構(gòu)設(shè)計(jì),請求落到不同的站點(diǎn)上户辫,數(shù)據(jù)可能不一致(頁面緩存不一樣)渐夸,這個業(yè)務(wù)場景能接受。但數(shù)據(jù)庫層面真實(shí)數(shù)據(jù)是沒問題的渔欢。

問題9****:就算處于業(yè)務(wù)把優(yōu)化考慮****“3k****張火車票墓塌,只透3k****個下單請求去db****”那這3K****個訂單就不會發(fā)生擁堵了嗎?
答:(1)數(shù)據(jù)庫抗3k個寫請求還是ok的奥额;(2)可以數(shù)據(jù)拆分苫幢;(3)如果3k扛不住,服務(wù)層可以控制透過去的并發(fā)數(shù)量垫挨,根據(jù)壓測情況來吧韩肝,3k只是舉例;

問題10****九榔;如果在站點(diǎn)層或者服務(wù)層處理后臺失敗的話哀峻,需不需要考慮對這批處理失敗的請求做重放?還是就直接丟棄哲泊?
答:別重放了剩蟀,返回用戶查詢失敗或者下單失敗吧,架構(gòu)設(shè)計(jì)原則之一是“fail fast”切威。

問題11.****對于大型系統(tǒng)的秒殺育特,比如12306****,同時進(jìn)行的秒殺活動很多先朦,如何分流缰冤?
答:垂直拆分

問題12****犬缨、額外又想到一個問題。這套流程做成同步還是異步的棉浸?如果是同步的話怀薛,應(yīng)該還存在會有響應(yīng)反饋慢的情況。但如果是異步的話迷郑,如何控制能夠?qū)㈨憫?yīng)結(jié)果返回正確的請求方乾戏?
答:用戶層面肯定是同步的(用戶的http請求是夯住的),服務(wù)層面可以同步可以異步三热。

問題13****鼓择、秒殺群提問:減庫存是在那個階段減呢?如果是下單鎖庫存的話就漾,大量惡意用戶下單鎖庫存而不支付如何處理呢呐能?

答:數(shù)據(jù)庫層面寫請求量很低,還好抑堡,下單不支付摆出,等時間過完再“回倉”,之前提過了首妖。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末偎漫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子有缆,更是在濱河造成了極大的恐慌象踊,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棚壁,死亡現(xiàn)場離奇詭異杯矩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)袖外,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門史隆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人曼验,你說我怎么就攤上這事泌射。” “怎么了鬓照?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵熔酷,是天一觀的道長。 經(jīng)常有香客問我颖杏,道長纯陨,這世上最難降的妖魔是什么坛芽? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任留储,我火速辦了婚禮翼抠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘获讳。我一直安慰自己阴颖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布丐膝。 她就那樣靜靜地躺著量愧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪帅矗。 梳的紋絲不亂的頭發(fā)上偎肃,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機(jī)與錄音浑此,去河邊找鬼累颂。 笑死,一個胖子當(dāng)著我的面吹牛凛俱,可吹牛的內(nèi)容都是我干的紊馏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼蒲犬,長吁一口氣:“原來是場噩夢啊……” “哼朱监!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起原叮,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤赫编,失蹤者是張志新(化名)和其女友劉穎窃这,沒想到半個月后忧风,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體劲藐,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蓝厌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年驰徊,在試婚紗的時候發(fā)現(xiàn)自己被綠了睁冬。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片镐确。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡祥诽,死狀恐怖黍聂,靈堂內(nèi)的尸體忽然破棺而出躺苦,到底是詐尸還是另有隱情,我是刑警寧澤产还,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布匹厘,位于F島的核電站,受9級特大地震影響脐区,放射性物質(zhì)發(fā)生泄漏愈诚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望炕柔。 院中可真熱鬧酌泰,春花似錦、人聲如沸匕累。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽欢嘿。三九已至衰琐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間炼蹦,已是汗流浹背羡宙。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掐隐,地道東北人辛辨。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像瑟枫,于是被迫代替她去往敵國和親斗搞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容