內容目錄
Toggle前言
此篇 Data Replication 如何優化資料庫?- 系統設計 09 講解了資料庫複製的重要性,我們可以透過資料庫複製的技巧,優化資料庫。資料分區(Data Partitioning)則是另一個優化資料庫很重要的概念,這一篇也會深入講解資料庫分區,並且分別講解不同的分片方式(Database Sharding)。此篇文章的中文名稱,包含資料分區、資料庫分片,目前都是參照 Azure 官方文件的翻譯,不過還是建議讀者使用原文稱呼這些名詞。
資料分區 (Data Partitioning) 是什麼?
資料分區 (Data Partitioning) 是將資料庫中的資料分割成更小、更易於管理的子區塊的過程。這些子區塊稱為分區 (Partition)。資料分割可以根據多種因素進行,例如:時間、客戶 ID 或產品類別。
為何我們要進行資料分區呢?
對於任何不對擴增的系統,資料量也會持續增長,並且針對資料庫的讀寫流量也會越來越大,給傳統資料庫帶來了可擴展性壓力,因此我們可以使用資料分割,使我們能夠使用多個節點,每個節點管理整個資料的一部分。
資料分區優點
- 提高性能:通過將資料分割成較小的部分,可以更輕鬆查詢資料。這對於處理大量資料的系統尤很有幫助。
- 提高可擴展性:隨著資料量的增加,可以輕鬆地添加更多分區來儲存新資料,這可以讓資料庫可以持續擴展,而無需進行重大更改。
- 提高可用性:如果一個分區發生故障,則只有該分區中的資料會受到影響。其他分區仍可以繼續使用,這有助於降低系統的整體停機時間。
- 簡化管理:資料分區可以簡化資料庫的管理。例如:可以對每個分區單獨備份和恢復,並且可以針對每個分區優化查詢。
資料分區缺點
- 增加複雜性:資料分區會增加資料庫的複雜性。需要開發和維護分割策略,並且系統可能需要進行一些更改用來適應分割的資料。
- 增加成本:資料分區可能需要額外的硬體和軟體,並且管理分割的資料庫的成本可能更高。
分片(Sharding)
為了在多個節點之間分配流量以及負載,我們需要透過分區(Partitioning)或分片(Sharding)來對資料進行分區。我們會將大型資料集合切分成較小的資料塊,儲存在不同節點上。
不過既然是要進行分割,就是必要讓分區平衡,確保每個分區儲存大約相同數量的資料。如果分區不平衡,大多數資料庫查詢落入少數分區,會造成負載過重的分區會不甘負荷,進而會造成系統瓶頸。另外,我們也會稱這些乘載量過高的分區節點為熱點(Hotspots)。
一般來說,我們會使用以下兩種方式進行分片:垂直分片、水平分片
垂直分片(Vertical Sharding)
垂直分片(Vertical Sharding)是將不同的表格放在不同的資料庫,這個方法可能運行在不同的伺服器上。這邊我先提供其他官方文件的圖例,讓使用者可以更加明白其中的原理。
通常,垂直分片(Vertical Sharding)用來提高檢索速度,例如:Blob 所組成的表(未來也會仔細介紹有關 Blob 相關內容)。在這種情況下,具有大型文字資料或是Blob 的列,就會被拆分到不同的表中。
垂直分片(Vertical Sharding)適合手動分區,主要是因為這樣的分片方式是相對複雜的,資料庫管理者需要透過這些資料關聯性,再來決定如何分區資料。相較之下,接下來要介紹的水平分片(Horizontal Sharding),即使在動態條件下也適合自動化。

水平分片(Horizontal Sharding)
除了前者介紹的垂直分片以外,還有另一種分片方式叫做水平分片(Horizontal Sharding)。如果資料庫中,某些表(Table)太龐大並且會影響讀取/寫入效能的話,水平分片就是一個很好解決此問題的分片方式。
水平分片或分區是透過拆分資料將一張表分成多張表,並且也很好理解,假如有五百行的資料,則可以直接分成兩個資料庫,並且每一個資料庫各有兩百五十行。
我也附上圖,讓讀者更了解水平分片的概念,通常我們有以下水平分片的方式,分別是:基於鍵的分片(Key Based Sharding)、基於範圍的分片(Range Based Sharding)、基於雜湊的分片(Hash Based Sharding),這些中文翻譯是我參考騰訊技術文件的翻譯,當然正常情況我們都會使用英文作為其稱呼。

基於鍵的分片(Key Based Sharding)
基於鍵的分片(Key Based Sharding)是根據資料表中的鍵欄位將資料分割成多個分區的方法。例如:可以根據客戶 ID 將客戶資料分割成多個分區,這樣每個分區都包含特定客戶的資料。
優點
使用基於鍵的分片(Key Based Sharding)方法,好處是查詢效率很高,並且很容易實作出來,並且可以精確知道在哪裡(哪個節點,哪個分片)尋找特定範圍的鍵。
缺點
如果鍵的選擇不是正確的話,由於流量分佈不均勻,某些節點可能必須儲存更多資料。簡而言之,分片不均勻的可能性較高。

基於範圍的分片(Range Based Sharding)
基於範圍的分片(Range Based Sharding)是根據資料表中的某個範圍欄位將資料分割成多個分區。例如:可以根據價格將商品資料分割成多個分區,這樣每個分區都包含特定商品的資料。
優點
使用基於範圍的分片(Range Based Sharding)好處是分片的平衡性較好,我們也可以單純透過範圍來決定要去查找哪一個資料庫。
缺點
通常在查詢範圍較小的資料時,這樣的資料分片方式是效率較低的。

基於雜湊的分片(Hash based sharding)
基於雜湊的分片(Hash based sharding)是根據資料表中的某個欄位的值對其進行雜湊(Hash Function),然後根據雜湊結果將資料分配到不同的分區。
優點
基於雜湊的分片(Hash based sharding)的優點是平衡性非常高,並且查詢的效率也相對高。
缺點
可能存在熱點問題,也複習一下前面提到的,如果分區不平衡,大多數資料庫查詢落入少數分區,會造成負載過重的分區會不甘負荷,進而會造成系統瓶頸。另外,我們也會稱這些乘載量過高的分區節點為熱點(Hotspots)。

重新平衡分割
當資料庫查詢負載本身是不平衡的時候,會造成資料庫效能不佳,這時候我們需要去深入探究原因才有機會去修正問題,其中這些造成不平衡的原因可能包含:
- 資料的分佈並不均勻。
- 單一分區上的負載過多。
- 查詢流量增加,我們需要增加更多節點來負擔系統流量。
以下是一些可以重新平衡分割的方法:
固定數量分區(Fixed number of partitions)
在這種方法中,一開始我們在設定資料庫時,就建立固定的分區數量。正常情況,會建立比節點數量更多的分區,並將這些分區分配給節點。因此,當一個新節點加入系統時,它可以從現有節點中取出一些分區,直到這些分區被均分為止。
當然每個方法都有優、缺點。這種方法的缺點是,當每個分區的大小隨著叢集(Cluster)中資料總量增加時,也會隨之增長,因為所有分區只包含總資料的一小部分。另外,如果一個分區非常小,就會導致分區的成本過大,因為每個分區都會花費一些成本。如果分區非常大,重新平衡節點以及從節點故障中恢復的成本將會很高。選擇正確的分區數量非常重要。
動態分區(Dynamic partitioning)
動態分區(Dynamic partitioning)中,當分區的大小達到設定的值時,原本的分區就會被平均分成兩個分區。不同的分區,分配一個節點,最終,負載就會被平均分配。分區的數量會與總資料量動態的去平衡,這是動態分區的優點。
不過,動態分區有一個缺點。在同時進行資料庫的讀取以及寫入時,很難動態重新平衡。讀取和寫入期間的動態重新平衡是很複雜的,因為讀取與寫入的資料,在不同節點上移動,如果這時候進行動態平衡,就會導致衝突甚至是延遲。為了確保資料一致性和可用性,就會帶來複雜性,從而影響系統效能和可靠性。MongoDB 就是使用這種動態分區知名的資料庫之一。
如果尚不了解一致性、可用性、可靠性的讀者,可以參考這一篇文章 軟體設計非功能性特性 – 系統設計 03
請求路由(Request routing)
前面介紹了各種資料分區,不過在資料傳進資料庫之前,我們需要一個問題:當客戶端在發出請求時,系統要如何知道要連接到哪個節點?重新平衡後,分區到節點的分配會改變。如果我們想要讀取某個特定的資料庫,我們如何知道需要連接哪個IP位址才能讀取呢?這個問題也稱為服務發現(Service Discovery)。以下是解決此問題的解法:
- 允許客戶端請求網路中的任何節點。如果該節點不包含所請求的數據,則會將該請求轉發到包含相關數據的節點。
- 建立一個路由層,將所有請求傳送到路由層,再由路由層決定連接哪個節點來滿足請求。
- 客戶端已經擁有與分區相關的資訊以及哪個分區連接到哪個節點。因此,他們可以直接聯繫包含他們所需資料的節點。
ZooKeeper
如果要追蹤分散式系統中,某一些叢集(Cluster)的修改,我們可以使用一些工具,其中一個知名的工具ZooKeeper,就可以做到以上的事情。ZooKeeper 是 Apache 為分散式系統提供的分散式開源協調服務。這個工具也可以,追蹤網路中的所有映射(Mapping),每個節點都連接到 ZooKeeper 以獲取資訊。每當分區發生變化,或新增或刪除節點時,ZooKeeper 就會更新並通知路由層有關變更的資訊。 ZooKeeper 被 Yelp、RackSpace、Yahoo!、Reddit、Facebook 和 Twitter 等公司使用。
結論
資料分區是一種將資料庫中的資料分割成更小、更易於管理的子集的技術,可以提高資料庫的性能、可擴展性、可用性和可管理性。
當資料庫查詢負載不平衡時,需要重新平衡分割以提高資料庫性能。重新平衡分割的過程通常涉及識別不平衡的分割、制定重新平衡計劃和執行重新平衡計劃等步驟。
對於目前所有的分散式系統來說,分區已經成為標準,並且也是大部分軟體工程師都需要知道的知識之一。也因為系統的資料量不斷增加,因此對資料進行分區很有意義,它可以加快寫入和讀取速度,進一步提高系統的可用性、可擴展性和效能。
相關文章
Data Replication 如何優化資料庫?- 系統設計 09
系統設計元件介紹 Building Block – 系統設計 05
Back-of-the-envelope 封底計算 – 系統設計 04