春運一票難求,候補官方搶票
最近春節(jié)火車一票難求,12306系統(tǒng)的候補購票是一種官方支持的搶票方式。在首日票已售罄時,立即提交候補請求,系統(tǒng)會優(yōu)先考慮候補乘客的需求。根據(jù)成功率靈活選擇是否候補購票。
當旅客在12306網(wǎng)站購票,輸入乘車日期、發(fā)到站等信息查詢沒有余票時,頁面會在相關(guān)車次的席別余票顯示列表中出現(xiàn)“候補”字樣,旅客可根據(jù)需求點擊相應車次、席別對應的“候補”區(qū)域,系統(tǒng)將該需求自動加入當前候補購票需求列表。候補訂單提交成功后需在30分鐘內(nèi)完成支付,完成候補預付款支付后,候補購票訂單立即生效。候補購票訂單生效后,相關(guān)候補需求不可修改,如需變更,可終止訂單后重新操作。兌現(xiàn)時,按照候補訂單生效的時間順序,優(yōu)先兌現(xiàn)符合條件的候補需求。預付款按該單不同組合需求中票款的最高額度計算(臥鋪按下鋪票價計算)。
候補訂單系統(tǒng)該如何設計?
那么如何設計一個12306火車票候補功能的系統(tǒng)呢?設計一個12306火車票候補功能的系統(tǒng)我們需要考慮的主要模塊包括乘客候補系統(tǒng)、車票余量監(jiān)控、排隊、通知機制以及支付與出票等核心環(huán)節(jié)。以下是一種簡化的系統(tǒng)設計概述:

??用戶提交候補請求:允許用戶對已經(jīng)售罄的車次座位發(fā)起候補申請,包含乘車人信息、日期、車次、席別等必要信息。
??候補隊列建立:系統(tǒng)將所有候補請求按照一定的優(yōu)先級策略(如購票時間先后、會員等級等)排序,形成候補隊列。
2.?支付模塊:
??候補訂單申請成功后,用戶在接到通知后,應在規(guī)定時間內(nèi)完成支付。
??支付成功后需要將消息推送到候補訂單模塊,候補訂單根據(jù)規(guī)則排序建立候補隊列。
3.?車票余量監(jiān)控模塊:
??實時對接12306票務數(shù)據(jù)庫,監(jiān)控各車次的退票、改簽動態(tài),實時更新車票剩余情況。
??當有乘客退票或者改簽導致座位空缺時,觸發(fā)候補隊列處理機制。
4.?候補處理模塊:
??根據(jù)車票余量變化,自動從候補隊列中選擇符合條件的候補乘客,為其生成車票。
??成功分配車票的候補請求移除出隊列,未成功分配的則繼續(xù)保留等待。
5.?出票模塊:
??候補訂單處理后,系統(tǒng)立即執(zhí)行出票操作,將電子客票信息更新至乘客賬戶,并可下載電子憑證。
通過以上模塊,構(gòu)建一個高效、穩(wěn)定、透明的火車票候補系統(tǒng),既能有效利用票源,又能提升用戶體驗。
那么不同的車次、訂票日期、坐席、出站、候補人數(shù)組合在一起后傳統(tǒng)的消息隊列可能無法滿足我們的需求了。下面拿G521列車舉個例子:

這是一個開往武漢的高鐵,假如我們要在2024-02-08這天要到鄭州,票沒有了,我們候補訂單候補了3個人,那么這個隊列該怎么存放呢?

我們可以簡單想下一個隊列能夠快速的根據(jù)車次、訂票日期、坐席、出站、候補人數(shù)組合等信息快速找到隊列,并消費。傳統(tǒng)數(shù)據(jù)庫無法滿足這種高并發(fā)的需求,REDIS的list貌似可以試下,如果我想對某個車次+日期查詢隊列情況(超過一定數(shù)量,提示用戶不要排隊了)又不太方便,這時hash+list的組合就比較合適了。下面我們看下詳細設計。
如何使用redis的hash+list實現(xiàn)候補隊列
我們使用 Redis 的 Hash 結(jié)構(gòu)來實現(xiàn)根據(jù)車次、車站、日期、乘車人數(shù)設計一個隊列。每個車次及時間作為一個 key,車站和乘車人數(shù)作為 field,對應的值是一個隊列,存放候補訂單。當某個車次到某個車站有票時,可以遍歷這個 key 及 field,找到第一個隊列進行消費。以下是具體的設計方案:

1. Redis Hash 結(jié)構(gòu)
Key:?train:{train_number}:{date}
Field:?{station}_{passenger_count}
Value:?候補訂單隊列2. 舉例
假設 G521 車次,日期為 2024-02-08,有 3 個乘客,站臺為 鄭州。
Key:?train:G520:2024-02-08
Field:?鄭州_二等座_1
Value:?[候補訂單1,?候補訂單2,?候補訂單3,?...]3. 消費邏輯
當某個車次到達某個車站有票時,我們可以按遍歷該車次在該日期下的 Hash 結(jié)構(gòu)的 field,如果很多票我們選擇優(yōu)先消費field=鄭州_二等座_3的隊列,如果只有一張票我們只能消費鄭州_二等座_1的隊列。當然還需要結(jié)合候補時間判斷。
總結(jié)
1.?Hash 結(jié)構(gòu)設計:?使用 Hash 結(jié)構(gòu)來存儲車次、日期、車站、乘車人數(shù)等信息,便于查詢和管理。
2.?隊列存儲候補訂單:?在 Hash 結(jié)構(gòu)的 field 中存儲候補訂單隊列,便于根據(jù)車站和乘車人數(shù)索引訂單。
3.?消費邏輯:?當某個車次到達某個車站有票時,遍歷相應的 Hash 結(jié)構(gòu),找到一個非空隊列進行消費。
通過以上設計,我們可以根據(jù)車次、車站、日期、乘車人數(shù)設計一個隊列,并通過 Redis 的 Hash 結(jié)構(gòu)實現(xiàn),保證了訂單信息的管理和處理的高效性和可靠性。想想一些平臺的排隊功能是不是也可以這么搞?