天天看點

詳細解讀資料庫分片技術

你的程式正在變得越來越好,它有更多的功能,更多的活躍使用者,并且每天收集更多的資料。而同時你的資料庫正在導緻程式的其餘部分變慢。資料庫分片技術可能是該問題的答案,但許多人不知道它是什麼,最重要的是,不知道何時使用它。在本文中,我們将讨論什麼是資料庫分片技術、它是如何工作的以及使用它的最佳方式。

在我們進入這個問題之前,有必要了解為什麼我們要對資料存儲進行分片,以及在開始分片之前你擁有的各種選項。

詳細解讀資料庫分片技術

資料庫分片資訊圖

當表達到特定大小時,人們通常會覺得分片是解決所有擴充問題的神奇方法。然而,我有數十億行的表,并且沒有看到一個令人信服的理由進行分片,因為我的使用模式很适合單個表并且沒有看到任何強有力的理由(除了管理這麼大的表,它在某些情況下是足夠的理由)對表進行分片。

#01什麼是資料庫分片?

簡單地說,分片是一種跨多台機器分布資料的方法。當沒有一台機器可以處理預期的工作負載時,分片就特别有必要。

分片是水準擴充的一個例子,而垂直擴充是一個越來越大的機器來支援新工作負載的例子。

詳細解讀資料庫分片技術

水準擴充

工程師們經常陷入複雜的做事方式,但随着程式的發展,盡早保持簡單會使以後面對具有挑戰性的事情時變得容易得多。是以,如果通過獲得具有更多資源的機器來解決你的問題,這是正确的答案。

我們已經讨論了潛在的伺服器架構,現在我們談談資料布局。

你也可以通過幾種方式對資料進行分區并将特定表移動到它們自己的資料庫中,這與你在微服務架構中看到的非常相似,程式的特定部分有其自身資料庫伺服器。程式知道每個資料庫該在哪裡尋找。或者,你可以跨多個資料庫節點存儲同一個表的行,這帶來了分片鍵等想法;稍後會詳細介紹。

詳細解讀資料庫分片技術

分區政策

更現代的資料庫,如 Cassandra 和其他資料庫,将分區方法從程式邏輯中抽象出來,并在資料庫級别進行維護。

#02分片前我有哪些選擇?

與任何分布式架構一樣,資料庫分片也需要花錢。設定分片、使每個分片上的資料保持最新以及確定将請求發送到正确的分片既費時又複雜。在開始分片之前,你可能想看看這些其他選項之一是否适合你。

選項 1:什麼都不做

我被問過無數次,在沒有任何明顯的瓶頸或限制因素,比如用完了可以支援工作負載的硬體,分片是否是一個好主意。我的答案是如果程式仍正常,請不要修理它。

選項 2:垂直擴充

在獲得具有更多資源的機器、添加額外的 RAM、為計算繁重的工作負載添加更多 CPU 核心以及添加額外的存儲之後,我們也可以避開分片。這些都是不需要重新設計程式和資料庫架構的選項。其他最終限制,例如帶寬(網絡或系統内部),也會迫使你進行分片。

詳細解讀資料庫分片技術

垂直擴充

選項 3:複制

如果你對資料所做的大部分工作是讀取,複制可以提高資料的可用性并加快讀取資料的速度。這可以幫助你避免資料庫分片的一些複雜性。可以通過制作更多資料庫副本來提高讀取性能。當然,假設你已經補充了緩存。這可以通過負載均衡或根據他們在世界上的位置路由查詢來完成。

但是複制使得頻繁寫入的工作負載更難處理,因為每次寫入都必須複制到每個節點。這可能因資料存儲而異,其中一些是異步執行的,而另一些可能會延遲初始寫入以確定其被複制。

WAL

WAL(預寫日志)是磁盤上的一種額外結構,隻能添加到其中。在将更改寫入資料庫之前,它們首先寫入日志,此日志必須在持久存儲上。它用于從崩潰和丢失的事務中恢複。此日志還用于支援某些資料庫(如 PostgreSQL 和 MySQL)中的複制。

詳細解讀資料庫分片技術

擴充讀取

選項 4:專業資料庫

性能不佳是因為資料庫需要對其服務的工作負載進行更好地設計。例如,将搜尋資料存儲在關系資料存儲中可能意義不大。将類似的東西移到 Elasticsearch 會更有效。将 blob 移動到像 S3 這樣的對象存儲可能是一個相當大的勝利,而不是将它們存儲在你的關系存儲中。外包此功能可能比嘗試對整個資料庫進行分片更有意義。

如果你的程式資料庫管理大量資料,需要大量讀寫,和 / 或需要始終可用,則分片資料庫可能是最佳選擇。讓我們來看看分片的優缺點。

#03必要時分片

分片可以在增加系統吞吐量、存儲容量和可用性方面為你提供幾乎無限的可擴充性。有許多更小、更容易控制的系統,每個系統都可以通過各自的副本自行擴充和縮減。

所有這些優勢都要在操作複雜性、程式開銷和支援這種新設計的基礎設施成本上進行權衡。

它是如何工作的?

在我們可以分片資料庫之前,我們需要回答幾個重要問題。你的計劃将取決于你如何回答這些問題。

  1. 我們如何跨分片分布資料?如果資料分布不均,是否存在潛在熱點(hotspots)?
  2. 我們運作哪些查詢操作,以及表如何互動?
  3. 資料将如何增長?以後需要如何重新配置設定?

術語熱點是指節點的工作負載已超過特定資源(記憶體、io 等)的門檻值。有一個有趣的例子叫做 Bieber Bug。

在我們進入下一點之前,了解以下術語很重要。

Shard Key(分片鍵)是主鍵的一部分,它告訴我們資料應該如何分布。使用分片鍵,你可以通過将操作路由到正确的資料庫來快速查找和更改資料。

同一節點包含具有相同分片鍵的條目。共享相同分片鍵的一組資料稱為邏輯分片。一個資料庫節點包含多個邏輯分片,也稱為實體分片。

詳細解讀資料庫分片技術

分離邏輯分片

最關鍵的推定也是未來最難改變的推定。邏輯分片隻能跨越一個節點,因為它是一個原子存儲單元。在分片對于單個節點來說太大的情況下,資料庫叢集實際上空間不足。

基于鍵的分片

算法分片資料庫使用哈希函數來定位資料。這允許我們給定一個特定的分片鍵來找到正确的實體分片來請求資料。

資料僅通過散列函數進行分發。它不考慮有效負載的大小或空間使用情況。當沒有合适的分區鍵時,散列的好處是允許更均勻的分布,并且如果你有合适的分區鍵,則可以即時計算位置。

詳細解讀資料庫分片技術

基于鍵的分片

如果你對确定性哈希函數感興趣,請檢視我關于該主題的 Redis 文章:

https://architecturenotes.co/redis/

這種分片政策的缺點是重新分片資料可能很困難,并且在可用的同時保持一緻性更難。

#04基于範圍的分片

在基于範圍的分片中,根據某個值的範圍将資料分成塊。

詳細解讀資料庫分片技術

基于範圍的分片

這需要一個查找表來檢視資料應該存儲在哪裡。保持此類表格的一緻性并在此處選擇範圍至關重要。

在為這種分片類型選擇分片鍵時,必須選擇一個具有高基數的分片鍵,是以該鍵的可能值的數量很多。例如,可能值為 North、South、East 和 West 的鍵的基數較低,因為隻有 4 個。此外,理想情況下,你希望在該基數内有良好的分布。

詳細解讀資料庫分片技術

均勻/不均勻分布

如果一切都落在 50% 的可能值中,你的一些分片将開始出現熱點。使用準确的資料将其作為實驗運作很容易,隻需幾行代碼即可完成。首先,選擇一個鍵和範圍并檢查潛在分布。

#05基于關系的分片

這種共享機制将相關資料儲存在一個實體分片上。例如,相關資料通常分布在關系資料庫中的多個表中。

例如,對于像 Instagram 這樣的程式,使用者和所有相關資料将被分片到同一個實體節點,其中分别包含文章和評論。通過将相關實體放在同一個分區中,你可以從單個分區中獲得更多收益。是以,在整個實體分片和更少的跨實體分片查詢中保持更強的一緻性。

跨分片事務

最後,我想總結一些複雜性的細節,當你需要進行跨多個分片的事務時,這些複雜性可能會引入。無論你計劃多少,足夠長壽命的服務或程式最終都會遇到一些跨分片事務。

這實質上意味着你需要由 ACID 相容資料庫提供的事務保證,但跨分片時資料庫不能確定這種合規性,因為你操作的資料不在啟動它的事務範圍内。

這通常被稱為全局事務,其中多個子事務需要協調并成功。作為一般規則,事務打開的時間越長,争用就越多,并且可能會發生故障。

兩階段送出

兩階段送出在理論上很簡單,但在實踐中很難執行。

  • 上司者寫入一個持久的事務記錄,訓示跨分片事務。
  • 參與者寫下他們願意承諾的永久記錄并通知上司者。
  • 上司者在收到所有響應後通過更新持久事務記錄來送出事務。(如果沒有人響應,它可以中止事務。)
  • 參與者可以在上司者宣布送出決定後顯示新狀态。(如果上司者中止事務,他們會删除暫存狀态。)

協定路徑中的讀寫放大是一個主要問題。寫入放大的發生是因為你必須寫入事務記錄并持久地進行送出,這需要每個參與者至少進行一次寫入。過多的寫入可能會導緻鎖争用和程式不穩定。資料庫必須額外過濾每次讀取,以確定它看不到任何依賴于挂起的跨分片事務的狀态,這會影響系統中的所有讀取,甚至是非事務性讀取。

#06結論

我們已經讨論了分片、何時使用它以及如何設定它。對于需要管理大量資料并使其随時可用于大量讀取和寫入的程式,分片是一種出色的解決方案。盡管如此,它還是使操作變得更加複雜。在開始實施之前,你應該考慮收益是否值得付出代價,或者是否有更直接的解決方案。