1. 程式人生 > >淺談12306架構

淺談12306架構

原文地址:http://blog.csdn.net/qq_21260033/article/details/78969329

讀了幾篇有關12306架構設計的部落格,在這裡做下簡單的總結:

主要角色:使用者 
主要功能:查詢剩餘票數 售票

一 分析業務 
業務複雜點: 
1 庫存集中:所有登入的使用者訪問的都是資料中心的票據資料 
2 複雜的業務邏輯:還有很多查詢操作,查時間,查座位,查鋪位,一個車次不 行,又查另一個車次,其伴隨著大量的查詢操作,下單的時候需要對資料庫操作。另外,關於秒殺,完全可以做成只接受前N個使用者的請求(完全不操作後端的任何資料, 僅僅只是對使用者的下單操作log),這種業務,只要把各個伺服器的時間精確同步了就可以了,無需在當時操作任何資料庫。可以訂單數夠後,停止秒殺,然後批量寫資料庫。火車票這個豈止是秒殺那麼簡單。能不能買到票得當時告訴使用者啊。 
3 資料一致性造成效率瓶頸

:訂票系統應該和電子商務的訂單系統很相似,都是需要對庫存進行:1)佔住庫存,2)支付(可選),3)扣除庫存的操作。這個是需要有一致性的檢查的,也就是在併發時需要對資料加鎖的。B2C的電商基本上都會把這個事幹成非同步的,也就是說,你下的訂單並不是馬上處理的,而是延時處理的,只有成功處理了,系統才會給你一封確認郵件說是訂單成功。我相信有很多朋友都收到認單不成功的郵件。這就是說,資料一致性在併發下是一個瓶頸。 
4 使用者量巨大:春運期間,當票放出來的時候,就會有幾百萬人甚至上千萬人殺上去,查詢,下單。幾十分鐘內,一個網站能接受幾千萬的訪問量,這個是很恐怖的事情。據說12306的高峰訪問是10億PV,集中在早8點到10點,每秒PV在高峰時上千萬。 
5 動態庫存

與淘寶對比: 
淘寶要比B2C的網站要簡單得多,因為沒有倉庫,所以,不存在像B2C這樣有N個倉庫對同一商品庫存更新和查詢的操作。下單的時候,B2C的 網站要去找一個倉庫,又要離使用者近,又要有庫存,這需要很多計算。試想,你在北京買了一本書,北京的倉庫沒貨了,就要從周邊的倉庫調,那就要去看看瀋陽或 是西安的倉庫有沒有貨,如果沒有,又得看看江蘇的倉庫,等等。淘寶的就沒有那麼多事了,每個商戶有自己的庫存,庫存分到商戶頭上了,反而有利於效能。

優化方案: 
1 服務端處理請求的負載均衡 
通過DNS的負載均衡器(一般在路由器上根據路由的負載重定向)可以把使用者的訪問均勻地分散在多個Web伺服器上。這樣可以減少Web伺服器的請求負載。因為http的請求都是短作業,所以,可以通過很簡單的負載均衡器來完成這一功能。最好是有CDN網路讓使用者連線與其最近的伺服器(CDN通常伴隨著分散式儲存) 
2 減少前端連結數:

 
我看了一下12306.cn,開啟主頁需要建60多個HTTP連線,車票預訂頁面則有70多個HTTP請求,現在的瀏覽器都是併發請求的。所以,只要有100萬個使用者,就會有6000萬個連結,太多了。一個登入查詢頁面就好了。把js打成一個檔案,把css也打成一個檔案,把圖示也打成一個檔案,用css分塊展示。把連結數減到最低。 
3 減少網頁大小增加頻寬 
4 優化查詢:使用noSQL資料庫完成餘票查詢 設計如下:
 
資料庫的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;使用者再怎麼刷,也不會干擾資料庫。 
5 資料映象(負載均衡) 
幾乎所有主流的資料庫都支援映象,也就是replication。資料庫的映象帶來的好處就是可以做負載均衡。把一臺資料庫的負載均分到多臺上,同時又保證了資料一致性(Oracle的SCN)。最重要的是,這樣還可以有高可用性,一臺廢了,還有另一臺在服務。 
6 資料分離: 
主從複製 讀寫分離 分庫分表 
7 硬體雲服務 
達到動態分配硬體資源,節省開銷