http://coolshell.cn/articles/6470.html
12306.cn網站掛了,被全國人民罵了称鳞。我這兩天也在思考這個事,我想以這個事來粗略地和大家討論一下網站性能的問題稠鼻。因為倉促冈止,而且完全基于本人有限的經驗和了解,所以候齿,如果有什么問題還請大家一起討論和指正熙暴。(這又是一篇長文,只討論性能問題慌盯,不討論那些UI怨咪,用戶體驗,或是是否把支付和購票下單環(huán)節(jié)分開的功能性的東西)
業(yè)務
任何技術都離不開業(yè)務需求润匙,所以诗眨,要說明性能問題,首先還是想先說說業(yè)務問題孕讳。
其一匠楚,有人可能把這個東西和QQ或是網游相比。但我覺得這兩者是不一樣的厂财,網游和QQ在線或是登錄時訪問的更多的是用戶自己的數(shù)據(jù)芋簿,而訂票系統(tǒng)訪問的是中心的票量數(shù)據(jù),這是不一樣的璃饱。不要覺得網游或是QQ能行你就以為這是一樣的与斤。網游和QQ 的后端負載相對于電子商務的系統(tǒng)還是簡單。
其二荚恶,有人說春節(jié)期間訂火車的這個事好像網站的秒殺活動撩穿。的確很相似,但是如果你的思考不在表面的話谒撼,你會發(fā)現(xiàn)這也有些不一樣食寡。火車票這個事廓潜,一方面會伴隨著大量的查詢操作抵皱,更BT的是下單的時候需要對數(shù)據(jù)庫很多的一致性的操作善榛,一方面是從起點到終點各個分段票的一致性,另一方面呻畸,買的人路線移盆、車次、時間選擇有很多伤为,會不停地改變下單方式味滞。而秒殺,直接殺就好了钮呀,沒有那么多查詢和一致性的問題剑鞍。另外,關于秒殺爽醋,完全可以做成只接受前N個用戶的請求(完全不操作后端的任何數(shù)據(jù)蚁署, 僅僅只是對用戶的下單操作log),這種業(yè)務蚂四,只需要在內存cache中放好可秒殺的數(shù)量光戈,還可以把數(shù)據(jù)分布開來放,100商品遂赠,10臺服務器一臺放10個久妆,無需在當時操作任何數(shù)據(jù)庫□文溃可以訂單數(shù)夠后筷弦,停止秒殺,然后批量寫數(shù)據(jù)庫抑诸。而且秒殺的商品不多烂琴。火車票這個不是像秒殺那么簡單的蜕乡,春運時間奸绷,幾乎所有的票都是熱門票,而且?guī)缀跏侨珖嗣穸紒砹瞬懔幔疫€有轉車業(yè)務号醉,多條線的庫存都要做事務操作,你想想吧辛块,這有多難畔派。(淘寶的雙十一也就3百萬用戶,而火車票瞬時有千萬級別甚至是億級別的)(更新:2014年1月11日:來了淘寶后憨降,對淘寶的系統(tǒng)有了解父虑,淘寶的秒殺活動该酗,本質上是用輸驗證碼并在CDN上把用戶直接過濾掉了授药,比如:1千萬個用戶過濾了只剩2萬個用戶士嚎,這樣數(shù)據(jù)庫就頂?shù)米×耍?/p>
其三,有人拿這個系統(tǒng)和奧運會的票務系統(tǒng)比較悔叽。我覺得還是不一樣莱衩。雖然奧運會的票務系統(tǒng)當年也一上線就廢了。但是奧運會用的是抽獎的方式,也就是說不存在先來先得的搶的方式,而且岸晦,是事后抽獎饺鹃,事前只需要收信息,事前不需要保證數(shù)據(jù)一致性氯质,沒有鎖,很容易水平擴展。
其四奋单,訂票系統(tǒng)應該和電子商務的訂單系統(tǒng)很相似,都是需要對庫存進行:1)占住庫存猫十,2)支付(可選)览濒,3)扣除庫存的操作。這個是需要有一致性的檢查的拖云,也就是在并發(fā)時需要對數(shù)據(jù)加鎖的贷笛。B2C的電商基本上都會把這個事干成異步的,也就是說宙项,你下的訂單并不是馬上處理的乏苦,而是延時處理的,只有成功處理了尤筐,系統(tǒng)才會給你一封確認郵件說是訂單成功邑贴。我相信有很多朋友都收到認單不成功的郵件。這就是說叔磷,數(shù)據(jù)一致性在并發(fā)下是一個瓶頸拢驾。
其五,鐵路的票務業(yè)務很變態(tài)改基,其采用的是突然放票繁疤,而有的票又遠遠不夠大家分,所以秕狰,大家才會有搶票這種有中國特色的業(yè)務的做法稠腊。于是當票放出來的時候,就會有幾百萬人甚至上千萬人殺上去鸣哀,查詢架忌,下單。幾十分鐘內我衬,一個網站能接受幾千萬的訪問量叹放,這個是很恐怖的事情饰恕。據(jù)說12306的高峰訪問是10億PV,集中在早8點到10點井仰,每秒PV在高峰時上千萬埋嵌。
多說幾句:
庫存是B2C的惡夢,庫存管理相當?shù)膹碗s俱恶。不信雹嗦,你可以問問所有傳統(tǒng)和電務零售業(yè)的企業(yè),看看他們管理庫存是多么難的一件事合是。不然了罪,就不會有那么多人在問凡客的庫存問題了。(你還可以看看《喬布斯傳》聪全,你就知道為什么Tim會接任Apple的CEO了捶惜,最主要的原因是他搞定了蘋果的庫存周期問題)
對于一個網站來說,瀏覽網頁的高負載很容易搞定荔烧,查詢的負載有一定的難度去處理吱七,不過還是可以通過緩存查詢結果來搞定,最難的就是下單的負載鹤竭。因為要訪問庫存啊踊餐,對于下單,基本上是用異步來搞定的臀稚。去年雙11節(jié)吝岭,淘寶的每小時的訂單數(shù)大約在60萬左右,京東一天也才能支持40萬(居然比12306還差)吧寺,亞馬遜5年前一小時可支持70萬訂單量窜管。可見稚机,下訂單的操作并沒有我們相像的那么性能高幕帆。
淘寶要比B2C的網站要簡單得多,因為沒有倉庫赖条,所以失乾,不存在像B2C這樣有N個倉庫對同一商品庫存更新和查詢的操作。下單的時候纬乍,B2C的 網站要去找一個倉庫碱茁,又要離用戶近,又要有庫存仿贬,這需要很多計算纽竣。試想,你在北京買了一本書,北京的倉庫沒貨了蜓氨,就要從周邊的倉庫調聋袋,那就要去看看沈陽或 是西安的倉庫有沒有貨,如果沒有语盈,又得看看江蘇的倉庫舱馅,等等缰泡。淘寶的就沒有那么多事了刀荒,每個商戶有自己的庫存,庫存就是一個數(shù)字棘钞,并且?guī)齑娣值缴虘纛^上了缠借,反而有利于性能擴展。
數(shù)據(jù)一致性才是真正的性能瓶頸宜猜。有 人說nginx可以搞定每秒10萬的靜態(tài)請求泼返,我不懷疑。但這只是靜態(tài)請求姨拥,理論值绅喉,只要帶寬、I/O夠強叫乌,服務器計算能力夠柴罐,并支持的并發(fā)連接數(shù)頂?shù)米?0萬TCP鏈接的建立 的話,那沒有問題憨奸。但在數(shù)據(jù)一致性面前革屠,這10萬就完完全全成了一個可望不可及的理論值了。
我說那么多排宰,我只是想從業(yè)務上告訴大家似芝,我們需要從業(yè)務上真正了解春運鐵路訂票這樣業(yè)務的變態(tài)之處。
前端性能優(yōu)化技術
要解決性能的問題板甘,有很多種常用的方法党瓮,我在下面列舉一下,我相信12306這個網站使用下面的這些技術會讓其性能有質的飛躍盐类。
一麻诀、前端負載均衡
通過DNS的負載均衡器(一般在路由器上根據(jù)路由的負載重定向)可以把用戶的訪問均勻地分散在多個Web服務器上。這樣可以減少Web服務器的請求負載傲醉。因為http的請求都是短作業(yè)蝇闭,所以,可以通過很簡單的負載均衡器來完成這一功能硬毕。最好是有CDN網絡讓用戶連接與其最近的服務器(CDN通常伴隨著分布式存儲)呻引。(關于負載均衡更為詳細的說明見“后端的負載均衡”)
二、減少前端鏈接數(shù)
我看了一下12306.cn吐咳,打開主頁需要建60多個HTTP連接逻悠,車票預訂頁面則有70多個HTTP請求元践,現(xiàn)在的瀏覽器都是并發(fā)請求的(當然,瀏覽器的一個頁面的并發(fā)數(shù)是有限的童谒,但是你擋不住用戶開多個頁面单旁,而且,后端服務器TCP鏈接在前端斷開始饥伊,還不會馬上釋放或重要)象浑。所以,只要有100萬個用戶琅豆,就有可能會有6000萬個鏈接(訪問第一次后有了瀏覽器端的cache愉豺,這個數(shù)會下來,就算只有20%也是百萬級的鏈接數(shù))茫因,太多了蚪拦。一個登錄查詢頁面就好了。把js打成一個文件冻押,把css也打成一個文件驰贷,把圖標也打成一個文件,用css分塊展示洛巢。把鏈接數(shù)減到最低括袒。
三、減少網頁大小增加帶寬
這個世界不是哪個公司都敢做圖片服務的狼渊,因為圖片太耗帶寬了∠浒荆現(xiàn)在寬帶時代很難有人能體會到當撥號時代做個圖頁都不敢用圖片的情形(現(xiàn)在在手機端瀏覽也是這個情形)。我查看了一下12306首頁的需要下載的總文件大小大約在900KB左右狈邑,如果你訪問過了城须,瀏覽器會幫你緩存很多,只需下載10K左右的文件米苹。但是我們可以想像一個極端一點的案例糕伐,1百萬用戶同時訪問,且都是第一次訪問蘸嘶,每人下載量需要1M良瞧,如果需要在120秒內返回,那么就需要训唱,1M * 1M /120 * 8 = 66Gbps的帶寬褥蚯。很驚人吧。所以况增,我估計在當天赞庶,12306的阻塞基本上應該是網絡帶寬,所以,你可能看到的是沒有響應歧强。后面隨著瀏覽器的緩存幫助12306減少很多帶寬占用澜薄,于是負載一下就到了后端,后端的數(shù)據(jù)處理瓶頸一下就出來摊册。于是你會看到很多http 500之類的錯誤肤京。這說明后端服務器垮了。
四茅特、前端頁面靜態(tài)化
靜態(tài)化一些不常變的頁面和數(shù)據(jù)忘分,并gzip一下。還有一個變態(tài)的方法是把這些靜態(tài)頁面放在/dev/shm下温治,這個目錄就是內存饭庞,直接從內存中把文件讀出來返回戒悠,這樣可以減少昂貴的磁盤I/O熬荆。使用nginx的sendfile功能可以讓這些靜態(tài)文件直接在內核心態(tài)交換,可以極大增加性能绸狐。
五卤恳、優(yōu)化查詢
很多人查詢都是在查一樣的,完全可以用反向代理合并這些并發(fā)的相同的查詢寒矿。這樣的技術主要用查詢結果緩存來實現(xiàn)突琳,第一次查詢走數(shù)據(jù)庫獲得數(shù)據(jù),并把數(shù)據(jù)放到緩存符相,后面的查詢統(tǒng)統(tǒng)直接訪問高速緩存拆融。為每個查詢做Hash,使用NoSQL的技術可以完成這個優(yōu)化啊终。(這個技術也可以用做靜態(tài)頁面)
對于火車票量的查詢镜豹,個人覺得不要顯示數(shù)字,就顯示一個“有”或“無”就好了蓝牲,這樣可以大大簡化系統(tǒng)復雜度趟脂,并提升性能。把查詢對數(shù)據(jù)庫的負載分出去例衍,從而讓數(shù)據(jù)庫可以更好地為下單的人服務昔期。
六、緩存的問題
緩存可以用來緩存動態(tài)頁面佛玄,也可以用來緩存查詢的數(shù)據(jù)硼一。緩存通常有那么幾個問題:
1)緩存的更新。也叫緩存和數(shù)據(jù)庫的同步梦抢。有這么幾種方法般贼,一是緩存time out,讓緩存失效,重查具伍,二是翅雏,由后端通知更新,一量后端發(fā)生變化人芽,通知前端更新望几。前者實現(xiàn)起來比較簡單,但實時性不高萤厅,后者實現(xiàn)起來比較復雜 橄抹,但實時性高。
2)緩存的換頁惕味。內存可能不夠楼誓,所以,需要把一些不活躍的數(shù)據(jù)換出內存名挥,這個和操作系統(tǒng)的內存換頁和交換內存很相似疟羹。FIFO、LRU禀倔、LFU都是比較經典的換頁算法榄融。相關內容參看Wikipeida的緩存算法。
3)緩存的重建和持久化救湖。緩存在內存愧杯,系統(tǒng)總要維護,所以鞋既,緩存就會丟失力九,如果緩存沒了,就需要重建邑闺,如果數(shù)據(jù)量很大跌前,緩存重建的過程會很慢,這會影響生產環(huán)境检吆,所以舒萎,緩存的持久化也是需要考慮的。
諸多強大的NoSQL都很好支持了上述三大緩存的問題蹭沛。
后端性能優(yōu)化技術
前面討論了前端性能的優(yōu)化技術臂寝,于是前端可能就不是瓶頸問題了。那么性能問題就會到后端數(shù)據(jù)上來了摊灭。下面說幾個后端常見的性能優(yōu)化技術咆贬。
一、數(shù)據(jù)冗余
關于數(shù)據(jù)冗余帚呼,也就是說掏缎,把我們的數(shù)據(jù)庫的數(shù)據(jù)冗余處理皱蹦,也就是減少表連接這樣的開銷比較大的操作,但這樣會犧牲數(shù)據(jù)的一致性眷蜈。風險比較大沪哺。很多人把NoSQL用做數(shù)據(jù),快是快了酌儒,因為數(shù)據(jù)冗余了辜妓,但這對數(shù)據(jù)一致性有大的風險。這需要根據(jù)不同的業(yè)務進行分析和處理忌怎。(注意:用關系型數(shù)據(jù)庫很容易移植到NoSQL上籍滴,但是反過來從NoSQL到關系型就難了)
二、數(shù)據(jù)鏡像
幾乎所有主流的數(shù)據(jù)庫都支持鏡像榴啸,也就是replication孽惰。數(shù)據(jù)庫的鏡像帶來的好處就是可以做負載均衡。把一臺數(shù)據(jù)庫的負載均分到多臺上鸥印,同時又保證了數(shù)據(jù)一致性(Oracle的SCN)勋功。最重要的是,這樣還可以有高可用性辅甥,一臺廢了酝润,還有另一臺在服務燎竖。
數(shù)據(jù)鏡像的數(shù)據(jù)一致性可能是個復雜的問題璃弄,所以我們要在單條數(shù)據(jù)上進行數(shù)據(jù)分區(qū),也就是說构回,把一個暢銷商品的庫存均分到不同的服務器上夏块,如,一個暢銷商品有1萬的庫存纤掸,我們可以設置10臺服務器脐供,每臺服務器上有1000個庫存,這就好像B2C的倉庫一樣借跪。
三政己、數(shù)據(jù)分區(qū)
數(shù)據(jù)鏡像不能解決的一個問題就是數(shù)據(jù)表里的記錄太多,導致數(shù)據(jù)庫操作太慢掏愁。所以歇由,把數(shù)據(jù)分區(qū)。數(shù)據(jù)分區(qū)有很多種做法果港,一般來說有下面這幾種:
1)把數(shù)據(jù)把某種邏輯來分類沦泌。比如火車票的訂票系統(tǒng)可以按各鐵路局來分,可按各種車型分辛掠,可以按始發(fā)站分谢谦,可以按目的地分……释牺,反正就是把一張表拆成多張有一樣的字段但是不同種類的表,這樣回挽,這些表就可以存在不同的機器上以達到分擔負載的目的没咙。
2)把數(shù)據(jù)按字段分,也就是豎著分表千劈。比如把一些不經常改的數(shù)據(jù)放在一個表里镜撩,經常改的數(shù)據(jù)放在另外多個表里。把一張表變成1對1的關系队塘,這樣袁梗,你可以減少表的字段個數(shù),同樣可以提升一定的性能憔古。另外遮怜,字段多會造成一條記錄的存儲會被放到不同的頁表里,這對于讀寫性能都有問題鸿市。但這樣一來會有很多復雜的控制锯梁。
3)平均分表。因為第一種方法是并不一定平均分均焰情,可能某個種類的數(shù)據(jù)還是很多陌凳。所以,也有采用平均分配的方式内舟,通過主鍵ID的范圍來分表合敦。
4)同一數(shù)據(jù)分區(qū)。這個在上面數(shù)據(jù)鏡像提過验游。也就是把同一商品的庫存值分到不同的服務器上充岛,比如有10000個庫存,可以分到10臺服務器上耕蝉,一臺上有1000個庫存崔梗。然后負載均衡。
這三種分區(qū)都有好有壞垒在。最常用的還是第一種蒜魄。數(shù)據(jù)一旦分區(qū),你就需要有一個或是多個調度來讓你的前端程序知道去哪里找數(shù)據(jù)场躯。把火車票的數(shù)據(jù)分區(qū)谈为,并放在各個省市,會對12306這個系統(tǒng)有非常有意義的質的性能的提高推盛。
四峦阁、后端系統(tǒng)負載均衡
前面說了數(shù)據(jù)分區(qū),數(shù)據(jù)分區(qū)可以在一定程度上減輕負載耘成,但是無法減輕熱銷商品的負載榔昔,對于火車票來說驹闰,可以認為是大城市的某些主干線上的車票。這就需要使用數(shù)據(jù)鏡像來減輕負載撒会。使用數(shù)據(jù)鏡像嘹朗,你必然要使用負載均衡,在后端诵肛,我們可能很難使用像路由器上的負載均衡器屹培,因為那是均衡流量的,因為流量并不代表服務器的繁忙程度怔檩。因此褪秀,我們需要一個任務分配系統(tǒng),其還能監(jiān)控各個服務器的負載情況薛训。
任務分配服務器有一些難點:
負載情況比較復雜媒吗。什么叫忙?是CPU高乙埃?還是磁盤I/O高闸英?還是內存使用高?還是并發(fā)高介袜?還是內存換頁率高甫何?你可能需要全部都要考慮。這些信息要發(fā)送給那個任務分配器上遇伞,由任務分配器挑選一臺負載最輕的服務器來處理辙喂。
任務分配服務器上需要對任務隊列,不能丟任務啊赃额,所以還需要持久化加派。并且可以以批量的方式把任務分配給計算服務器。
任務分配服務器死了怎么辦跳芳?這里需要一些如Live-Standby或是failover等高可用性的技術。我們還需要注意那些持久化了的任務的隊列如何轉移到別的服務器上的問題竹勉。
我看到有很多系統(tǒng)都用靜態(tài)的方式來分配飞盆,有的用hash,有的就簡單地輪流分析次乓。這些都不夠好吓歇,一個是不能完美地負載均衡,另一個靜態(tài)的方法的致命缺陷是票腰,如果有一臺計算服務器死機了城看,或是我們需要加入新的服務器,對于我們的分配器來說杏慰,都需要知道的测柠。另外炼鞠,還要重算哈希(一致性hash可以部分解決這個問題)。
還有一種方法是使用搶占式的方式進行負載均衡轰胁,由下游的計算服務器去任務服務器上拿任務谒主。讓這些計算服務器自己決定自己是否要任務。這樣的好處是可以簡化系統(tǒng)的復雜度赃阀,而且還可以任意實時地減少或增加計算服務器霎肯。但是唯一不好的就是,如果有一些任務只能在某種服務器上處理榛斯,這可能會引入一些復雜度观游。不過總體來說,這種方法可能是比較好的負載均衡驮俗。
五备典、異步、 throttle 和 批量處理
異步意述、throttle(節(jié)流閥) 和批量處理都需要對并發(fā)請求數(shù)做隊列處理的提佣。
異步在業(yè)務上一般來說就是收集請求,然后延時處理荤崇。在技術上就是可以把各個處理程序做成并行的拌屏,也就可以水平擴展了。但是異步的技術問題大概有這些术荤,a)被調用方的結果返回倚喂,會涉及進程線程間通信的問題。b)如果程序需要回滾瓣戚,回滾會有點復雜端圈。c)異步通常都會伴隨多線程多進程,并發(fā)的控制也相對麻煩一些子库。d)很多異步系統(tǒng)都用消息機制舱权,消息的丟失和亂序也會是比較復雜的問題。
throttle 技術其實并不提升性能仑嗅,這個技術主要是防止系統(tǒng)被超過自己不能處理的流量給搞垮了宴倍,這其實是個保護機制。使用throttle技術一般來說是對于一些自己無法控制的系統(tǒng)仓技,比如鸵贬,和你網站對接的銀行系統(tǒng)。
批量處理的技術脖捻,是把一堆基本相同的請求批量處理阔逼。比如,大家同時購買同一個商品地沮,沒有必要你買一個我就寫一次數(shù)據(jù)庫嗜浮,完全可以收集到一定數(shù)量的請求羡亩,一次操作。這個技術可以用作很多方面周伦。比如節(jié)省網絡帶寬夕春,我們都知道網絡上的MTU(最大傳輸單元),以態(tài)網是1500字節(jié)专挪,光纖可以達到4000多個字節(jié)及志,如果你的一個網絡包沒有放滿這個MTU,那就是在浪費網絡帶寬寨腔,因為網卡的驅動程序只有一塊一塊地讀效率才會高速侈。因此,網絡發(fā)包時迫卢,我們需要收集到足夠多的信息后再做網絡I/O倚搬,這也是一種批量處理的方式。批量處理的敵人是流量低乾蛤,所以每界,批量處理的系統(tǒng)一般都會設置上兩個閥值,一個是作業(yè)量家卖,另一個是timeout眨层,只要有一個條件滿足,就會開始提交處理上荡。
所以趴樱,只要是異步,一般都會有throttle機制酪捡,一般都會有隊列來排隊叁征,有隊列,就會有持久化逛薇,而系統(tǒng)一般都會使用批量的方式來處理捺疼。
云風同學設計的“排隊系統(tǒng)”就是這個技術。這和電子商務的訂單系統(tǒng)很相似金刁,就是說帅涂,我的系統(tǒng)收到了你的購票下單請求,但是我還沒有真正處理尤蛮,我的系統(tǒng)會跟據(jù)我自己的處理能力來throttle住這些大量的請求,并一點一點地處理斯议。一旦處理完成产捞,我就可以發(fā)郵件或短信告訴用戶你來可以真正購票了。
在這里哼御,我想通過業(yè)務和用戶需求方面討論一下云風同學的這個排隊系統(tǒng)坯临,因為其從技術上看似解決了這個問題焊唬,但是從業(yè)務和用戶需求上來說可能還是有一些值得我們去深入思考的地方:
1)隊列的DoS攻擊。首先看靠,我們思考一下赶促,這個隊是個單純地排隊的嗎?這樣做還不夠好挟炬,因為這樣我們不能杜絕黃牛鸥滨,而且單純的ticket_id很容易發(fā)生DoS攻擊,比如谤祖,我發(fā)起N個 ticket_id婿滓,進入購票流程后,我不買粥喜,我就耗你半個小時凸主,很容易我就可以讓想買票的人幾天都買不到票。有人說额湘,用戶應該要用身份證來排隊卿吐, 這樣在購買里就必需要用這個身份證來買,但這也還不能杜絕黃牛排隊或是號販子锋华。因為他們可以注冊N個帳號來排隊嗡官,但就是不買。黃牛這些人這個時候只需要干一個事供置,把網站搞得正常人不能訪問谨湘,讓用戶只能通過他們來買。
2)對列的一致性芥丧?對這個隊列的操作是不是需要鎖紧阔?只要有鎖,性能一定上不去续担。試想擅耽,100萬個人同時要求你來分配位置號,這個隊列將會成為性能瓶頸物遇。你一定沒有數(shù)據(jù)庫實現(xiàn)得性能好乖仇,所以,可能比現(xiàn)在還差询兴。搶數(shù)據(jù)庫和搶隊列本質上是一樣的乃沙。
3)隊列的等待時間。購票時間半小時夠不夠诗舰?多不多警儒?要是那時用戶正好不能上網呢?如果時間短了,用戶不夠時間操作也會抱怨蜀铲,如果時間長了边琉,后面在排隊的那些人也會抱怨。這個方法可能在實際操作上會有很多問題记劝。另外变姨,半個小時太長了,這完全不現(xiàn)實厌丑,我們用15分鐘來舉例:有1千萬用戶定欧,每一個時刻只能放進去1萬個,這1萬個用戶需要15分鐘完成所有操作蹄衷,那么忧额,這1千萬用戶全部處理完,需要1000*15m = 250小時愧口,10天半睦番,火車早開了。(我并非信口開河耍属,根據(jù)鐵道部專家的說明:這幾天托嚣,平均一天下單100萬,所以厚骗,處理1000萬的用戶需要十天合搅。這個計算可能有點簡單了居扒,我只是想說庶香,在這樣低負載的系統(tǒng)下用排隊可能都不能解決業(yè)務問題)
4)隊列的分布式桐玻。這個排隊系統(tǒng)只有一個隊列好嗎?還不足夠好冲秽。因為舍咖,如果你放進去的可以購票的人如果在買同一個車次的同樣的類型的票(比如某動車臥鋪),還是等于在搶票锉桑,也就是說系統(tǒng)的負載還是會有可能集中到其中某臺服務器上排霉。因此,最好的方法是根據(jù)用戶的需求——提供出發(fā)地和目的地民轴,來對用戶進行排隊攻柠。而這樣一來,隊列也就可以是多個后裸,只要是多個隊列瑰钮,就可以水平擴展了。這樣可以解決性能問題微驶,但是沒有解決用戶長時間排隊的問題飞涂。
我覺得完全可以向網上購物學習。在排隊(下單)的時候祈搜,收集好用戶的信息和想要買的票较店,并允許用戶設置購票的優(yōu)先級,比如容燕,A車次臥鋪買 不到就買 B車次的臥鋪梁呈,如果還買不到就買硬座等等,然后用戶把所需的錢先充值好蘸秘,接下來就是系統(tǒng)完全自動地異步處理訂單官卡。成功不成功都發(fā)短信或郵件通知用戶。這樣醋虏,系統(tǒng)不僅可以省去那半個小時的用戶交互時間寻咒,自動化加快處理,還可以合并相同購票請求的人颈嚼,進行批處理(減少數(shù)據(jù)庫的操作次數(shù))毛秘。這種方法最妙的事是可以知道這些排隊用戶的需求,不但可以優(yōu)化用戶的隊列阻课,把用戶分布到不同的隊列叫挟,還可以像亞馬遜的心愿單一樣,通過一些計算就可以讓鐵道部做車次統(tǒng)籌安排和調整(最后限煞,排隊系統(tǒng)(下單系統(tǒng))還是要保存在數(shù)據(jù)庫里的或做持久化抹恳,不能只放在內存中,不然機器一down署驻,就等著被罵吧)奋献。
小結
寫了那么多,我小結一下:
0)無論你怎么設計旺上,你的系統(tǒng)一定要能容易地水平擴展瓶蚂。也就是說,你的整個數(shù)據(jù)流中抚官,所有的環(huán)節(jié)都要能夠水平擴展扬跋。這樣,當你的系統(tǒng)有性能問題時凌节,“加30倍的服務器”才不會被人譏笑钦听。
1)上述的技術不是一朝一夕能搞定的,沒有長期的積累倍奢,基本無望朴上。我們可以看到,無論你用哪種都會引發(fā)一些復雜性卒煞,設計總是在做一種權衡痪宰。
2)集中式的賣票很難搞定,使用上述的技術可以讓訂票系統(tǒng)能有幾佰倍的性能提升。而在各個省市建分站衣撬,分開賣票乖订,是能讓現(xiàn)有系統(tǒng)性能有質的提升的最好方法。
3)春運前夕搶票且票量供遠小于求這種業(yè)務模式是相當變態(tài)的具练,讓幾千萬甚至上億的人在某個早晨的8點鐘同時登錄同時搶票的這種業(yè)務模式是變態(tài)中的變態(tài)乍构。業(yè)務形態(tài)的變態(tài)決定了無論他們怎么辦干一定會被罵。
4)為了那么一兩個星期而搞那么大的系統(tǒng)扛点,而其它時間都在閑著哥遮,有些可惜了,這也就是鐵路才干得出來這樣的事了陵究。
更新2012年9月27日