鐵路訂票系統(tǒng)的簡(jiǎn)單設(shè)計(jì)2012-01-15 13:18 | 3384次閱讀 | 來(lái)源:云風(fēng)博客 【已有27條評(píng)論】發(fā)表評(píng)論 關(guān)鍵詞:訂票系統(tǒng) | 作者:云風(fēng) | 收藏這篇資訊 其實(shí)鐵路訂票系統(tǒng)面臨的技術(shù)難點(diǎn)無(wú)非就是春運(yùn)期間可能發(fā)生的海量并發(fā)業(yè)務(wù)請(qǐng)求。這個(gè)加上一個(gè)排隊(duì)系統(tǒng)就可以輕易解決的。 本來(lái)我在weibo上閑扯兩句,這么簡(jiǎn)單的方案,本以為大家一看就明白的。沒(méi)想到還是許多人有疑問(wèn)。好吧,寫(xiě)篇 blog 來(lái)解釋一下。 簡(jiǎn)單說(shuō),我們?cè)O(shè)置幾個(gè)網(wǎng)關(guān)服務(wù)器,用動(dòng)態(tài) DNS 的方式,把并發(fā)的訂票請(qǐng)求分?jǐn)傞_(kāi)。類(lèi)比現(xiàn)實(shí)的話,就是把人分流到不同的購(gòu)票大廳去。每個(gè)購(gòu)票大廳都可以買(mǎi)到所有車(chē)次的票。OK ,這一步的負(fù)載均衡怎么做我就不詳細(xì)說(shuō)了。 每個(gè)網(wǎng)關(guān)其實(shí)最重要的作用就是讓訂票的用戶排隊(duì)。其實(shí)整個(gè)系統(tǒng)也只用做排隊(duì),關(guān)于實(shí)際訂票怎么操作,就算每個(gè)網(wǎng)關(guān)后坐一排售票員,在屏幕上看到有人來(lái)買(mǎi)票,輸入到內(nèi)部訂票系統(tǒng)中出票,然后再把票號(hào)敲回去,這個(gè)系統(tǒng)都能無(wú)壓力的正常工作。否則,以前春運(yùn)是怎么把票賣(mài)出去的? 我們來(lái)說(shuō)說(shuō)排隊(duì)系統(tǒng)是怎么做的: 其實(shí)就類(lèi)似我們?nèi)衢T(mén)館子吃飯拿號(hào)。只不過(guò)要防止別人偽造號(hào)插隊(duì)而已。 如果你來(lái)一個(gè)人(一次 HTTP 請(qǐng)求),我就隨機(jī)產(chǎn)生一個(gè)我做過(guò)一些簽名處理的號(hào)碼返回給你。暫時(shí)稱(chēng)為 ticket id 。這個(gè) ticked id 是很難偽造的。 系統(tǒng)在內(nèi)存里開(kāi)一個(gè)大數(shù)組(32G 內(nèi)存夠排上億人了吧),就是一循環(huán)隊(duì)列。把這個(gè) ticket id 放在隊(duì)列尾。 用戶現(xiàn)在拿著 ticket id 向網(wǎng)關(guān)發(fā)起請(qǐng)求。網(wǎng)關(guān)利用一次 hash 查詢,在內(nèi)存中的數(shù)組隊(duì)列里查到它的位置,立刻返回給用戶。用戶的前端就可以看到,他在這個(gè)網(wǎng)關(guān)(售票大廳)前面還有多少人等著。 這里的關(guān)鍵是,整個(gè)隊(duì)列都在本機(jī)的內(nèi)存中,查詢返回隊(duì)列中的位置,可以實(shí)現(xiàn)的比一個(gè)處理靜態(tài)文件的 web server 還要高效。靜態(tài)文件至少還要去調(diào)用文件 IO 呢。靜態(tài)文件 web server 可以處理多少并發(fā)量,不用我介紹了。 同時(shí),前端會(huì)控制用戶拿著 ticket id 查詢隊(duì)列位置的頻率。高負(fù)載時(shí)可以 1s 一次,甚至更長(zhǎng)時(shí)間。為了防止用戶自己寫(xiě)腳本刷這個(gè)請(qǐng)求(雖然沒(méi)有太大意義,因?yàn)樗⒌亩嘁膊粫?huì)排到前面去),如果見(jiàn)到同一個(gè) ticket id 過(guò)于頻繁的查詢。比如 10s 內(nèi)查詢了 20 次以上。就直接把這個(gè) ticket id 作廢。持有這個(gè) ticket 的人就需要重新排隊(duì)了。 對(duì)于最后排到的人,系統(tǒng)會(huì)生成一個(gè)唯一的不可偽造的 session id ,用戶下面就可以通過(guò)這個(gè) session id 去做實(shí)際的購(gòu)票流程了。可以連去真正的購(gòu)票服務(wù)器,也可以通過(guò)網(wǎng)關(guān)中轉(zhuǎn)。非法的 session id 會(huì)立刻斷掉,用戶一旦知道偽造 session id 幾乎不可能,只有通過(guò) ticket id 排隊(duì)拿到,除非是惡意攻擊系統(tǒng),不然不會(huì)有人亂拿 session id 去試。 我們?cè)俳o每個(gè) session id 設(shè)置一個(gè)最長(zhǎng)有效時(shí)間,比如半小時(shí)。如果超過(guò)半小時(shí)還沒(méi)有完整購(gòu)票流程,那么就重新去排隊(duì)。 至于同時(shí)開(kāi)放多少個(gè) session id ,也就是相當(dāng)于開(kāi)放多少個(gè)購(gòu)票窗口,就取決于購(gòu)票系統(tǒng)能承受的負(fù)載了。不過(guò)簡(jiǎn)單計(jì)算一下,就知道有排隊(duì)系統(tǒng)保證了良好的次序,再以計(jì)算機(jī)的吞吐能力,解決 不過(guò)幾億人的購(gòu)票請(qǐng)求,即使這些人都同來(lái)排隊(duì),也就是一組機(jī)器幾小時(shí)的處理量而已。 這票 blog 也就是隨便寫(xiě)寫(xiě),可能不太嚴(yán)謹(jǐn),但意思達(dá)到了。中間有很多數(shù)據(jù)需要估算,也不是太難的事情。 為什么現(xiàn)在的購(gòu)票系統(tǒng)這么濫?關(guān)鍵在于大量的網(wǎng)絡(luò)帶寬,計(jì)算力浪費(fèi)在了“維持次序”上。系統(tǒng)不穩(wěn)定時(shí),大量的只做了一半的無(wú)效的購(gòu)票流程浪費(fèi)掉了這 些。要響應(yīng)高并發(fā)的 HTTP 請(qǐng)求,關(guān)鍵就在于迅速反應(yīng),不要什么都想著從數(shù)據(jù)庫(kù)繞一圈。排隊(duì)的隊(duì)伍維持就完全不需要使用數(shù)據(jù)庫(kù)。如果所有 HTTP 請(qǐng)求都立刻返回,在短時(shí)間內(nèi)可以處理的 HTTP 請(qǐng)求量也會(huì)非常大。而如果你一下處理不了這個(gè)請(qǐng)求,又把 TCP 連接保持在那里,就莫怪系統(tǒng)支持不住了。 另外,用戶看到了不斷在減少的隊(duì)列前面的人數(shù),他們也會(huì)安心等待。只要網(wǎng)站頁(yè)面刷新流暢(只處理隊(duì)列信息很容易保證),用戶體驗(yàn)會(huì)很好。 最后補(bǔ)充幾句廢話:因?yàn)殍F路購(gòu)票系統(tǒng)很多年前就實(shí)現(xiàn)了內(nèi)部網(wǎng)絡(luò)化,有成熟系統(tǒng)支撐,運(yùn)作多年。這次做互聯(lián)網(wǎng)版本,一定不能放棄原有系統(tǒng)新來(lái)一套。不然實(shí)體購(gòu)票點(diǎn)也在網(wǎng)頁(yè)上刷不出票就崩潰了。 所以要做的僅僅是怎么做一個(gè)系統(tǒng)和原有系統(tǒng)對(duì)接。這樣風(fēng)險(xiǎn)最小。兩套系統(tǒng)可以分別優(yōu)化處理能力?;谶@個(gè)設(shè)計(jì)起點(diǎn),所以我才不看好所有企圖取代原有系統(tǒng)的方案。 本文來(lái)自:云風(fēng)的博客 |
|
|