電商訂單系統分庫分表


一、兩種方案分庫分表

 一般業界,對訂單數據的分庫分表,有兩類思路:按照訂單號來切分、按照用戶id來切分。

 方案一、按照訂單號來做hash分散訂單數據

   把訂單號看作是一個字符串,做hash,分散到多個服務器去。

  具體到哪個庫、哪個表存儲數據呢?訂單號里面的數字來記錄着。

  如果要查詢某用戶的所有訂單呢?

  由於是根據訂單號來分散數據的。他的訂單分散在了多個庫、多個表中。

  總不能去所有的庫,所有的表掃描吧。這樣效率很低。(解決:維護uid和oid的關系表, 此表可以作為緩存,當數據量增大時此關系表也要進行分表)

  一般使用方案二的比較多,一個用戶的所有訂單,都在一張表里面,那么做分頁展示的時候,就容易。

方案二、按照用戶id打散訂單數據

  以uid來切分數據,有兩種思路:

第一種是,某個范圍的uid訂單到哪些庫。0到2千萬uid,對應的訂單數據到a庫、a表。2千萬到4千萬對應的訂單到b庫。

  為什么這種方案用得比較少呢?

  容易出現瓶頸嗎。某個范圍內的用戶,下單量比較多,那么造成這個庫的壓力特別大。其他庫卻沒什么壓力。

第二種是,使用uid取模運算。第二種方案業界用得比較多。

  一方面、處理簡單,程序上做取模運算就好了。

  另一方面、使用取模的方式,數據比較均勻分散到多個庫去了。不容易出現單個庫性能瓶頸。

  但是不好處也有:即要擴容的時候,比較麻煩。就需要遷移數據了。

  要擴容的時候,為了減少遷移的數據量,一般擴容是以倍數的形式增加。比如原來是8個庫,擴容的時候,就要增加到16個庫,再次擴容,就增加到32個庫。這樣遷移的數據量,就小很多了。這個問題不算很大問題,畢竟一次擴容,可以保證比較長的時間,而且使用倍數增加的方式,已經減少了數據遷移量。

 

下面分析一下按照用戶id取模的方式分庫分表。

  按照用戶id作為key來切分訂單數據,具體如下:

1、 庫名稱定位:用戶id末尾4位 Mod 32。

    Mod表示除以一個數后,取余下的數。比如除以32后,余下8,余數就是8。

    代碼符號是用%表示:15%4=3。

2、表名稱定位:(用戶id末尾4位 Dev 32) Mod 32。

    Dev表示除以一個數,取結果的整數。比如得到結果是25.6,取整就是25。

    代碼用/來表示:$get_int = floor(15/4)。15除以4,是一個小數3.75,向下取整就是3。一定是向下取整,向上取整就變成了4了。

   按照上面的規則:總共可以表示多少張表呢?32個庫*每個庫32個表=1024張表。如果想表的數量小,就把32改小一些。

 

庫ID = userId % 庫數量4 
表ID = userId / 庫數量4 % 表數量8 

或者 
庫ID = userId / 表數量4 % 庫數量4 
表ID = userId % 表數量8
 

 

上面是用計算機術語來表示, 下面用通俗的話描述。

1、庫名稱計算

  用戶id的后4位數,取32的模(取模就是除以這個數后,余多少)。余下的數,是0-31之間。

  這樣可以表示從0-31之間,總共32個數字。用這個32個數字代表着32個庫名稱:order_db_0、order_db_2.........................order_db_31

2、表名稱計算

  最后要存儲定到哪個表名里面去呢?

  用戶id的最后4位數,除以32,取整數。將整數除以32,得到余數,能夠表示從0-31之間32個數字,表示表名稱。

  表名稱類似這樣:order_tb_1、order_tb_2..........................order_tb_31。一個庫里面,總共32個表名稱。

  比如用戶id:19408064,用最后4位數字8064除以32,得到是251.9,取它的整數是251。

  接着將251除以32,取余數,余數為27。

  為了保持性能,每張表的數據量要控制。單表可以維持在一千萬-5千萬行的數據。1024*一千萬。哇,可以表示很多數據了。

三、思考優點和缺點

優點

  訂單水平分庫分表,為什么要按照用戶id來切分呢?

  好處:查詢指定用戶的所有訂單,避免了跨庫跨表查詢。

   因為,根據一個用戶的id來計算節點,用戶的id是規定不變的,那么計算出的值永遠是固定的(x庫的x表)

    那么保存訂單的時候,a用戶的所有訂單,都是在x庫x表里面。需要查詢a用戶所有訂單時,就不用進行跨庫、跨表去查詢了。

缺點

  缺點在於:數據分散不均勻,某些表的數據量特別大,某些表的數據量很小。因為某些用戶下單量多,打個比方,1000-2000這個范圍內的用戶,下單特別多,

  而他們的id根據計算規則,都是分到了x庫x表。造成這個表的數據量大,單表的數據量撐到極限后,咋辦呢?

 

   總結一下:每種分庫分表方案也不是十全十美,都是有利有弊的。目前來說,這種使用用戶id來切分訂單數據的方案,還是被大部分公司給使用。實際效果還不錯。程序員省事,至於數據量暴漲,以后再說呢。畢竟公司業務發展到什么程度,不知道的,項目存活期多久,未來不確定。先扛住再說。

 

思考一、b2b平台的訂單分賣家和買家的時候,選擇什么字段來分庫分表呢?

上面討論的情況是,b2c平台。訂單的賣家就一個,就是平台自己。

b2b平台,上面支持開店,買家和賣家都要能夠登陸看到自己的訂單。

先來看看,分表使用買家id分庫分表和根據賣家id分庫分表,兩種辦法出現的問題

如果按買家id來分庫分表。有賣家的商品,會有n個用戶購買,他所有的訂單,會分散到多個庫多個表中去了,賣家查詢自己的所有訂單,跨庫、跨表掃描,性能低下。

如果按賣家id分庫分表。買家會在n個店鋪下單。訂單就會分散在多個庫、多個表中。買家查詢自己所有訂單,同樣要去所有的庫、所有的表搜索,性能低下。

所以,無論是按照買家id切分訂單表,還是按照賣家id切分訂單表。兩邊都不討好。

淘寶的做法是拆分買家庫和賣家庫,也就是兩個庫:買家庫、賣家庫。

買家庫,按照用戶的id來分庫分表。賣家庫,按照賣家的id來分庫分表。

  實際上是通過數據冗余解決的:一個訂單,在買家庫里面有,在賣家庫里面也存儲了一份。下訂單的時候,要寫兩份數據。先把訂單寫入買家庫里面去,然后通過消息中間件來同步訂單數據到賣家庫里面去。

 

買家庫的訂單a修改了后,要發異步消息,通知到賣家庫去,更改狀態。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM