日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

12306的数据库设计

發布時間:2023/12/20 数据库 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 12306的数据库设计 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原文地址:http://blog.csdn.net/hnkontecna/article/details/61672983

標簽

PostgreSQL , 12306 , 春節 , 一票難求 , 門禁廣告 , 數組 , 范圍類型 , 搶購 , 排他約束 , 大盤分析 , 廣告查詢 , 火車票


背景

馬上春節了,又到了火車票的銷售旺季,一票難求的問題依舊存在嗎?

還記得10年前春節前買火車票得在放票前1天搬個小板凳去排隊,對于熱門路線,排一個晚上都有可能買不到票。

隨著互聯網的發展,幾年前建設了12306網上購票系統,可以從電腦上買票,但是不要以為在電腦上就能買到票。

我記得12306剛推出時,經常發生12306網站打不開,無法付款的問題。

為什么呢?

原因很簡單,春節期間網上購票的人可能達到幾億的級別,而且放票日期是同一天同一個時間點,也就是說同一時刻12306要接受幾億用戶的訪問。

處理能力和實際的訪問需求更不上,帶來的結果就是網站打不開,系統不穩定的現象。

后來12306想了分線路分時段開啟的辦法,想辦法把不同線路的用戶錯開時間來訪問12306的網站,但是這個方法起初的效果不明顯,并不是所有用戶都知道的(就好像你臨時通知今天不上班,但還是有用戶會來單位的),所以大多數用戶還是集中在一個點去訪問12306的網站。

隨著硬件的發展,技術的演進,12306的系統越來越趨于成熟,穩定性和響應速度也越來越好。

據說現在很多商家還開通了云搶票業務,本質上是讓你不要沖擊12306系統了,把需求提前收集,在放票時,這些系統會進行排隊與合并購買,這種手段可以減少12306的訪問并發。

搶火車票是很有意思的一個課題,對IT人的智商以及IT系統的健壯性,尤其是數據庫的功能和性能都是一種挑戰。

接下來我們一起來縷一縷有哪些難點,又有怎樣的解決手段。

一、鐵路售票系統 - 西天取經之路開始啦

鐵路售票系統最基本的功能包括

查詢余票、余票統計、購票、車次變化、退票、改簽、中轉乘車規劃 等。

每個需求都有各自的特點,例如

1. 查詢余票,用戶在購票前通常會查一下到達目的地有哪些余票,它屬于一個高并發的操作,同時需要統計余票張數,需要很強的CPU來支撐實時的查詢。

2. 購票,購票和查詢不一樣,購票是會改變庫存的,所以對數據庫來說是更新的操作。

而且購票很可能發生沖突,例如很多人要買同一趟車的票,那就出現沖突了,到底賣給誰呢?

需要考慮鎖沖突,盡量的讓不同的人購買時可并行,或者可以合并多人的購票請求,來減少數據庫的更新操作。

3. 中轉乘車,當用戶需要購買的起點和到達站無票時,需要計算中轉的搭乘方案。

比如從北京到上海,如果沒有直達車,是不是該轉車呢?轉哪趟,在哪里轉就成了問題,簡單一點就是買票的人自己想。

高級一點的話,可以讓12306給你推薦路線,這個涉及的是數據庫的路徑規劃功能。

我們來逐一分析一下這些需求的特點。

1 查詢余票

1. 普通的余票查詢需求

你如果要買從北京到上海的火車票,通常會查一下哪些車次還有余票。

查詢的過濾條件可能很多,比如

1.1. 上車站、下車站、中轉站

1.2. 車次類型(高鐵、動車、直達、快速、普客、...)

1.3. 出發日期、時段

1.4. 到達日期、時段

1.5. 席別(硬座、硬臥、...站票)

1.6. 過濾掉沒有余票的車次

展示給用時還要考慮到怎么排序(是按始發時間排呢,還是按票價,或者按余票數量排?),怎么分頁。

眼見不一定為實

查詢余票通常不是實時的、或者說不一定是準確的,有可能是后臺異步統計的結果。

即使是實時統計的結果,在高并發的搶票期間,你看到的信息對你來說也許很快就會失效。

比如你看到某趟車還有100張票,很可能等你付款的時候,已經賣光了。

所以在高峰期,余票信息的參考價值并不大,不要被迷惑了。

2. 查詢余票的另一個更高級的需求是路徑規劃, 自動適配(根據用戶輸入的中轉站點s)

這個功能以前可能沒有,但是總有一天會暴露出來,特別是車票很緊張的情況下。

就比如從北京到上海,直達的沒有了,系統可以幫你看看轉一趟車的,轉2趟車的,轉N趟車的。(當然,轉的越多越復雜)。

從中轉這個角度來講,實際上已經扯上路徑規劃的技術了。

怎么中轉是時間最短的、價格最低的、中轉次數最少的等等。(里面還涉及轉車的輸入要求(比如用戶要求在一線城市轉車,或者必須要轉高鐵))。

關于路徑規劃,可以參考一下PostgreSQL pgrouting,已支持多種路徑規劃算法,支持算法的自定義擴展。

簡直是居家旅行,殺人滅口的必備良藥。

《聊一聊雙十一背后的技術 - 物流, 動態路徑規劃》

師父小心,有妖怪。。。

1. 大多數用戶是有選擇綜合癥的,通常來說,用戶可能會查詢很多次,才選到合適日期的合適車次的票。

查詢量比較大,春節期間更甚。

2. 為了展示余票數量,需要統計,會耗費較多的CPU, IO資源。

3. 路徑規劃,幫用戶選擇最佳的轉車路線,很考驗數據庫的功能,大多數數據庫沒有這個功能。

2 余票統計

對于售票系統來說,查詢余票實際上是一個統計操作。

統計操作相比簡單查詢,不但消耗更多的IO還消耗更多的CPU資源。

想像一下幾億人(其實不用這么多,可能幾十萬就夠了)來查詢余票,即使機器沒掛掉,也會把所有機器的資源跑滿,CPU產生的熱量,可能幾分鐘就能把雞蛋煮熟咯。

為了減少實時查詢余票的開銷,通常會分時進行統計,更新最新的統計信息。

用戶查詢余票信息時,查到的是統計后的結果,前面我已經分析過了,余票是不可信的,所以存在一定的延遲其實也是允許的。

這下不能煮雞蛋了,因為把幾億個統計請求,變成了1個統計請求,是不是一下子世界就冷靜了呢?

我們可以看到12306主頁的余票大盤數據

師父小心,有妖怪。。。

1. 余票信息需要統計,查詢會耗費較多的CPU,IO。

由于余票是不可信的,所以存在一定的延遲其實也是允許的,優化手段是異步統計,用戶查詢統計后的結果。

3 購票

購票相對于查詢余票來說,從請求量來分析,比查詢請求更少,因為通常來說,用戶可能會查詢很多次,才選到合適日期的合適車次的票。

但是由于購票是一次交易,每次交易都會產生寫操作,而且這種交易并不是無限庫存的交易,因為庫存是有限的,所以設計的關鍵是降低粒度,減少鎖沖突,減少數據掃描量。

另外還需要考慮的因素包括

1. 同一趟車次的同一個座位,在不同的維度可能會被多次售賣

1.1 時間維度,如發車日期

1.2 空間維度,不同的起始站點

2. 票價

票價一般和席別綁定,按區間計費。

另一個需求是盡量的將票賣出去,減少空洞座位。

打個比方,從北京到上海的車,中間經過(天津、徐州、南京、無錫、蘇州),如果天津到南京段有人買了,剩下的沒有被購買的段應該還可以繼續被購買。

如果一趟從北京到上海的車,所有的票都被蘇州到上海的用戶買了,其他的位置沒有賣出,鐵大哥是不是要哭暈在廁所。

又或者某趟車大量的座位被中途上車的用戶買了,是不是可以買到全程的票數就少了。

以前就存在這種情況,對鐵大哥的成本是個不小的考驗。

師父小心,有妖怪。。。

1. 為了減少購票系統的寫鎖沖突,例如同一個座位,盡量不出現因為一個會話在更新它,其他會話需要等待的情況。

(比如A用戶買了北京到天津的,B用戶買了天津到上海的同一趟車的同一個座位,那么應該設計合理的合并操作(如數據庫內核改進)或者從設計上避免鎖等待)

其實就是把座位的空間維度(從哪里到哪里)、本身的屬性(座位號)、時間維度(發車日期)進行解耦,放到多條記錄中,從而在購買時,可以同時進行。

因為數據庫中最小的鎖目前是行鎖(單行記錄同一時刻只允許一個會話進行更新,其他的被堵塞,等待釋放鎖),也許隨著技術的發展,會演變成列鎖,或者列里面的元素鎖(比如數組,JSON)。

4 車次新增、刪除、變更

春節來臨時、通常需要對某些熱門線路增加車次。

及車次的新增、刪除和變更需求。

在設計數據庫時,應該考慮到這一點。

師父小心,有妖怪。。。

車次的變更簡直是牽一發而動全身,比如余票統計會跟著變化,查詢系統也要跟著變化。

還有初始化信息的準備,例如為了加快購票的速度,可能會將車次的數據提前準備好(也許是每個座位一條記錄),參考第3個需求的解說。

5 對賬需求

票可能是經過很多渠道賣出去的,例如支付寶、去哪兒、攜程、鐵老大的售票窗口、銀行的代理窗口、客運機構 等等。

涉及到實際的銷售信息與資金往來的對賬需求。

通常這個操作是隔天延遲對賬的。

6 退票、改簽需求

退票和改簽也是比較常見的需求,特別是現在APP流行起來,退改簽都很方便。

這就導致了用戶可能會先買好一些,特別是春節期間,用戶無法預先知道什么時候請假回家,所以先買幾張不同日期的,到時候提前退票或者改簽。

改簽和退票就涉及到位置回收(對數據庫來說也許是更新數據),改簽還涉及購票同樣的流程。

7 取票

這個就很簡單了,就是按照用戶ID,查詢已購買,未打印的車票。

8 其他需求

票的種類

學生票、團體票、臥鋪、站票

這里特別是站票,站票是有上限的,需要控制一趟車的站票人數

站票同樣有起點和終點,但是有些用戶可能買不到終點的票,會先買一段的,然后補票或者就一直在車上不下車,下車后再補票。

先上車后補票

這個手段極其惡劣,不過很多人都是這么干的,未婚先孕,現在的年輕人啊。。。。

通常會考慮容積率,避免站票太多。

如果無節制的銷售站票,可能坐不下的。

猴哥,師父被妖怪抓走啦

1. 大多數用戶是有選擇綜合癥的,通常來說,用戶可能會查詢很多次,才選到合適日期的合適車次的票。

查詢量比較大,春節期間更甚。

2. 為了展示余票數量,需要統計,會耗費較多的CPU, IO資源。

3. 路徑規劃的需求,幫用戶找出(時間最短、行程最短、指定中轉站、最廉價、或者站票最少)等條件的中轉搭乘路線。

媽媽再也不用擔心買不到票啦。

4. 余票信息需要統計,查詢會耗費較多的CPU,IO。

由于余票是不可信的,所以存在一定的延遲其實也是允許的,優化手段是異步統計,用戶查詢統計后的結果。

5. 為了減少購票系統的寫鎖沖突,例如同一個座位,盡量不出現因為一個會話在更新它,其他會話需要等待的情況。

(比如A用戶買了北京到天津的,B用戶買了天津到上海的同一趟車的同一個座位,那么應該設計合理的合并操作(如數據庫內核改進)或者從設計上避免鎖等待)

其實就是把座位的空間維度(從哪里到哪里)、本身的屬性(座位號)、時間維度(發車日期)進行解耦,放到多條記錄中,從而在購買時,可以同時進行。

因為數據庫中最小的鎖目前是行鎖(單行記錄同一時刻只允許一個會話進行更新,其他的被堵塞,等待釋放鎖),也許隨著技術的發展,會演變成列鎖,或者列里面的元素鎖(比如數組,JSON)。

6. 車次的變更簡直是牽一發而動全身,比如余票統計會跟著變化,查詢系統也要跟著變化。

還有初始化信息的準備,例如為了加快購票的速度,可能會將車次的數據提前準備好(也許是每個座位一條記錄),參考第3個需求的解說。

綜合以上痛點和需求分析,我們在設計時應盡量避免鎖等待,避免實時余票查詢,同時還要避免席位空洞。

二、誰是猴子請來的救兵?

經過前面的分析,已經把鐵路售票系統最關鍵的幾個業務場景進行了描述,并且闡述了其中的設計痛點,那么我們如何設計合理的系統來滿足幾億人民搶票的需求呢?

西游記里每一集孫悟空師父被妖怪抓走,總能找到救兵來解救。

我們也需要救兵,救兵快來啊。。。。

PostgreSQL是全世界最高級的開源數據庫,幾乎適用于任何場景。

有很多特性是可以用來加快開發效率,滿足架構需求的。

針對鐵路售票系統,可以用到哪些救命法寶呢?

1. 看招,法寶1,varbit類型

使用varbit存儲每趟車的每個座位途徑站點是否已銷售。

例如 G1921車次,從北京到上海,途徑天津、徐州、南京、蘇州。包括起始站,總共6個站點。 那么使用6個比特位來表示。

'000000'

如果我要買從天津到徐州的,這個值變更為(下車站的BIT不需要設置)

'010000'

這個位置還可以賣從北京到天津,從徐州到終點的任意站點。

余票統計也很方便,對整個車次根據BIT做聚合計算即可。

統計任意組合站點的余票( 北京-天津, 北京-徐州, 北京-南京, 北京-蘇州, 北京-上海, 天津-徐州, 天津-南京, ......, 蘇州-上海 )

udf_count(varbit) returns record

統計指定起始站點的余票(start: 北京, end: 南京; 則返回的是 北京-南京 的余票)

udf_count(varbit, start, end) returns record

以上兩個需求,開發對應的聚合函數即可,其實就是一些指定范圍的bitand的count操作。

通過法寶1,解決了統計余票的需求、售票無空洞的需求。

2. 看招,法寶2,數組類型

使用數組存儲每趟車的起始站點,途經站點。

使用數組來存儲,好處是可以使用到數組的GIN索引,快速的檢索哪些車次是可以搭乘的。

例如查詢從北京到南京的車次。

select 車次 from 全國列車時刻表 where column_arr @> array['北京','南京'];

這條SQL是可以走索引的,效率非常高,每秒請求幾十萬不是問題。

法寶2解決了高并發請求查詢符合條件的列車信息的需求。

3. 看招,法寶3,skip locked

這個特性是跳過已被鎖定的行,比如用戶在購買某一趟從北京到南京的車票時,其實是一次UPDATE ... SET BIT的操作。

但是很可能其他用戶也在購買,可能就會出現鎖沖突,為了避免這個情況發生,可以skip locked,跳過鎖沖突,直接找另一個座位。

select * from table where column1='車次號' -- 指定車次 and column2='車次日期' -- 指定發車日期 -- and mod(pg_backend_pid(),100) = mod(pk,100) -- 提高并發,如果有多個連接并發的在更新,可以直接分開落到不同的行,但是可能某些pID賣完了,可能會找不到票,建議不要開啟這個條件 and column4='席別' -- 指定席別 and getbit(column3, 開始站點位置, 結束站點位置-1) = '0...0' -- 獲取起始位置的BIT位,要求全部為0 order by column3 desc -- 這個目的是先把已經賣了散票的的座位拿來賣,也符合鐵大哥的思想,盡量把起點和重點的票賣出去,減少空洞 for update skip locked -- 跳過被鎖的行,老牛逼了,不需要鎖等待 limit ?; -- 要買幾張票

法寶3解決了一伙人來搶票時,在同一趟車的座位發生沖突的問題。

4. 看招,法寶4,cursor

如果要查詢大量記錄,可以使用cursor,減少重復掃描。

5. 看招,法寶5,路徑規劃

如果用戶選擇直達車已經無票了,可以自動計算如何轉乘,根據用戶的乘車站點和目的地選擇最佳搭乘路線。

參考一下pgrouting,與物流的動態路徑規劃需求一致。

《聊一聊雙十一背后的技術 - 物流, 動態路徑規劃》

6. 看招,法寶6,多核并行計算

開源也支持多核并行計算的,在生成余票統計時,為了提高生成速度,可以將更多的CPU加入進來并行計算,快速得到余票統計。

就比如你策劃了一本書,已經列好了大綱,同時你找了100個作者,這100個作者可以根據你分配的工作,同時開始寫作,很快就能把一本書寫完。

而傳統的情況,一本書,只能一個作者幫你寫,即使你找了100個作者,另外的99位也只能空閑,或者他們只能寫其他的99本書。

7. 看招,法寶7,資源隔離

PostgreSQL為進程模型,所以可以控制每個進程的資源開銷,包括(CPU,IOPS,MEMORY,network),在鐵路售票系統中,查詢和售票是最關鍵的需求,使用這種方法,可以在關鍵時刻保證關鍵業務有足夠的資源,流暢運行。

這個思想和雙十一護航也是一樣的,在雙十一期間,會關掉一些不必要的業務,保證主要業務的資源,以及它們的流暢運行。

8. 看招,法寶8,分庫分表

鐵路數據達到了海量數據的級別,很顯然一臺機器無法存下所有的鐵路數據。

那么怎么辦呢? 可以將鐵路的數據進行分區存儲,存到不同的主機。

PostgreSQL的分庫分表方案很多,例如plproxy, pgpool-II, pg-xl, pg-xc, citus等等.

9. 看招,法寶9,遞歸查詢

鐵路有非常典型的上下文相關特性,例如一趟車途徑N個站點,全國鐵路組成了一個很大的鐵路網。

遞歸查詢可以根據某一個節點,向上或者向下遞歸搜索相關的站點。

比如在有哪些車可以直達北京,有哪些車可以轉車到達北京,又或者查詢從北京到拉薩,有哪些線路以及途經線路可以走。

10. 看招,法寶10,MPP,打完收工

為了持續的提高12306的體驗,鐵大哥還有數據挖掘的需求,比如今年春節應該對哪些線路增加車次,每天的車次增加的規劃,哪些線路可以減少車次也能在春節前將用戶送回家。

這些問題可以基于以往的運輸數據進行挖掘計算,進行回答。

基于PostgreSQL的MPP產品很多,例如Postgres-XL, Greenplum, Hawq, REDSHIFT, paraccl, 等等。

使用PG可以和這些產品很好的融合,保持語法一致。

降低數據分析的開發成本。

10道法寶一出,師父又回來啦。

猴子請來的救兵厲害吧,別急,還有更厲害的,阿里云在PostgreSQL基礎上做了很多的改進,比如對12306的系統,就有特別的定制特性。

三、阿里云PostgreSQL varbit, array增強介紹

在鐵路購票系統中,有幾個需求需要用到bit和array的特殊功能,這些特殊的功能目前社區版本沒有,阿里云RDS PostgreSQL對此做了增強,如下。

1. 余票統計

統計指定bit范圍=全0的計數

不指定范圍,查詢任意組合的bit范圍全=0的計數

2. 購票

指定bit位置過濾、取出、設置對應的bit值

根據數組值取其位置下標。

回顧一下我之前寫的兩篇文章,也是使用varbit的應用場景,有異曲同工之妙

《基于 阿里云 RDS PostgreSQL 打造實時用戶畫像推薦系統》

《門禁廣告銷售系統需求剖析 與 PostgreSQL數據庫實現》

PostgreSQL的bit, array功能已經很強大,阿里云RDS PostgreSQL的bitpack也是用戶實際應用中的需求提煉的新功能,大伙一起來給阿里云提需求。

打造屬于國人的PostgreSQL。

小結

本文從鐵路購票系統的需求出發,分析了購票系統的部分痛點,以及數據庫設計時需要注意的事項。

PostgreSQL的10個特性,以及阿里云對PostgreSQL的改進,可以很好的滿足鐵路購票系統的需求。

1. 使用varbit存儲每趟車的每個座位途徑站點是否已銷售。解決了統計余票的需求、售票無空洞的需求。

2. 使用數組存儲每趟車的起始站點,途經站點。數組類型支持索引,解決了高并發請求查詢符合條件的列車信息的需求。

3. 使用skip locked特性,解決了一伙人來搶票時,在同一趟車的座位發生沖突的問題。

4. 使用pgrouting路徑規劃特性,解決了智能推薦乘車的需求。

同時還可以用在很多場景,比如金融風險控制,刑偵,社會關系分析,人脈分析等。

如果你感興趣,網上有很多分析PostgreSQL, pgrouting, Neo4j的文章,PostgreSQL甚至比Neo4j更適合graph場景.

5. 多核并行計算,讓更多的CPU同時幫你干活,例如快速的異步余票統計。

6. 減少坐席空洞的產生,保證更多的人可以購買到全程票。(購票時,如果是中途票,盡量選擇已售的中途票)

7. 根據每個進程進行資源隔離,可以提高穩定性。

8. 對接HybridDB (基于GP\HAWQ) MPP系統,語法一致,可以支持鐵

路系統的數據挖掘需求,節約了開發成本。

阿里云長期提供PostgreSQL, HybridDB ( 基于Greenplum, HAWQ ) 服務和支持。


總結

以上是生活随笔為你收集整理的12306的数据库设计的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。