春節(jié)即將來(lái)臨,大家想必目前最重要的事就是買車票回家了。這是個(gè)春運(yùn)時(shí)刻,車票都是非常緊張的,所以大家都在通過(guò)各種渠道搶能往溫暖家的懷抱的旅程票。有的在電話上訂購(gòu),有的在代售點(diǎn)排起長(zhǎng)長(zhǎng)的列隊(duì),現(xiàn)在的網(wǎng)絡(luò)這么發(fā)達(dá),怎么可以沒(méi)有網(wǎng)絡(luò)訂票呢,今天2012的春運(yùn)就建立起來(lái)了一個(gè)完整的網(wǎng)站,最強(qiáng)大的一個(gè)系統(tǒng)就是網(wǎng)絡(luò)訂票。這個(gè)網(wǎng)站建設(shè)的對(duì)我們是那么的重要。
關(guān)于12306網(wǎng)站和清華某院長(zhǎng)的微博言論,我做了一個(gè)小回復(fù),說(shuō)這玩意不難,2個(gè)人2周,40臺(tái)服務(wù)器可以搞定。
下面詳細(xì)解釋一下大概的思路。免費(fèi)share一下,看看靠譜不靠譜。
別人看到的是流量,我先看結(jié)構(gòu),這里的數(shù)據(jù)結(jié)構(gòu)是相當(dāng)簡(jiǎn)單的,主要滿足的需求是:
1.車次查詢(最常見(jiàn)的是起點(diǎn)站,終點(diǎn)站查詢 和車次直接輸入查詢)+余票顯示
所謂的用戶刷頁(yè)面,絕大部分應(yīng)該在這里。日均10億pv(這個(gè)數(shù)字我先質(zhì)疑一下,不過(guò)么關(guān)系,后面再說(shuō)怎么處理),估計(jì)主要落在這個(gè)查詢上。
2.注冊(cè),登陸。每天過(guò)千萬(wàn)人次是有的
3.下單,也就是日成交訂單量,可能存在下單失敗,約幾百萬(wàn)次。
這里基本不涉及復(fù)雜的關(guān)系操作,不涉及推拉結(jié)構(gòu),和新浪微博,facebook這樣的應(yīng)用場(chǎng)景相比,在數(shù)據(jù)關(guān)系上簡(jiǎn)直毫無(wú)難度,這也才是我敢說(shuō)大話的原因。
因?yàn)椴簧婕皬?fù)雜的關(guān)系操作,不涉及個(gè)性展示(不同用戶搜索同樣的條件,結(jié)果一致),那么緩存化就是最佳途徑。
1.存儲(chǔ)key-value化, 推薦redis
基本上查詢都是直線式的,所以key-value就是很好的工具;因?yàn)槌銎笨赡苄枰乙幌萝嚧危唬荒芤灰粚?duì)應(yīng)的查詢就不好用;弄個(gè)redis帶個(gè)列表結(jié)構(gòu)(dict or zset ,哪個(gè)結(jié)構(gòu)更合適?問(wèn)問(wèn)新浪架構(gòu)師楊衛(wèi)華吧,這事估計(jì)對(duì)他太簡(jiǎn)單了)進(jìn)去就可以了。春節(jié)放票總共多少?gòu)垼坑植皇且淮畏懦鰜?lái),每張票對(duì)應(yīng)一個(gè)key,一個(gè)value,能吃多少內(nèi)存?后面跟個(gè)數(shù)據(jù)庫(kù)做同步,這點(diǎn)數(shù)據(jù)量對(duì)于現(xiàn)在的服務(wù)器來(lái)說(shuō)根本不是問(wèn)題。
注冊(cè)登陸也可以在 mysql基礎(chǔ)上弄個(gè)redis掛在前頭響應(yīng),這種查詢速度,biu.
根據(jù)不同車次分幾臺(tái)服務(wù)器,響應(yīng)速度根本不是問(wèn)題。
2.將所有查詢結(jié)果緩存化,靜態(tài)化
首先明確一下查詢的步驟,實(shí)際上主要查詢分兩步
第一步是查詢符合要求的車次,第二步是查詢余票。
緩存也就分兩步做,起始地,目標(biāo)地查詢 - 常見(jiàn)查詢目標(biāo)(如北京到成都)全部預(yù)制緩存。非常見(jiàn)查詢目標(biāo),基于第一次查詢的結(jié)果緩存,這樣查詢車次基本上無(wú)壓力。
查詢有票狀態(tài)就更簡(jiǎn)單了,因?yàn)槠睌?shù)只有有票,無(wú)票兩個(gè)狀態(tài),某日某車次作為一個(gè)key-value類型存儲(chǔ)(仍用redis即可)。某類車票發(fā)生從有到無(wú)或從無(wú)到有的變化,才通知緩存更新。更新是后臺(tái)通知的,而非基于用戶查詢。比如某車次硬臥票售完,通知一次更新,硬座售完,通知一次更新,軟座售完,通知一次更新。以此類推,這樣的緩存更新次數(shù)極少。而且可以給前端返回甚至靜態(tài)結(jié)果(基于查詢條件生成靜態(tài)結(jié)果,是個(gè)網(wǎng)站推廣都都會(huì)的,后臺(tái)在票數(shù)變化時(shí)通知更新,這樣結(jié)構(gòu)上就與前端查詢無(wú)關(guān)了,而且一樣可以保持實(shí)時(shí)性)。
如果你較真說(shuō),其實(shí)一個(gè)車次在不同區(qū)間也存在有無(wú)票的不同,的確,不過(guò)按照同樣思路,結(jié)構(gòu)多做一層死不了人的。畢竟這只是概述。但是核心思路不變,緩存的變更次數(shù)遠(yuǎn)少于查詢請(qǐng)求次數(shù),這就夠了。
3.前端緩存處理
很多人被10億請(qǐng)求數(shù)嚇到了,其實(shí)這里水分很大,最多的是重復(fù)刷新和外掛工具,那么如果你做到基于2的查詢結(jié)果緩存化,這一步就簡(jiǎn)單了;直接參見(jiàn)這篇文章,大量的用戶重復(fù)刷新根本不是問(wèn)題。 想知道實(shí)際效果,看這里1小時(shí)20億的刷新都不怕,還怕你一天10億刷新?
4.i/o推廣
其實(shí)我甚至覺(jué)得用了redis都不需要做i/o推廣了,如果用戶單據(jù)需要數(shù)據(jù)庫(kù)保存,一天200萬(wàn)單嘛,搜一下 淘寶技術(shù)專家余鋒分享的qcon講座文檔,順便讀一下他歷來(lái)新浪微博分享的文字,這個(gè)需求簡(jiǎn)直就是小兒科了。 大不了狠狠心買幾塊ssd硬盤做raid1/0,對(duì)于我這樣的窮架構(gòu)師來(lái)說(shuō),都屬于大手筆了,至于昂貴的fusion-io,我真覺(jué)得,這個(gè)場(chǎng)景用不著,實(shí)在用不著。
這里關(guān)鍵點(diǎn),是查詢結(jié)果的靜態(tài)化和前段緩存的利用
查詢?cè)趺纯赡莒o態(tài)化?
因?yàn)?/p>
1:重復(fù)查詢的頻度遠(yuǎn)遠(yuǎn)大于數(shù)據(jù)更新的頻度(即便是票數(shù)的更新,也是500:1,更不用說(shuō)是有無(wú)的變化)
2:靜態(tài)化不代表不動(dòng)態(tài)更新,在訂票成功后,如果發(fā)生了票數(shù)狀態(tài)的改變(是狀態(tài)改變,而不是數(shù)字改變),服務(wù)端更新或刪除該靜態(tài)結(jié)果(下一次查詢重新生成靜態(tài)結(jié)果)
至于為什么說(shuō)2人2周,別搞花的,別圖好看,就把這些結(jié)構(gòu)捋清楚,代碼能有多少行?這玩意沒(méi)什么工作量。
此外,有人說(shuō),你肯定沒(méi)考慮神馬神馬神馬神馬;您說(shuō)對(duì)了,我還真沒(méi)考慮這么多,畢竟鐵道部沒(méi)給我1000多萬(wàn),不過(guò)真要是給了我1000多萬(wàn),我用三天時(shí)間考慮清楚,肯定比這不到1個(gè)小時(shí)整理的東西詳細(xì),您覺(jué)得呢,剩下一周半干活足夠完工了,過(guò)完這一周半,2011年的網(wǎng)頁(yè)設(shè)計(jì)任務(wù)算是完結(jié)了,該回家和親愛(ài)的家人團(tuán)聚了。