一. 大綱
在談論數據庫架構和數據庫優化的時候,我們經常會聽到分庫分表
、分區
、分片(Sharding)
等關鍵詞,對於這些概念,相信大家應該都有聽說過或是瀏覽過相關的文檔,我們今天就來詳細了解下這幾個比較容易混淆的概念。
首先呢,我們需要知道上述的這些方案都是為了同一個目的
而產生,那就是為了突破單表/庫過大
或單節點數據庫服務器
的性能瓶頸,解決數據庫的擴展性問題。
因為隨着表數據量的增長,單機數據庫的資源和處理能力有限,所以數據庫非常容易成為應用系統的瓶頸。
二. 分庫
垂直分庫
在微服務
盛行的今天已經非常普及了,基本的思路就是按照業務模塊
來划分出不同的數據庫,而不是像早期一樣將所有的數據表都放到同一個數據庫中。
系統層面的服務化
拆分能夠解決業務系統層面的耦合
與性能瓶頸
,有利於系統的擴展維護。
而數據庫層面的數據拆分,道理其實也是相通的,可以更加便於數據庫的管理、維護、監控、擴展
等。
垂直分庫
可以在一定程度上解決數據庫單機瓶頸,因為可以將不同的業務庫分散在不同的服務器上,獨享資源,互不干擾,但是一定要了解清楚拆分的原則與技巧,否則會遇到很多問題,例如:跨庫JOIN
、分布式事務
等。
三. 分表
分表
就是將一張大表
拆分成N個子表
,根據切分規則,通常由如下兩種模式:
-
垂直拆分:基於
列
拆分表,將表中的某些字段拆分出去放入到擴展表
中。 -
水平拆分:基於
行
拆分表,通過規則匹配分類后,將數據放到若干個子表
中。
3.1. 垂直分表
垂直分表
在日常開發和設計中比較常見,通俗的說法叫做大表拆小表
,拆分是基於關系型數據庫中的列(字段)
進行的。
通常情況下,當某個表中的字段比較多時,可以新建一張擴展表
,將不經常使用或者長度較大的字段拆分出去。
垂直分表的作用比較有限,它只可以減少行數據大小,加快數據檢索的速度,但是無法解決因為表數據量增長而導致的壓力。
表字段拆分(垂直分表)
建議在數據庫設計階段就做好,如果是在發展過程中拆分,則需要改寫以前的查詢語句,會額外帶來一定的成本和風險。
3.2. 水平分表
水平分表
也稱為橫向分表
,就是將表中不同的數據行按照一定規律分布到不同的數據庫表中(這些表保存在同一個數據庫中
),以此來降低單表數據量,優化查詢性能。
這種同庫下水平分表通常有以下幾張方式:
-
冷熱數據分離:
-
定期將使用較少的歷史數據遷移到對應的歷史表中,減少原表的數據量。
-
-
業務分表:
-
在代碼層面實現分表,數據庫中存在多張子表,但在應用上層表現為一張表。
-
-
分區表:
-
通過數據庫自帶的分區表功能實現分表,邏輯上表現為一張表,但是底層存儲在不同的分區上。
-
水平分表
能夠降低單表的數據量(分區表必須要帶上分區條件才可以提前過濾
),一定程度上緩解查詢性能瓶頸。但本質上這些表還是保存在同一個庫,或者說同一個數據庫實例、同一個DB服務器中,所以無法避免單機數據庫性能瓶頸的問題。
四. 分片
分片
也叫做Sharding
,或是水平分庫分表
,都是相同的概念,與上面所講到的水平分表的概念類似,唯一不同點
就在於將這些拆分出來的子表保存在不同的數據庫服務器
中。
常見分片策略
:
-
RANGE:按照范圍划分,比如按照日期或者自增鍵進行范圍划分。
-
HASH: 采用 hash+mod 的組合划分數據。
分片實現方式
:
-
客戶端:
-
在客戶端實現分片,如比較流行的
分庫分表框架Sharding-JDBC
,就是在驅動層
實現了分片功能,對上層應用保持透明。
-
-
中間層:
-
通過在應用與DB之間接入
中間件(Proxy)
,如DBLE、MaxScale等開源中間件,用於實現后端數據分片與路由查詢,對上層應用保持透明。
-
-
服務端:
-
使用某些
分布式數據庫
,如TiDB、SequoiaDB等開源NewSQL,其在存儲引擎層
實現了數據分片功能,對上層應用保持透明。
-
分片能夠有效的緩解單機、單庫、單表的性能瓶頸,突破IO、連接數、硬件資源等瓶頸。但是我們一旦將數據分片后,那么整個數據庫架構就轉換成了分布式架構
,也會引發諸多問題:
-
分布式事務
:-
數據分片后,原先的
本地事務
就演變成了分布式事務
了,一般需要通過二階段或三階段提交
來保證分布式事務的ACID特性,性能也因此會有一定損耗。
-
-
跨庫join
:-
分庫分表后,不同的表分布在不同的服務器上,所以無法直接通過sql join來進行查詢,這時候通常會建立
冗余字段
或全局表
來實現跨庫join。
-
-
SQL問題
:-
數據分片后,SQL的運行需要分發到各個節點計算,然后將結果合並后再返回,
性能會有所下降
,並且當SQL較為復雜時,結果准確性
也有可能出現問題。這個問題也是數據分片實現中最為關鍵的點,只能不斷優化完善,無法完全解決。
-
-
自增主鍵
:-
數據分片后,我們將不能再依賴數據庫自身的自增鍵生成機制,需要配置額外的
全局序列
來保證自增主鍵的全局唯一。
-
五. 小結
需要注意的是,分片(Sharding)
會為數據庫維護和業務邏輯帶來一系列復雜性和性能損耗,所以除非業務量大到萬不得已,否則切莫過度設計
、過早優化
。
面對數據庫性能問題,我們可以先嘗試用以下方式來解決:
-
數據優化:優化SQL、索引及相關數據庫參數配置。
-
硬件擴展:提升服務器CPU、內存、磁盤IOPS等硬件配置。
-
讀寫分離:通過讀寫分離架構提高數據庫的整體性能。
-
數據拆分:通過垂直拆分庫表,或水平分表來解決大表性能問題
如果上述方式仍未能奏效,才考慮最復雜的方案:數據分片