<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    深藍色心情

    過來聊聊~~~~

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      31 Posts :: 0 Stories :: 46 Comments :: 0 Trackbacks
    12306主要就是賣票比較復雜,注冊登錄之類的功能就不說了。 

    有網友說,12306賣票系統比航空復雜,因為要分段賣,航空只有起點和終點,火車中間還有好多站。不過好消息是,這些站在售票時是連續的,不會出現1張票跳著站買的情況,這樣就可以把一張票拆成N張只有起點和終點的票,和航空售票一樣了。 

    賣票分為兩部分,查詢和購買。12306目前提供了單獨的查詢,我覺得這個其實挺好的,至少有讀寫分離的思想;不過延遲10分鐘的數據,肯定沒什么人愿意用,大家還是要擠進購買系統查詢。單獨的查詢相當于擺設了,沒有發揮作用。要讓查詢系統有效,尤其是春運期間,延遲應該在30秒之內。 

    查詢剩余票數設計: 

    查詢的特點是按照車次信息或者時間查,車次和時間一般都不會變,因此在設計時,可以把頁面分成兩部分。一是匹配的車次列表信息,如北京到上海有哪些車,這個結果可以用CDN緩存。車次基本是固定的,緩存設置為10分鐘應該就能滿足需要。不占用負載。在瀏覽器拿到這個頁面后,通過異步請求,根據每趟車的編號二次查詢剩余票數等實時數據,合并顯示。 

    車次查詢時,把車次信息分庫存儲,并作冗余存儲。好比這個庫提供所有北京->xxx的查詢,這個庫提供上海到xxx的查詢,這個庫提供廣州到xx的查詢,剩下的在一個大庫中等。車次變化很小,庫可以分散存,而且可以冗余存儲。用內存表也行,總數據量也不多,性能上沒什么可說的。 

    對于實時票數,確實是比較困難的,網上很多方案都不對,沒有考慮中間站的問題。剩余票數緩存并不好做。我的想法是,提前分好票,然后用單獨的數據結構做緩存。 

    例如,對于G113高鐵,共有8站:北京、德州、濟南、徐州、南京、常州、蘇州、上海。假設它有兩千張票,座位啊臥鋪啊啥的。在發票前,創建新表20120113_G113,然后把2000張票提前插入到表中,每個票都有一個本表內唯一的數字編號。表結構基本上就是:編號、起始站、終點站、座位類型、車廂、座位號、乘客姓名、乘客證件號碼、車票狀態等實際業務模型需要。初始化時,起點站就是北京(根據順序存儲為1),終點站就是上海(根據順序存儲為8),乘客信息空著表示尚未綁定乘客,車票狀態置為“待出售”。 

    這樣我們要查詢2012年1月13號G113 濟南->南京 的剩余票數時,就查詢20120113_G113起始站編號大于等于3并且小于等于5,并且狀態為“待出售”的記錄數就行了。 

    每張表2000條數據,對于非春運時節,性能完全足夠。對于春運時節,非繁忙路段,性能應該也足夠了。對于春運繁忙期,繼續看下面的。 

    車票出售基本流程: 

    用戶選擇車票并要求購買,系統鎖定票并標記狀態為“鎖定中”,讓用戶付款等。完成后標記車票為“已經發售”,并且更新用戶信息到車票的持有人信息字段中。此票不再出售。 

    對于中間站購票,假設用戶購買了 濟南->南京 ,前面流程不變。但完成出票后,將車票起始和終點站改為“濟南”和“南京”,并且自動插入兩張新票可用。一張是“北京->濟南”,一張是“南京->上海”,通知隊列更新相關緩存。相當于車票做了自動分裂。這樣我們設計時只需要把一張票設計為“只有起點和終點”就行了。 

    更高效的剩余票數查詢設計: 

    數據庫的count操作并不快,因此對于繁忙季節的繁忙表,每次都count是鐵定不行的。我想到的一個辦法是:把上面提到的預售車票表加載到內存中。我們用一個64位long類型數字表示一張車票,每趟車的每種座位類型是一個long數組。 

    對于每個long數字,前面的32位用來順序存儲32個車站(假設一趟車最多有32個站,沒查過,不行可以放長點),每一位標記“車票是否包含此站”。如G113 濟南到南京的票(車站順序為第3到第5站),long數字的第2到第4位設置為1,其他前32位設置為0。后面的32位用來表示車票在車票出售表中的唯一編號。這樣根據一個long類型數字,我們就能表述一張票的發售信息了。 

    比如2012年1月13號G113,有軟臥500張和硬臥1500張。那就需要兩個數組。20120113_G113_軟臥 對應一個長度500的long數組;20120113_G113_硬臥 對應一個長度1500的long數組。存儲所有售票信息。 

    有點類似BitSet的感覺,對空間要求不高。我們可以做個系統把所有車票信息按照這種結構加載到內存中。對于實時查票,如查詢2012年1月13號G113車次 濟南->南京 的余票,就是遍歷兩個數組,檢查位數為2和4的long數字有多少個,就直接獲得了軟臥和硬臥的剩余票數。對于現代計算機,這點遍歷,時間是納秒級的。 

    當車票被出售后,從long數組中刪除票信息,比如先置為-1表示已經無效。再用后臺線程實際刪除(避免寫沖突,將刪除延遲到重建一個數組所消耗的多少納秒內剛好沒有寫請求的時間段中)。如果long數組長度為0,那就是沒有車票了,直接返回0;用戶再怎么刷,也不會干擾數據庫。 

    更高效的剩余票數查詢方案的擴展性和容錯性: 

    本身車票是按照車次劃分的,同時也有時間維度,橫向擴展不存在任何問題。 

    long數組可以根據數據庫票務信息重新構造,而且成本不高(一條“select * from xxx where 狀態=待發售” SQL語句)。在硬件故障,擴容機器,或是發現數據不一致時,重新構造數組就行。而且可以從后臺異步做。擴展性和容錯性都不是問題。 

    售票交易與鎖票: 

    用戶查詢到有票后,填寫要購買的票數,提交。好比購買兩張硬臥,流程如下: 

    1. 在20120113_G113_硬臥long數組中隨機獲取符合要求的順序的兩個long數字,并將其從數組中刪除;這個速度很快,納秒級; 

    2. 根據long數字后32位,從數據庫中鎖票。如果全部鎖定成功,設置票為預定狀態,更新用戶預定信息,鎖票時間等。然后記錄日志等其他相關操作。如果鎖票失敗,說明在納秒級的時間內,票還是有沖突,購票失敗,直接返回報錯。鎖票就是數據庫行鎖,sql中的 select for update nowait。 

    3. 頁面提示錯誤,或者進入下一步交易流程,如網銀支付等。 

    在整個過程中,我們看到,用戶請求就算集中爆發,事務的沖突性也能降低到“隨機獲取的long數組值剛好一樣 + 在cpu執行2000個for循環的可能百萬分之一秒內剛好同時提交”。我覺得沖突概率應該很低很低。一趟車2000個車票,1:100比例也就20萬人同時搶,20萬人同1秒提交cpu也算的過來。而實際上,怎么可能一秒鐘有20萬人同時搶一趟車的票哪…… 

    在整個過程中,大部分請求都被long數組消耗完后,直接檢查long數組長度為0,提示無票攔截。進入數據庫階段的,也就是比實際的票數多一點點的有效訂單而已。 

    回票: 

    中間站買票的,在預定成功后,車票自動分裂,分裂的票可以通過隊列調度實時的回到long數組中,繼續服務。 

    預定后不買的,可以通過預定時間的超時檢查,后臺做個線程,讓票回歸。 

    歡迎討論。 

    微博:http://weibo.com/guzzframework 
    posted on 2012-01-16 19:48 深藍色心情 閱讀(2499) 評論(1)  編輯  收藏

    Feedback

    # re: 對于12306,我的完整技術方案 2012-01-17 09:42 何楊
    最近這方面的討論好多啊。  回復  更多評論
      


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲精品在线网站| www.亚洲色图.com| 午夜影视日本亚洲欧洲精品一区| 一个人免费观看www视频| 国产伦一区二区三区免费| 亚洲日韩精品无码专区加勒比☆ | 国产免费一区二区三区VR| 亚洲熟妇无码AV| 成人免费一区二区三区在线观看| 亚洲1234区乱码| 四虎影院免费视频| 阿v视频免费在线观看| 亚洲色一色噜一噜噜噜| 插鸡网站在线播放免费观看| 国产亚洲综合色就色| 成人黄网站片免费视频| 内射干少妇亚洲69XXX| 免费AA片少妇人AA片直播| 亚洲熟妇无码AV| 波多野结衣一区二区免费视频| 免费在线观看自拍性爱视频| 国产亚洲人成A在线V网站| CAOPORN国产精品免费视频| 亚洲精品国产精品乱码不卡√| 成人午夜免费视频| 99re热免费精品视频观看| 国产成人 亚洲欧洲| 国产a级特黄的片子视频免费| 特黄aa级毛片免费视频播放| 免费在线观看理论片| 99精品免费视频| 亚洲国产精品成人精品无码区| 国产精品区免费视频| 亚洲va成无码人在线观看| 免费观看美女裸体网站| 牛牛在线精品观看免费正| 亚洲中文字幕无码久久精品1| 久久久久成人片免费观看蜜芽| 亚洲春色在线观看| 久久久久久精品免费免费自慰| 国产91在线|亚洲|