天天看點

大廠原來都這麼對MySQL分庫分表!(中)5 資料庫拆分8 分庫分表的方式1 Sharding垂直切分/水準切分3 分表和分區4 分庫

5 資料庫拆分

  • 資料庫如何拆分
  • 大廠原來都這麼對MySQL分庫分表!(中)5 資料庫拆分8 分庫分表的方式1 Sharding垂直切分/水準切分3 分表和分區4 分庫

5.1 水準拆分

把一個表的資料給弄到多個庫的多個表裡,但每個庫的表結構都一樣,隻不過每個庫中表放的資料不同,所有庫表的資料加起來就是全部資料。關注點在資料的特點。

水準拆分的意義

  • 将資料均勻放更多的庫,然後用多個庫抗更高并發
  • 多個庫的存儲進行擴容

5.2 垂直拆分(拆庫)

解決問題

  • 服務不能複用
  • 連接配接數不夠

将一個資料庫,拆分成多個提供不同業務資料處理能力的資料庫,關注點在于業務相關性。

例如拆分所有訂單的資料和産品的資料,變成兩個獨立的庫,資料結構發生了變化,SQL 和關聯關系也必随之改變。

原來一個複雜 SQL 直接把一批訂單和相關的産品都查了出來,現在得改寫 SQL 和程式。

先查詢訂單庫資料,拿到這批訂單對應的所有産品 id

再根據産品 id list去産品庫查詢所有産品資訊

最後再業務代碼裡進行組裝把一個有很多字段的表給拆分成多個表或庫

每個庫表的結構都不一樣,每個庫表都包含部分字段。

一般将較少的通路頻率很高的字段放到一個表,然後将較多的通路頻率很低的字段放到另外一個表。

因為資料庫有緩存,通路頻率高的行字段越少,可在緩存裡緩存更多行,性能就越好。這個一般在表這個層面做的較多。

現有中間件都可實作分庫分表後,根據你指定的某個字段值,比如userid,自動路由到對應庫,然後再自動路由到對應表。

8 分庫分表的方式

按range分

就是每個庫一段連續的資料,一般按比如時間範圍來的,但是這種一般較少用,因為很容易産生熱點問題,大量的流量都打在最新的資料上了

  • 好處

    後面擴容的時候,就很容易,因為你隻要預備好,給每個月都準備一個庫就可以了,到了一個新的月份的時候,自然而然,就會寫新的庫了

  • 缺點

    但是大部分的請求,都是通路最新的資料。實際生産用range,要看場景,你的使用者不是僅僅通路最新的資料,而是均勻的通路現在的資料以及曆史的資料

按某字段hash

均勻分散,最為常用。

  • 可以平均配置設定沒給庫的資料量和請求壓力
  • 壞處

    擴容起來比較麻煩,會有一個資料遷移的過程

1 Sharding

把資料庫橫向擴充到多個實體節點的一種有效方式,主要是為了突破資料庫單機伺服器的 I/O 瓶頸,解決資料庫擴充問題。

Sharding可簡單定義為将大資料庫分布到多個實體節點上的一個分區方案。每一個分區包含資料庫的某一部分,稱為一個shard,分區方式可以是任意的,并不局限于傳統的水準分區和垂直分區。

一個shard可以包含多個表的内容甚至可以包含多個資料庫執行個體中的内容。每個shard被放置在一個資料庫伺服器上。一個資料庫伺服器可以處理一個或多個shard的資料。系統中需要有伺服器進行查詢路由轉發,負責将查詢轉發到包含該查詢所通路資料的shard或shards節點上去執行。

垂直切分/水準切分

MySQL的擴充方案

  • Scale Out 水準擴充

    一般對資料中心應用,添加更多機器時,應用仍可很好利用這些資源提升自己的效率進而達到很好的擴充性

  • Scale Up 垂直擴充

一般對單台機器,Scale Up指當某個計算節點添加更多的CPU Cores,儲存設備,使用更大的記憶體時,應用可以很充分的利用這些資源來提升自己的效率進而達到很好的擴充性

MySQL的Sharding政策

  1. 垂直切分:按功能子產品拆分,以解決表與表之間的I/O競争

e.g. 将原來的老訂單庫,切分為基礎訂單庫和訂單流程庫。資料庫之間的表結構不同

大廠原來都這麼對MySQL分庫分表!(中)5 資料庫拆分8 分庫分表的方式1 Sharding垂直切分/水準切分3 分表和分區4 分庫
  1. 水準切分:将

    同個表

    的資料分塊,儲存至不同的資料庫

    以解決單表中資料量增長壓力。這些資料庫中的表結構 完全相同

2.3 表結構設計案例

垂直切分

  1. 大字段

    單獨将大字段建在另外的表中,提高基礎表的通路性能,原則上在性能關鍵的應用中應當避免資料庫的大字段

  2. 按用途

例如企業物料屬性,可以按照基本屬性、銷售屬性、采購屬性、生産制造屬性、财務會計屬性等用途垂直切分

3、 按通路頻率

例如電子商務、Web 2.0系統中,如果使用者屬性設定非常多,可以将基本、使用頻繁的屬性和不常用的屬性垂直切分開

水準切分

  1. 比如線上電子商務網站,訂單表資料量過大,按照年度、月度水準切分
  2. 網站注冊使用者、線上活躍使用者過多,按照使用者ID範圍等方式,将相關使用者以及該使用者緊密關聯的表做水準切分
  3. 論壇的置頂帖,因為涉及到分頁問題,每頁都需顯示置頂貼,這種情況可以把置頂貼水準切分開來,避免取置頂文章時從所有文章的表中讀取

3 分表和分區

分表:把一張表分成多個小表;

分區:把一張表的資料分成N多個區塊,這些區塊可以在同一個磁盤上,也可以在不同的磁盤上。

3.1 分表和分區的差別

  • 實作方式
  • MySQL的一張表分成多表後,每個小表都是完整的一張表,都對應三個檔案(MyISAM引擎:.MYD資料檔案,.MYI索引檔案,.frm表結構檔案)

資料處理

分表後資料都存放在分表裡,總表隻是個外殼,存取資料發生在一個個的分表裡

分區則不存在分表的概念,分區隻不過把存放資料的檔案分成許多小塊,分區後的表還是一張表,資料處理還是自己完成。

性能

分表後,單表的并發能力提高了,磁盤I/O性能也提高了。分表的關鍵是存取資料時,如何提高 MySQL并發能力

分區突破了磁盤I/O瓶頸,想提高磁盤的讀寫能力,來增加MySQL性能

實作成本

分表的方法有很多,用merge來分表,是最簡單的一種。這種方式和分區難易度差不多,并且對程式代碼透明,如果用其他分表方式就比分區麻煩

分區實作比較簡單,建立分區表,跟建平常的表沒差別,并且對代碼端透明

3.2 分區适用場景

  1. 一張表的查詢速度慢到影響使用
  2. 表中的資料是分段的
  3. 對資料的操作往往隻涉及一部分資料,而不是所有的資料
  4. 大廠原來都這麼對MySQL分庫分表!(中)5 資料庫拆分8 分庫分表的方式1 Sharding垂直切分/水準切分3 分表和分區4 分庫

3.3 分表适用場景

  1. 頻繁插入或連接配接查詢時,速度變慢
  2. 分表的實作需要業務結合實作和遷移,較為複雜

4 分庫

分表能解決

單表資料量過大帶來的查詢效率下降

問題,但無法給資料庫的并發處理能力帶來質的提升。面對高并發的讀寫通路,當資料庫主伺服器無法承載寫壓力,不管如何擴充從伺服器,都沒有意義了。

換個思路,對資料庫進行拆分,

提高資料庫寫性能

,即分庫。

4.1 分庫的解決方案

一個MySQL執行個體中的多個資料庫拆到不同MySQL執行個體中:

大廠原來都這麼對MySQL分庫分表!(中)5 資料庫拆分8 分庫分表的方式1 Sharding垂直切分/水準切分3 分表和分區4 分庫
  • 缺陷

    有的節點還是無法承受寫壓力。

4.1.1 查詢切分

  • 将key和庫的映射關系單獨記錄在一個資料庫。
  • 大廠原來都這麼對MySQL分庫分表!(中)5 資料庫拆分8 分庫分表的方式1 Sharding垂直切分/水準切分3 分表和分區4 分庫
  • 優點

    key和庫的映射算法可以随便自定義

  • 引入了額外的單點

4.1.2 範圍切分

按某字段的區間拆分,比較常用的是時間字段。

在内容表裡有“建立時間”的字段,而我們也是按時間來檢視一個人釋出的内容。我們可能會要看昨天的内容,也可能會看一個月前釋出的内容,這時即可按建立時間的區間來分庫分表。比如可以把一個月的資料放入一張表,查詢時即可根據建立時間先定位資料存儲在哪個表,再按查詢條件查詢。

按照時間區間或ID區間切分。

大廠原來都這麼對MySQL分庫分表!(中)5 資料庫拆分8 分庫分表的方式1 Sharding垂直切分/水準切分3 分表和分區4 分庫

适用場景

一般清單資料可使用這種拆分方式。

比如一個人某時間段的訂單、釋出的内容。但這種方式可能存在明顯熱點,因為肯定會更關注最近使用者買了啥,發了啥,是以查詢的 QPS 會更多,對性能有一定影響。

使用這種拆分規則後,資料表要提前建立好,否則如果時間到了次年元旦,DBA卻忘記了建表,那麼次年的資料就沒有庫表可寫了。

  • 單表容量可控,水準擴充很友善。
  • 無法解決集中寫入的瓶頸問題。

4.1.3 Hash切分

按照某字段的哈希值做拆分,适用于實體表,比如使用者表,内容表,一般按這些實體表的 ID 字段拆分。

比如把使用者表拆分成 16 個庫,64 張表,可先對使用者 ID 做哈希将 ID 盡量打散,然後再對 16 取餘,這樣就得到了分庫後的索引值;對 64 取餘,就得到了分表後的索引值。

一般都是采用hash切分。

大廠原來都這麼對MySQL分庫分表!(中)5 資料庫拆分8 分庫分表的方式1 Sharding垂直切分/水準切分3 分表和分區4 分庫

資料水準切分後我們希望易于水準擴充,是以推薦采用mod 2^n這種一緻性Hash。

比如一個訂單庫,分庫分表方案是32*32,即通過UserId後四位mod 32分到32個庫中,同時再将UserId後四位Div 32 Mod 32将每個庫分為32個表,共計分為1024張表。

線上部署情況為8個叢集(主從),每個叢集4個庫。

大廠原來都這麼對MySQL分庫分表!(中)5 資料庫拆分8 分庫分表的方式1 Sharding垂直切分/水準切分3 分表和分區4 分庫

為什麼說這易于水準擴充?分析如下場景:

資料庫性能達到瓶頸

  1. 現有規則不變,可直接擴充到32個資料庫叢集。
大廠原來都這麼對MySQL分庫分表!(中)5 資料庫拆分8 分庫分表的方式1 Sharding垂直切分/水準切分3 分表和分區4 分庫
  1. 如果32個叢集也無法滿足需求,那麼将分庫分表規則調整為(32*2n)*(32⁄2n),可以達到最多1024個叢集。
大廠原來都這麼對MySQL分庫分表!(中)5 資料庫拆分8 分庫分表的方式1 Sharding垂直切分/水準切分3 分表和分區4 分庫

單表容量達到瓶頸

或1024都無法滿足。

大廠原來都這麼對MySQL分庫分表!(中)5 資料庫拆分8 分庫分表的方式1 Sharding垂直切分/水準切分3 分表和分區4 分庫

假如單表都突破200G,200*1024=200T

沒關系,32 * (32 * 2^n),這時分庫規則不變,單庫裡的表再裂變,當然,在目前訂單這種規則下(用userId後四位 mod)還是有極限的,因為隻有四位,是以最多拆8192個表。