一元搶寶系統是京東虛擬新興的乙個業務系統,上線以來訂單量一直持續增長。在距離618前兩個月時,京東**商品虛擬研發部對系統做了整體預估,訂單量快速增長及618大促的到來都將帶來單量劇增,屆時勢必會對資料庫容量和負載造成壓力。分析結果表明資料庫很可能成為影響效能的瓶頸,並決定對資料庫底層做分庫分表改造,確保資料水平動態擴充套件能力,滿足資料容量持續增長的需求,並提高下單效率。
上圖是一元搶寶商品詳情頁,從圖中可以看出,一元搶寶的商品即商品項,其不同於其他京東商品的地方在於:有期次、總人次和剩餘人次的概念;假設乙個商品項有100個庫存,則會分100期次售賣,每期次乙個售賣的是乙個庫存;總人次即設定的每一期搶寶商品**,假設1000人次,則商品總價是1000元(每人1元);當剩餘人次為0時,本期搶寶結束,然後按照相應演算法產生搶寶者;然後進行下一期搶寶。
通過技術改造,從整體上來說實現三個目標:
底層路由策略實現;
歷史資料遷移;
業務改造。下面詳細介紹本次改造的過程。
分庫分表最重要的是要先做容器預估,依據資料量和業務特性估算出容器/庫/表的數量及分庫分表規則。
假設一天100萬訂單,一年則產生3.6億訂單量;假設資料結構是這樣的:訂單表10個字段,乙個欄位50個字元;一條訂單則需要500位元組儲存,那麼3.6億訂單則需要大約170gb儲存空間;假設每台機器儲存空間為200gb,則每年增加一台機器即可滿足容量需求。而實際需求要根據壓測結果來決定;如壓測其他一些指標是否滿足需求,如qps、響應時間等。
分庫分表路由策略是基礎,影響整個系統架構,後期業務需求是否滿足和支援,使用是否方便都與此有關。路由策略設計合理,上層業務使用會很方便。一元搶寶專案的路由策略適配和實現是在dao層實現,對上層業務層透明,可不用關心具體實現,並且路由策略不涉及結構上的改動,對上層不會產生影響。
我們知道常見的分表策略有兩種:
hash路由
分割槽路由(增量區間路由)
當然每種策略都不是完美的,只有最適合業務場景的策略才是好的。該專案採用的是兩種方式的結合。
首先按搶寶項hash分庫,然後按搶寶期區間段分表,如下圖所示:
期的路由策略表規則如下:
為什麼使用這種策略?
搶寶項是業務上層維度,可以理解為商品,大部分表中都有這個字段;此id生成時是連續的,長期來看,hash分庫後資料是均衡的。搶寶期是搶寶項下的乙個維度,如乙個項庫存是100,不停售前提下,會生成100期,在售的期次只有乙個。為什麼選擇期id區間作為分表路由策略呢,有朋友會認為也可以選擇訂單id,從路由策略上來說,沒有問題,但一元搶寶專案的業務場景,有根據項id和期id查詢訂單參與紀錄的場景,所以要考慮通過這兩個維度能查到訂單。另外,使用區間作為分表策略,可以動態擴充套件,即使每次查詢經過路由表,這點開銷可以忽略,而且都是通過快取載入。
那以上策略,可以路由的維度有哪些呢?
通過訂單id路由:訂單號按照一定規則生成,其儲存了庫和表的資訊,可以根據訂單號直接定位到相應的庫和表;
通過搶寶項id和搶寶期id路由:搶寶項hash定位到庫,搶寶期查詢路由策略表定位到表,具體圖示如下:
有分就涉及到聚合查詢,我們如何實現呢?先看如下架構圖:
上圖是資料層改造後的架構圖,之前是單錶主從模式,改造後為多個分庫、基礎庫。聚合採用了elastic search (以下簡稱es)。
為什麼使用它呢,首先,簡單便捷,容易接入;其次,支援動態擴容分片,對業務層透明等。系統中的聚合查詢主要使用了es,當然我們有很多降級方案,後面會講到。es不能當作庫來使用,它並不能百分之百保證資料完整性,所以一定要有資料備份,我們使用了聚合表,儲存一段時間內的資料,用於降級使用,一旦es有延遲或集群不可用,就會降級查詢聚合表。
同步es我們是怎麼做的呢?我們使用了canal。有的朋友可能說了,為什麼不在直接在**中插入時去同步,可以這樣做,但有兩個問題,一是同步失敗如何處理,如何保證事務,二是與業務**強耦合,借用術語,不beautify。使用canal,**解耦,不侵入與**。它其實是模擬了資料庫主從複製機制,偽裝為乙個從庫,當資料庫(為不影響主庫生產,我們監聽的是從庫)binlog有變化時,canal監聽到,通過解析服務解析過濾binlog,把需要的日誌過濾出來。解析後,我們通過傳送mq訊息,訊息體是表名和主鍵id,不是整條資料,消費端接到變化的表名和id,實時從庫中查詢最新資料,同步到es、聚合表。
為什麼通過mq訊息呢?還可以用以上兩點來解釋,一是訊息支援失敗重試,儲存失敗後拋異常,等待下次處理,二是系統間解耦。細心的朋友可以看到,乙個訊息佇列,通過多個消費訂閱(可以理解為每個消費者的佇列都是映象複製的)。這樣做為了在儲存時不相互影響;如果使用乙個訂閱者處理,儲存es失敗,其他兩個聚合儲存成功,那也要拋異常或其他處理方式,下次消費時,另兩個聚合還要儲存一次。
以上就是我們聚合和同步聚合的設計。查詢時,一部分業務會先查詢快取,不存在再查詢es,如果降級,才會查庫,正常的聚合查詢都不會查到庫。
由於我們系統上線時是單庫,分庫是上線幾個月後做的技改,所以資料需要遷移,主要遷移步驟如下:
前半部分,從掃瞄到同步到分庫是新**,後面canal到同步es、聚合表都是復用上面邏輯,這樣設計,降低我們整體工作量,並且保證資料遷移完整。
具體遷移細節如下:
可以看出,主要分為兩部分,停機前和停機後。停機前是遷移歷史資料,支援重複遷移;停機後,只遷移增量部分,這樣,大大縮短我們的上線時間。停機後只需要遷移很少的資料量。
遷移就涉及到資料校驗,校驗邏輯整體來說比較簡單:
三個維度分別和基礎庫做對比,如果不同,重新遷移某一天資料。
這一部分也很重要,我們的降級主要有兩點,一是canal同步延遲降級,一是es不可用降級。第一種如下:
如果canal同步延遲,或者從庫掛掉,開啟開關,掃瞄主庫資料(最近幾小時)直接同步到es、聚合表;這樣,即使從庫掛掉,也不影響業務資料,這一點很重要,實際業務場景中我們也遇到過。
es降級,es不可用時,關閉es開關,直接查詢聚合表。
乙個系統從設計到最終完成,依賴於整個團隊,每個人的想法、不同思路的碰撞和付出;再有前期合理細緻的設計尤為重要,每個時間點和具體上線步驟和回滾方案做好詳細計畫;另外,就是細緻深入測試,測試環境和線上多輪測試和回歸,也是正常上線的重要保證。
以上就是京東一元搶寶專案分庫分表的主要思想,希望有同樣想法的朋友可以深入交流,互相提公升系統架構。
系統調優之系統架構的搭建 資料庫字段設計時的要領
系統調優之系統架構的搭建 持續補充中一.資料庫字段設計時的要領 1.數字型 一般用來記錄次數分數等等,還有一種可以用在檢索,排序,它比字元型來的快,如果你能用數字型的那就用數字型,特別是用來區分某條資料是什麼型別時用,比如我們的訂單是處於新建訂單還是同程已確認還是已結,完全可以用數字1,2,3,4,...
基於MVC架構訪問資料庫寫乙個登入系統
visual studio 2019 sql server 建立乙個mvc專案 建立資料庫 新建一對login方法,乙個用於訪問頁面,乙個用於資料互動,使用httpget和httppost進行修飾,表明每個方法的功能。在models資料夾中新建類,並新增使用者名稱和密碼兩個屬性,並對屬性進行限制,再...
MyCat 啟蒙 分布式系統的資料庫架構演變
public user selectuser public user insertuser public user selectuser public user insertuser public user selectuser public user insertuser 即使每次改動的 即使很小...