前幾天在 QQ 群里跟 網友 討論了一下 12306 架構 , 把 討論的一些想法整理一下 。
總的來說 , 12306 的解決可以分為 2 個 流派 : 1 技術流 , 2 業務流 。
我們先來看看這篇文章 https://www.cnblogs.com/netfocus/p/5187241.html , 這篇文章應該算 “業務流” 吧 ! 不過有意思的是這篇文章的 回復 。 ^^
我們再來看看這篇文章 https://www.csdn.net/article/2015-03-03/2824091 , 這篇文章里有一幅 架構圖 :
從這個架構圖里 , 我們可以把問題 分成 2 個問題來看 : 1 海量請求的分流 , 2 數據的一致性 和 同步 。
我前幾天寫過一篇博客 《Grid Virtual Server 和 網格計算》 https://www.cnblogs.com/KSongKing/p/9486434.html , 在這篇文章里也提到了這 2 個問題 。
實際上 , 12306 的問題也是 未來的互聯網 要解決的問題 。
在 《Grid Virtual Server 和 網格計算》 里提到 , 分流 采用的是 Client 自主智能 的 選擇 Server 節點 (多中心化) , 數據一致性 和 同步 采用 樂觀 和 松耦合 的 方式 。
樂觀 松耦合 可能需要 換一種 售票 和 購票 觀念 。 所謂 新的 售票 觀念 和 購票 觀念 , 比如 預約 , 預約的方式 。 Book a Ticket 。
樂觀 就是類似 樂觀鎖定 的 那種 方式 , 比如 在 12306 這個 場景上, 樂觀 可以是 預定 , Book a Ticket 。
我們現在是 買票 , 買票 就是 看有沒有 符合要求的 票 , 有就買, 如果 有人 比你先搶到 , 那你就后一個買 , 如果 被 搶完了 , 那 你就 買不到 , 只能再等 。
這種 “搶” 的 方式 會造成 大量的 訪問 在 同一時間 擁擠 向 服務器 。
如果是 預定 的 方式 , 你 可以在 任何 時候 做 一個 預定 , 系統 可以 隨時 受理 你的 預定 , 系統 受理 預定, 並不表示 現在就 購票成功 , 也 不表示 未來一定有票 , 但是 系統 會在 一定的時間 結算 某一批 預定, 然后 根據 票況 給予 預定 的 結果 。
如果 符合你的 要求 有票 , 那么 系統 會 回復 消息 給你 “您 預定的票 已可購買 , 在 1 個 小時內 回復 xxx 確定購買 ” 。
那么 , 你 在 1個 小時內 回復 xxx 的話 (當然包括了 支付 錢) , 那么 就購買成功了 。
如果 沒有 符合要求的票, 或者 符合要求的 票 已經 用完了(安排 給 在你之前 預定的 人們 了) , 那么 系統 會回復 你 “沒有 符合您的 要求的 票” 或者 “符合要求的 票 已預定完 , 請再次 預定” 。
你 可以 再次 預定 , 然后 等待 系統通知 , 如此 循環 。
如果 從 架構 的 角度 來 解釋 預定 這種 業務 , 可以 這樣解釋 , 傳統的 購買 相當於 同步 , 預定 相當於 異步 , 預定(異步) 可以解決 同一時間 大量請求 擁擠向 服務器 的 問題 。
同時可以解決 數據 一致性 和 同步 的 問題 。
異步 可以 在 一定的時間 進行 一次 “結算” , 就不需要像 同步方式 那樣 為了 數據一致性 和 數據同步 而 需要 極致 的 服務器資源 和 網絡資源 。
你把 需求 提給 服務器 , 服務器 不是 即時(同步) 答復 , 而是, “先考慮一下” , 把 很多 用戶 的 需求 都 匯集 一下 , 再統一答復一次 。
消息隊列 是 “架構” 里 異步 的 代表 , 但在這里說的 解決方案 中, 具體的 技術 可以是 各種各樣 。
輪詢 Redis , 甚至 輪詢 數據庫 也是可以的么 。 ^^
事實上 , 用戶的 需求 會先持久化 , 所以, 可能 會 輪詢 數據庫 。
因為 是 異步 樂觀 松耦合 的 架構 , 所以 , 輪詢 數據庫 也是 很輕松 的 ,不會給 系統造成 負擔 。
我們再看上面的那個 架構圖 , 圖的下方 列出了 余票查詢集群 、 用戶登錄集群 、 訂單分級查詢 、 票價計算集群 、 實名制身份確認集群 5 項 。
我們可以看到圖的中央 , 紅色 粗的 箭頭 “海量購票請求” , 這個就是來自於 全國 的 用戶 的 購票請求。這個 請求 是 指向 “鐵路總公司數據中心” 。
中央 還有一個 藍色 的 比較細 的 箭頭 , 是 “余票查詢請求分流” , 指向 阿里雲 公有雲 數據中心 , 也就是說, 阿里雲 公有雲 數據中心 可以 來 分擔 “余票查詢” 業務 。
而 左側 有一個 “主數據庫” , 主數據庫 的 數據 來自於 18 個路局 的 數據匯總 , 主數據庫 同時 向 鐵路總公司數據中心 和 阿里雲數據中心(負責 余票查詢分流) 提供數據(同步數據) 。
從 這個 圖 的 架構 中 我們 可以看到 , 核心 交易 是 發生在 “鐵路總公司 數據中心” , 就是說, 這是 一個 實時的, 中心化 的 數據庫 支持 的 業務系統 。
同時 也可以 判定, 余票 查詢 不是 實時 的 , 是一個 參考性 的 資料 。 具體 能不能 買這個 票, 在 真正 買票(在 鐵路總公司 數據中心 中 發生交易) 時 才能 知道 結果 。 而 “鐵路總公司 數據中心” 這個 中心數據庫 , 它 的 承載能力 來自於 一個 分布式數據庫 Gemfire 。
QQ 群里有網友發了一段節選資料 :
也可以看這一段 :
可以看到, 12306 核心的 數據 承載能力 來自於
1 中心數據庫 是 一個 可擴展的 計算機集群
2 中心數據庫 是 一個 內存數據庫 , 而且 Gemfire 是一個 key value 數據庫, 不是 關系數據庫
架構圖 左邊 的 18個路局 到 主數據庫 可能是 把 車況 和 票況 匯總給 鐵路總公司 數據中心 吧 。
所謂 “兩地三中心” , 兩地 應該是指 鐵路總公司 和 鐵科院 吧 。 三中心 應該就是 鐵路總公司數據中心 鐵科院數據中心 阿里公有雲數據中心 吧 。
總的來說呢 , 這種 中心化 的 設計 , 核心 的 處理能力 來自於 中心數據庫 。 而 12306 是通過 Gemfire 這樣一個 可以構建 集群 的 內存數據庫 並且是 key value 數據庫 來 做到這一點的 。
下面 , 這是根據我上面說的 多中心化 樂觀(異步 預定) 畫的架構圖 :