常用分庫分表方案彙總

目錄

一、數據庫瓶頸

1、IO瓶頸

2、CPU瓶頸

二、分庫分表

1、水平分庫

2、水平分表

3、垂直分庫(推薦)

4、垂直分表(不推薦)

三、分庫分表工具

四、分庫分表步驟

五、分庫分表問題

1、非partition key的查詢問題

前端上除了partition key,只有一個非partition key作爲條件查詢

前端上除了partition key,不止一個非partition key作爲條件查詢

後臺除了partition key,還有各種非partition key組合條件查詢

2、非partition key跨庫跨表分頁查詢問題

3、擴容問題

水平擴容庫(升級從庫法)

水平擴容表(雙寫遷移法)

六、分庫分表總結

七、分庫分表示例


一、數據庫瓶頸

不管是IO瓶頸,還是CPU瓶頸,最終都會導致數據庫的活躍連接數增加,進而逼近甚至達到數據庫可承載活躍連接數的閾值。在業務Service來看就是,可用數據庫連接少甚至無連接可用。接下來就可以想象了吧(併發量、吞吐量、崩潰)。

1、IO瓶頸

第一種:磁盤讀IO瓶頸,熱點數據太多,數據庫緩存放不下,每次查詢時會產生大量的IO,降低查詢速度 -> 分庫和垂直分表。

第二種:網絡IO瓶頸,請求的數據太多,網絡帶寬不夠 -> 分庫。

2、CPU瓶頸

第一種:SQL問題,如SQL中包含join,group by,order by,非索引字段條件查詢等,增加CPU運算的操作 -> SQL優化,建立合適的索引,在業務Service層進行業務計算。

第二種:單表數據量太大,查詢時掃描的行太多,SQL效率低,CPU率先出現瓶頸 -> 水平分表。

二、分庫分表

1、水平分庫

概念:以字段爲依據,按照一定策略(hash、range等),將一個庫中的數據拆分到多個庫中。

結果:

  • 每個庫的結構都一樣;
  • 每個庫的數據都不一樣,沒有交集;
  • 所有庫的並集是全量數據;

場景:系統絕對併發量上來了,分表難以根本上解決問題,並且還沒有明顯的業務歸屬來垂直分庫。

分析:庫多了,io和cpu的壓力自然可以成倍緩解。

2、水平分表

概念:以字段爲依據,按照一定策略(hash、range等),將一個表中的數據拆分到多個表中。

結果:

  • 每個表的結構都一樣;
  • 每個表的數據都不一樣,沒有交集;
  • 所有表的並集是全量數據;

場景:系統絕對併發量並沒有上來,只是單表的數據量太多,影響了SQL效率,加重了CPU負擔,以至於成爲瓶頸。

推薦文章:一次SQL查詢優化原理分析

分析:表的數據量少了,單次SQL執行效率高,自然減輕了CPU的負擔。

3、垂直分庫(推薦)

概念:以表爲依據,按照業務歸屬不同,將不同的表拆分到不同的庫中。

結果:

  • 每個庫的結構都不一樣;
  • 每個庫的數據也不一樣,沒有交集;
  • 所有庫的並集是全量數據;

場景:系統絕對併發量上來了,並且可以抽象出單獨的業務模塊。

分析:到這一步,基本上就可以服務化了。例如,隨着業務的發展一些公用的配置表、字典表等越來越多,這時可以將這些表拆到單獨的庫中,甚至可以服務化。再有,隨着業務的發展孵化出了一套業務模式,這時可以將相關的表拆到單獨的庫中,甚至可以服務化。

4、垂直分表(不推薦)

概念:以字段爲依據,按照字段的活躍性,將表中字段拆到不同的表(主表和擴展表)中。

結果:

  • 每個表的結構都不一樣;
  • 每個表的數據也不一樣,一般來說,每個表的字段至少有一列交集,一般是主鍵,用於關聯數據;
  • 所有表的並集是全量數據;

場景:系統絕對併發量並沒有上來,表的記錄並不多,但是字段多,並且熱點數據和非熱點數據在一起,單行數據所需的存儲空間較大。以至於數據庫緩存的數據行減少,查詢時會去讀磁盤數據產生大量的隨機讀IO,產生IO瓶頸。

分析:可以用列表頁和詳情頁來幫助理解。垂直分表的拆分原則是將熱點數據(可能會冗餘經常一起查詢的數據)放在一起作爲主表,非熱點數據放在一起作爲擴展表。這樣更多的熱點數據就能被緩存下來,進而減少了隨機讀IO。拆了之後,要想獲得全部數據就需要關聯兩個表來取數據。

但記住,千萬別用join,因爲join不僅會增加CPU負擔並且會講兩個表耦合在一起(必須在一個數據庫實例上)。關聯數據,應該在業務Service層做文章,分別獲取主表和擴展表數據然後用關聯字段關聯得到全部數據

三、分庫分表工具

  • sharding-sphere:jar,前身是sharding-jdbc;
  • TDDL:jar,Taobao Distribute Data Layer;
  • Mycat:中間件。

注:工具的利弊,請自行調研,官網和社區優先。

四、分庫分表步驟

根據容量(當前容量和增長量)評估分庫或分表個數 -> 選key(均勻)-> 分表規則(hash或range等)-> 執行(一般雙寫)-> 擴容問題(儘量減少數據的移動)。

推薦文章:MySQL:分庫分表與分區的區別和思考

五、分庫分表問題

1、非partition key的查詢問題

基於水平分庫分表,拆分策略爲常用的hash法。

前端上除了partition key,只有一個非partition key作爲條件查詢

映射法

基因法

注:寫入時,基因法生成user_id,如圖。關於xbit基因,例如要分8張表,23=8,故x取3,即3bit基因。根據user_id查詢時可直接取模路由到對應的分庫或分表。

根據user_name查詢時,先通過user_name_code生成函數生成user_name_code再對其取模路由到對應的分庫或分表。id生成常用snowflake算法。

前端上除了partition key,不止一個非partition key作爲條件查詢

映射法

冗餘法

注:按照order_id或buyer_id查詢時路由到db_o_buyer庫中,按照seller_id查詢時路由到db_o_seller庫中。感覺有點本末倒置!有其他好的辦法嗎?改變技術棧呢?

後臺除了partition key,還有各種非partition key組合條件查詢

NoSQL法

冗餘法

2、非partition key跨庫跨表分頁查詢問題

基於水平分庫分表,拆分策略爲常用的hash法。

注:用NoSQL法解決(ES等)。

3、擴容問題

基於水平分庫分表,拆分策略爲常用的hash法。

水平擴容庫(升級從庫法)

注:擴容是成倍的。

水平擴容表(雙寫遷移法)

  • 第一步:(同步雙寫)修改應用配置和代碼,加上雙寫,部署;
  • 第二步:(同步雙寫)將老庫中的老數據複製到新庫中;
  • 第三步:(同步雙寫)以老庫爲準校對新庫中的老數據;
  • 第四步:(同步雙寫)修改應用配置和代碼,去掉雙寫,部署;

注:雙寫是通用方案。

六、分庫分表總結

  • 分庫分表,首先得知道瓶頸在哪裏,然後才能合理地拆分(分庫還是分表?水平還是垂直?分幾個?)。且不可爲了分庫分表而拆分。
  • 選key很重要,既要考慮到拆分均勻,也要考慮到非partition key的查詢。
  • 只要能滿足需求,拆分規則越簡單越好。

七、分庫分表示例

示例GitHub地址:https://github.com/littlecharacter4s/study-sharding

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章