本文由雲+社區發表
作者:騰訊雲數據庫
Introduction 導言
任何看到顯著增長的應用程序或網站,最終都需要進行擴展,以適應流量的增加。以確保數據安全性和完整性的方式進行擴展,對於數據驅動的應用程序和網站來說十分重要。人們可能很難預測某個網站或應用程序的流行程度,也很難預測這種流行程度會持續多久,這就是為什么有些機構選擇“可動態擴展的”數據庫架構的原因。
在這篇概念性文章中,我們將討論一種“可動態擴展的”數據庫架構:分片數據庫。近年來,分片(Sharding)一直受到很多關注,但許多人並沒有清楚地了解它是什么,或者對數據庫進行分片可能有意義的場景。我們將討論分片是什么,它的一些主要優點和缺點,以及一些常見的分片方法。
下方是本文目錄,幫助您接下來的閱讀
What is Sharding? 什么是分片?
分片(Sharding)是一種與水平切分(horizontal partitioning)相關的數據庫架構模式——將一個表里面的行,分成多個不同的表的做法(稱為分區)。每個區都具有相同的模式和列,但每個表有完全不同的行。同樣,每個分區中保存的數據都是唯一的,並且與其他分區中保存的數據無關。
從水平切分(horizontal partitioning)與垂直切分(vertical partitioning)的關系,可能會有所幫助。在垂直切分表中,所有的列被分離出來,並放入新的不同的表中。每個垂直切分內的數據,獨立於所有其他分區中的數據,並且每個分區都包含不同的行和列。下圖說明了如何在水平和垂直方向上對表進行分區:
添加描述
分片(Sharding)將一個數據分成兩個或多個較小的塊,稱為邏輯分片(logical shards)。然后,邏輯分片(logical shards)分布在單獨的數據庫節點上,稱為物理分片(physical shards)。物理分片(physical shards)可以容納多個邏輯分片(logical shards)。盡管如此,所有分片中保存的數據,共同代表整個邏輯數據集。
數據庫分片(Database shards)是無共享架構的一個例子。這意味着分片是自治的:分片間不共享任何相同的數據或服務器資源。但是在某些情況下,將某些表復制到每個分片中作為參考表是有意義的。例如,假設某個應用程序的數據庫依賴於重量測量的固定轉換率。通過將包含必要轉換率數據的表復制到每個分片中,有助於確保查詢所需的所有數據都保存在每個分片中。
通常,分片(Sharding)在應用程序級別進行實現。這意味着應用程序包含“要向哪個分片發送讀和寫”的代碼。但是,某些數據庫管理系統內置了分片功能,允許您直接在數據庫級別實現分片。
以上是分片(Sharding)的概述,接下來讓我們來看一下,這種數據庫架構的優點和缺點。
Benefits of Sharding 分片的好處
數據庫分片的主要吸引力在於,它可以幫助促進水平擴展(horizontal scaling),也稱為向外擴展(scaling out)。水平擴展是將更多的機器添加到現有堆棧中,以分散負載,允許更多的流量和更快的處理。這通常與垂直擴展(vertical scaling)形成對比,垂直擴展也稱為向上擴展(scaling up),是指升級現有服務器的硬件,通常是添加更多內存或CPU。
讓一個關系數據庫在單個機器上運行,並按需升級其服務器資源進行向上擴展是相對簡單的。但最終,任何非分布式數據庫在存儲和計算能力方面都會受到限制,因此可以自由地水平擴展數據庫,會使您的架構更加靈活且適應性強。
選擇分片數據庫架構的另一個原因,是為了加速查詢響應的時間。當您對尚未分片的數據庫提交查詢時,必須先搜索您查詢的表中的每一行,然后才能找到您要查找的結果集。對於具有大型單片數據庫的應用程序,查詢可能變得極其緩慢。但是,通過將一個表分成多個,查詢過程會遍歷更少的行,並且返回結果集的速度要快得多。
分片還可以通過減少宕機(outage)的影響,使應用程序更穩定可靠。如果您的應用程序或網站依賴於未分片的數據庫,則宕機可能會導致整個應用程序不可用。但是,對於分片數據庫,宕機可能只會影響單個分片。即使這可能使某些用戶無法使用應用程序或網站部分功能,但仍會低於整個數據庫崩潰帶來的影響。
Drawbacks of Sharding 分片的缺點
雖然對數據庫進行分片可以使擴展更容易並提高性能,但它也可能會帶來某些限制。在這里,我們將討論其中的一些限制,以及為什么這些限制會讓我們避免對數據庫全部分片。
正確實現分片數據庫架構,是十分復雜的,所以這是分片遇到的第一個困難。如果操作不正確,則分片過程可能會導致數據丟失或表損壞,這是一個很大的風險。但是,即使正確地進行了分片,也可能對團隊的工作流程產生重大影響。與從單個入口點訪問和管理數據不同,用戶必須跨多個分片位置管理數據,這可能會讓某些團隊存在工作混亂。
在對數據庫進行分片后,用戶有時會遇到的一個問題是分片最終會變得不平衡。舉例來說,假設您有一個數據庫,其中有兩個單獨的分片,一個用於姓氏以字母A到M開頭的客戶,另一個用於名字以字母N到Z開頭的客戶。但是,您的應用程序為姓氏以字母G開頭的人提供了過多的服務。因此,A-M分片逐漸累積的數據比N-Z分片要多,這會導致應用程序速度變慢,並對很大一部分用戶造成影響。A-M分片已成為所謂的數據熱點。在這種情況下,數據庫分片的任何好處都被慢速和崩潰抵消了。數據庫可能需要修復和重新分片,才能實現更均勻的數據分布。
另一個主要缺點是,一旦對數據庫進行了分片,就很難將其恢復到未分片的架構。分片前數據庫的備份數據,都無法與分片后寫入的數據合並。因此,重建原始的非分片架構,需要將新的分區數據與舊備份合並,或者將分區的數據庫轉換回單個數據庫,這兩種方法都是昂貴且耗時的。
要考慮的最后一個缺點是,並不是每個數據庫引擎本身都支持分片。例如,盡管可以手動分片PostgreSQL數據庫,但PostgreSQL本身並不包括自動分片功能。有許多Postgres分支包括自動分片功能,但這些分支通常落后於最新的PostgreSQL版本,並且缺乏某些其他的功能特性。一些專業的數據庫技術——如MySQL Cluster或某些數據庫即服務產品(如MongoDB Atlas)確實包含自動分片功能,但這些數據庫管理系統的普通版本卻並不包含。因此,分片通常需要“自己動手”的方法。這意味着通常很難找到有關分片或故障排除技巧的文檔。
現在我們已經介紹了一些分片的缺點和好處,我們將討論一些分片數據庫的不同架構。
一旦你決定對數據庫進行分片,接下來你需要弄清楚的是如何進行分片。在運行查詢或將傳入的數據分發到分片表或數據庫時,關鍵是要將其分配到正確的分片。否則,它可能導致數據丟失或查詢速度緩慢。在本節中,我們將介紹一些常見的分片架構,每個架構使用稍微不同的流程來跨分片分發數據。
Key Based Sharding 基於鍵的分片
添加描述
為了確保數據記錄以正確的方式被放置在正確的分片中,哈希函數中輸入的值都應該來自同一列。此列稱為分片鍵。簡單來說,分片鍵與主鍵類似,因為它們都是列,用於為各個行建立唯一標識符。一般來說,分片鍵應該是靜態的,這意味着它不應包含可能隨時間變化的值。否則,它會增加更新操作的工作量,並可能降低性能。
雖然基於鍵的分片是一種相當常見的分片架構,但在嘗試動態添加或刪除數據庫中的其他服務器時,它會使事情變得棘手。在添加服務器時,每個服務器都需要一個相應的哈希值,並且許多現有條目(如果不是全部)都需要重新映射到新的正確哈希值,然后遷移到相應的服務器。當您開始重新平衡數據時,新舊哈希函數都不會有效。因此,在遷移期間,您的服務器將無法編寫任何新數據,您的應用程序可能會停機。
這種策略的主要吸引力在於,它可以用於均勻分布數據,從而防止熱點。此外,由於它以算法方式分配數據,因此無需維護所有數據所在位置的映射,而其他策略(如范圍或基於目錄的分片)必須維護數據位置的映射。
Range Based Sharding 基於范圍的分片
基於范圍的分片(Range based sharding),基於給定值的范圍進行數據分片。為了說明,假設您有一個數據庫,用於存儲零售商目錄中所有產品的信息。您可以創建一些不同的分片,並根據每個產品的價格范圍分配每個產品的信息,如下所示:
添加描述
基於范圍的分片的主要好處是,它實現起來相對簡單。每個分片都包含一組不同的數據,但它們都具有相同的模式,以及原始數據庫。應用程序代碼只讀取數據所屬的范圍,並將其寫入相應的分片。
另一方面,基於范圍的分片並不能預防數據不均勻分布的現象,而有可能會出現前面提到的數據熱點現象。查看示例圖,即使每個分片擁有相同數量的數據,特定產品比其他產品獲得更多關注的可能性也會很大。相應的,各個的分片將接收不成比例的讀取操作。
Directory Based Sharding 基於目錄的分片
要實現基於目錄的分片,必須創建並維護一個查找表,該查找表使用分片鍵來跟蹤哪個分片包含哪些數據。簡而言之,查找表是一個表,其中包含有關可以找到特定數據的靜態信息集。下圖顯示了基於目錄的分片的簡單示例:
添加描述
此處,Delivery Zone列被定義為分片鍵。將來自分片鍵的數據,連同每一行應該寫入的分片寫入查找表。這與基於范圍的分片類似,但不是確定分片鍵的數據落入哪個范圍,而是將每個鍵綁定到其自己的特定分片。如果分片鍵的基數很低,並且分片鍵存儲鍵的范圍沒有意義,那么基於目錄的分片比基於范圍的分片要更好。請注意,它也不同於基於密鑰的分片,因為它不通過散列函數處理分片鍵; 它只是根據查找表檢查鍵值,以查看數據需要寫入的位置。
基於目錄的分片的主要吸引力在於其靈活性。基於范圍的分片架構只能指定鍵值范圍,而基於鍵的分片架構只能使用固定的哈希函數,如前所述,在以后更改該函數非常困難。另一方面,基於目錄的分片允許您使用任何系統或算法將數據項分配給分片,使用這種方法動態添加分片也相對容易。
雖然基於目錄的分片是這里討論的最靈活的分片方法,但是在每次查詢或寫入之前連接到查找表,可能會對應用程序的性能產生不利影響。此外,查找表可能出現單點故障:如果查詢表損壞或出現其他故障,它可能會影響數據庫寫入新數據或訪問現有數據的能力。
Should I Shard? 我應該分片嗎?
是否應該實現分片數據庫架構,幾乎總是一個爭論的問題。有些人認為分片對於達到一定規模的數據庫來說,是不可避免的結果。而另一些人則認為這是一個令人頭疼的問題,除非絕對必要,否則應該避免,因為分片增加了操作的復雜性。
由於這種增加的復雜性,通常僅在處理非常大量的數據時才執行分片。以下是一些常見方案,可能對數據庫分片的操作有所幫助:
· 應用程序數據量增長到超過單個數據庫節點的存儲容量。
· 對數據庫的讀寫量,超過單個節點或其只讀副本可以處理的量,從而導致響應時間增加或超時。
· 應用程序所需的網絡帶寬,超過單個數據庫節點和任何只讀副本可用的帶寬,從而導致響應時間增加或超時。
在分片之前,您應該用盡所有其他選項來優化數據庫。您可能需要考慮的一些優化包括:
設置遠程數據庫。如果您使用的是一個整體應用程序,其中所有組件都位於同一個服務器上,那么可以通過將數據庫移到它自己的機器上來提高數據庫的性能。由於數據庫的表保持不變,因此這不會增加分片的復雜性。但是,它仍然允許您垂直伸縮數據庫,使其與基礎結構的其他部分分離。
實現緩存。如果您的應用程序的讀取性能導致您遇到麻煩,那么緩存是一種可以幫助改進它的策略。緩存涉及臨時存儲已在內存中請求的數據,以便您以后更快地訪問它。
創建一個或多個只讀副本。另一種有助於提高讀取性能的策略,包括將數據從一個數據庫服務器(主服務器)復制到一個或多個從服務器。在此之后,每次新的寫操作在復制到從服務器之前都要先到主服務器,而讀操作只對從服務器進行。像這樣分發讀寫可以防止任何一台機器承擔過多的負載,從而有助於防止速度下降和崩潰。請注意,創建讀副本需要更多的服務器資源,因此花費更多的錢,這對一些人來說可能是一個很大的限制。
升級到更大的服務器。在大多數情況下,將一個數據庫服務器擴展到具有更多資源的計算機比分片需要更少的工作量。與創建只讀副本一樣,具有更多資源的服務器升級可能會花費更多的錢。因此,只有當它確實是您的最佳選擇時,您才應該進行服務器擴容。
請記住,如果您的應用程序或網站增長超過某個點,這些策略本身都不足以提高性能。在這種情況下,分片可能確實是您的最佳選擇。
Conclusion 結語
對於那些希望橫向擴展數據庫的人來說,分片是一個很好的解決方案。但是,它還會增加很多復雜性,並為您的應用程序創建更多潛在的故障點。分片對於某些人來說可能是必要的,但是創建和維護分片架構所需的時間和資源可能會超過對其他人的好處。
通過閱讀這篇概念性文章,您應該更清楚地了解分片的優缺點。接下來,您可以使用這些見解來對分片數據庫架構是否適合您,做出更明智的決定。
版權聲明:本文由騰訊雲數據庫產品團隊整理,頁面原始內容來自於db weekly英文官網,若轉載請注明出處。翻譯目的在於傳遞更多全球最新數據庫領域相關信息,並不意味着騰訊雲數據庫產品團隊贊同其觀點或證實其內容的真實性。如果其他媒體、網站或其他任何形式的法律實體和個人使用,必須經過著作權人合法書面授權並自負全部法律責任。不得擅自使用騰訊雲數據庫團隊的名義進行轉載,或盜用騰訊雲數據庫團隊名義發布信息。
此文已由騰訊雲+社區在各渠道發布
獲取更多新鮮技術干貨,可以關注我們騰訊雲技術社區-雲加社區官方號及知乎機構號