新聞中心
在上一篇文章中 鐵道部信客票系統(tǒng)設(shè)計(一) 里面,探討了關(guān)于數(shù)據(jù)庫層面的功能性需求以及非功能性的需求,在非功能性需求里面,一博主 提出了沒有考慮到峰值的情況,這一點的確漏掉了,因為我們鐵道部的特殊需求,在春運期間負載很大,平時可能一般,如果用考慮***的情況,則回存在浪費的情況,如果考慮不足,就像網(wǎng)絡(luò)訂票一樣,苦逼。就好比 鐵道部春運的時候,發(fā)車量大,但是如果制造大量列車,平時就空閑了,也就很虧。機器的折舊很是塊的。春運期間可以考慮緊急擴容來實現(xiàn),所以從設(shè)計上可以保持這種擴展性。 擴容是一項工程,整體來說比較復(fù)雜。

創(chuàng)新互聯(lián)公司專注于網(wǎng)站建設(shè)|成都網(wǎng)站改版|優(yōu)化|托管以及網(wǎng)絡(luò)推廣,積累了大量的網(wǎng)站設(shè)計與制作經(jīng)驗,為許多企業(yè)提供了網(wǎng)站定制設(shè)計服務(wù),案例作品覆蓋成都PVC花箱等行業(yè)。能根據(jù)企業(yè)所處的行業(yè)與銷售的產(chǎn)品,結(jié)合品牌形象的塑造,量身制作品質(zhì)網(wǎng)站。
上一篇博客發(fā)表后,也有博主和我探討過一些問題,也讓我了解到鐵道部目前的狀態(tài)。由于這個純粹是技術(shù)上的分析,先不去考慮一些政治因素,畢竟這個比技術(shù)復(fù)雜多了
正題開始,原來打算這一篇里面介紹數(shù)據(jù)庫表的設(shè)計,但是上一篇文章中還有很多細節(jié)問題,沒有解決,這里面繼續(xù)上一張,把數(shù)據(jù)這一層在慢慢完善
購票的業(yè)務(wù)流程
由于購票過程中是鐵道部售票系統(tǒng)的主要功能也是核心業(yè)務(wù)邏輯,這里先從購票的業(yè)務(wù)流程開始,討論購票業(yè)務(wù)流程中相關(guān)的數(shù)據(jù)庫設(shè)計
簡單的購票流程
終端-->查詢余票-->選擇車次-->確認座位-->選擇張數(shù)-->支付-->出票
這里面重要的是兩個環(huán)節(jié) 查詢余票 和 支付過程
我們先模擬以下正常網(wǎng)絡(luò)購票過程中數(shù)據(jù)庫的操作,這里面先把問題簡單化,假設(shè)用戶只買始發(fā)站到終點站的數(shù)據(jù)
- select * from 余票
- insert into 車票
- update 余票 -1
- update 車票 set status='WAIT_PAY' where id = xxx
- update 車票 set status='PAY' where id = xxx
電話訂票類似,只不過訂的票不會由于過期而取消,要么支付,要么退票
而在窗口、代售點買的票,支付方式只不過是現(xiàn)金,出票的時候自動支付。
其實無論從那個終端過來的請求,都會涉及到查詢余票,創(chuàng)建車票,支付車票 過程,考慮一中簡單的情況,就是用戶只查詢一次,就選擇了自己要確定的車次,然后購票,去支付。那么一次購票請求,會至少 一次余票查詢 一次余票更新,一次車票insert,兩次車票update,這個還是最少的情況,實際鐵道部的業(yè)務(wù)應(yīng)該比這個復(fù)雜多了。由于查詢余票是購票請求的入口,所有的購票請求都會優(yōu)先查詢余票庫
余票庫的設(shè)計
在***篇文章中,余票庫沒有設(shè)計成為讀寫分離,主要是考慮的用戶一定獲取的是最實時信息,讀寫分離的話,讀庫和寫庫的數(shù)據(jù)有效性上面會有差異,比如我更新了一個數(shù)據(jù),必須馬上反映到余票上,否則用戶看到一個過期的數(shù)據(jù),對用戶體驗很不好。這個庫的訪問量超級大,而且還會涉及到熱點數(shù)據(jù)的鎖定,一旦同一條數(shù)據(jù)(比如我這次想買Z27硬臥)同時被大量用戶請求,根據(jù)上面分析的,出票就要鎖定余票表中Z27這一條記錄,由于一次只允許一條用戶請求能夠獲得鎖,請求要必須盡快的處理,除了必要的原子操作,比如票數(shù)-1,產(chǎn)生購票表,其他的耗時操作就應(yīng)該越少越好,盡量異步化操作,核心思想就是盡快的釋放鎖,否則請求排隊的線程越來越多,導(dǎo)致數(shù)據(jù)庫所有數(shù)據(jù)庫的連接資源被耗盡,系統(tǒng)會變的很慢。
整理以下:在設(shè)計余票庫的時候,在性能上提升,可以從下面幾個方面去考慮
1 盡量減少沒有必要的查詢,減少數(shù)據(jù)庫的資源消耗
2 鎖的粒度越小越好
3 訂票事務(wù)處理越短越好,消耗的業(yè)務(wù)邏輯處理越快越好,爭取***的異步處理。
接下來就是考慮如何通過上述思想,找出具體的設(shè)計方案
1 減少對數(shù)據(jù)庫的查詢
一般情況下,先會查詢某日余票信息,接下來就是根據(jù)查詢出來的信息,選擇車次,席位。然后張數(shù),然后訂票成功。
首先,假設(shè)我們把余票信息緩存,應(yīng)用先查詢緩存,如果有票,用戶選擇車次和席位,這樣會減少一次數(shù)據(jù)庫的查詢。
緩存有兩種方式,一種是應(yīng)用局部緩存,每個渠道緩存票務(wù)數(shù)據(jù),這里涉及到數(shù)據(jù)的更新以及各個緩存之間的同步,不及時,暫時不考慮。
另外一個種是分布式緩存,建立緩存服務(wù)器(這里面說的緩存都是指內(nèi)存緩存),數(shù)據(jù)庫只需要和緩存服務(wù)器之間保持同步,但是這樣一來,如果會員想獲取***的數(shù)據(jù),緩存服務(wù)器也需要保持很頻繁的更新,相當于要保持緩存和余票數(shù)據(jù)的同步。這個成本也是非常高。還有一個折中方案,就是緩存不緩存票數(shù),而是緩存有票無票信息,每次用戶查詢票數(shù)的時候,先查緩存信息,看看是否有票,如果有票,就查詢數(shù)據(jù)查詢具體的票數(shù),如果無票,就不需要進行查詢了,這樣減少了數(shù)據(jù)庫的查詢。同時緩存的更新也少了很多,只需要在票數(shù)等于0的時候,更新以下緩存數(shù)據(jù)。假設(shè)票在一分鐘之內(nèi)賣掉,相當于只需要承受一分鐘的查詢請求。
當緩存替代數(shù)據(jù)庫作為主要查詢請求處理者的時候,緩存成為整個系統(tǒng)的瓶頸。
2 減少鎖的粒度
當旅客選擇一張票的時候,我需要鎖定一條記錄,避免同時更新,造成重復(fù)出票(這里說以下,我記得大學(xué)的時候,我從武漢買回家的票,鐵道部一個座位賣出三張票,而且是大面積情況,相當于一個車廂人數(shù)比平時多了三倍,當初我以為是假票,現(xiàn)在看來,可能是重復(fù)出票了)。還是拿Z27距離,假設(shè)我要買20120931日期票,我必須要選擇一個座位,那么設(shè)計的時候,就可以 按照日期,車次,席位類型 三者確定一條記錄,然后鎖定它。而不是值根據(jù)車次 + 日期,這樣在你買坐票的時候,買臥鋪的旅客就不會受到影響。(PS:實際鐵道部售票會遠遠這個模型簡單,因為涉及到始發(fā)站,??空?,終點到,假設(shè)一個車次???S1->S2-S3,那么旅客買S1->S2 和 旅客買S2->S3 就不會收到影響,我們先簡化模型,這里只是先提出設(shè)計的思想)
3 減少訂票處理事務(wù)時間
在整個訂票業(yè)務(wù)流程中,發(fā)郵件,發(fā)短信,計算各個站點的余票信息等比較等耗時業(yè)務(wù)操作,完全異步化處理。只需要找出關(guān)鍵的流程,如果需要保持一個事務(wù),那么通過異步確保的方式進行。這個是技術(shù)層面的東西,后面在介紹。
存在的問題
通過分析,我們給出了一個最簡單的訂票數(shù)據(jù)庫這一層的解決方案,再仔細分析其中存在的問題
1 余票查詢的維度并不是 車次 + 日期 + 席位類型,應(yīng)該還有始發(fā)站-->終點站因素,必須有一個非常快的算法,判斷是否有票,然后告知應(yīng)用。
2 緩存是系統(tǒng)中的單點,一旦緩存故障,數(shù)據(jù)庫估計承受不了
3 數(shù)據(jù)庫上次我說的只需要分成一個庫(因為上一章節(jié)建立數(shù)據(jù)庫備份機制,故這里面不存在單點),這里面可能存在性能,這里需要進行壓力測試,模擬測試??纯慈萘可暇€。為了繼續(xù)進行設(shè)計,我們假設(shè)即使在緩存存在的情況,數(shù)據(jù)庫沒有辦法處理當前的數(shù)據(jù),主要是為了應(yīng)付春運。
這里先解決余票庫分庫的問題,分庫考慮的原則在上一篇文章分析過,但是由于這個庫的數(shù)據(jù)量不大,只是訪問會比較頻繁,我們竟可能減少用戶的訪問為主要考慮因素,鐵路購票有其特殊的因素,比如春節(jié)的時候從上海買去成都的票非常緊張,查詢量也是***,但是相反,這段期間買成都去上海的票的人就會比較少,查詢量比較少。而春節(jié)過后上班也就相反。這個思路也就是說按照站站來分,也可以按照鐵路局賣的票來分。我們的思路就是盡量各個庫的訪問量均勻。不過也存在一個問題,就是分庫的擴展性比較差,一旦擴容,就要做改動。
在談緩存的問題,一臺緩存服務(wù)器不夠,可以部署緩存集群。至于是不是一臺緩存服務(wù)器存放所有的數(shù)據(jù),還是要看數(shù)據(jù)的多少,盡可能的所有數(shù)據(jù)都緩存在一臺服務(wù)器上面。緩存的數(shù)據(jù)維度為 預(yù)售期、車次 、席位、始發(fā)站、終點站 、是否有票 ,按照道理,應(yīng)該可以緩存所有的數(shù)據(jù),不過這個也要看緩存的實現(xiàn)支持***的內(nèi)存數(shù)量。比如java實現(xiàn)的緩存 在32位機器上面 只能支持差不多2G的緩存空間。這里面假設(shè)一臺緩存服務(wù)器能夠?qū)崿F(xiàn)所有預(yù)售期車票數(shù)據(jù)的緩存,那么這里面只需要的就是在余票數(shù)據(jù)更新的時候更新所有集群的緩存數(shù)據(jù)。
而余票的計算則是里面最為復(fù)雜的了,因為新增了兩個維度,就是始發(fā)站->到達站。這個問題比較復(fù)雜,先暫時放到下一篇文章區(qū)分析。
繼續(xù)分析,發(fā)現(xiàn)上面的分析中,貌似還少了一個比較重要的因素,那就是渠道因素,我們知道,訂票有窗口渠道,代理售票口,網(wǎng)站,電話等等。假如每個渠道售出的票都是公平的,那么肯定不合乎道理的,那互聯(lián)網(wǎng)可能就是比較占優(yōu)勢的(如果系統(tǒng)設(shè)計的足夠好的話),對于辛苦排隊的人來說,相當不公平。這里面有兩種解決方案
1 可以設(shè)計為每個渠道進行配額,比如網(wǎng)絡(luò)訂票 ,我給總票數(shù)的多少,每個代理點,我給的票數(shù)是多少等等。如果把這些因素在加入到余票信息中,會變的非常復(fù)雜,也不好擴展,畢竟這個是屬于經(jīng)常變化的。設(shè)計的一個原則分離不變和易變。如果不變的和易變?nèi)岷驮谝黄穑到y(tǒng)的擴展性就回很弱。
2 可以按照請求排隊,按照渠道優(yōu)先級進行分配,這樣在大多數(shù)請求排隊的情況下,有一些請求就回被餓死,也就是部分渠道根本買不到票,因為請求會被餓死。
如果要我選擇兩種方案的,我會選擇***種,因為可以在不同時刻進行放票,這樣可以分散請求。來自互聯(lián)網(wǎng)10點放票,窗口的8點放票,代理點9點。自然把流量就分開了。渠道配額管理這一塊我覺得將會是最復(fù)雜的一個系統(tǒng),涉及到利益太多。余票庫這里面我想設(shè)計的簡單一點,不想把復(fù)雜的渠道,配額管理引入進來,盡量放在外圍系統(tǒng)中控制。
今天先寫到這里,發(fā)現(xiàn)在這上面思考的比較多了,后面再持續(xù)分析吧。還要繼續(xù)開發(fā)我的ios app,寫文章有點超時了。
原文鏈接:http://www.cnblogs.com/aigongsi/archive/2012/09/18/2689868.html
【編輯推薦】
- ASP.NET Web開發(fā)框架項目介紹
- YQBlog .NET MVC3博客系統(tǒng)之用戶系統(tǒng)實戰(zhàn)
- ASP.NET Cache的一些總結(jié)
- ASP.NET中常用的幾種身份驗證方式
- 各自為政:ASP.NET實現(xiàn)團隊分工的思考
新聞名稱:鐵道部新客票系統(tǒng)設(shè)計(二)
瀏覽地址:http://m.fisionsoft.com.cn/article/ccdpocd.html


咨詢
建站咨詢
