1. 引言
鍵值存儲,也稱為鍵值數據庫,是一種非關係型數據庫。它通過鍵值對的方式存儲數據,每個鍵都是唯一的,可以快速地通過鍵訪問到對應的值。鍵值存儲在現代應用中非常廣泛,如緩存、消息隊列、分佈式系統等。本文將詳細介紹鍵值存儲的設計原理、核心概念、技術實現以及應用場景。
2. 鍵值存儲的基本概念
2.1 鍵值對
鍵值存儲的核心是鍵值對,每個鍵都是唯一的,與之關聯的值可以通過鍵快速訪問。鍵可以是純文本或哈希值,通常為了性能考慮,鍵的長度越短越好。值可以是字符串、列表、字典等,通常被視為不透明對象。
2.2 鍵值存儲的特點
- 高性能:鍵值存儲通過鍵直接訪問值,具有非常高的讀寫性能。
- 高可用性:通過數據複製和分佈式架構,鍵值存儲可以在節點故障時繼續提供服務。
- 高可擴展性:鍵值存儲可以根據流量自動擴展,支持大數據集。
- 靈活的數據模型:鍵值存儲不需要預定義數據模式,可以存儲任意類型的數據。
3. 單服務器鍵值存儲
在單個服務器上開發鍵值存儲相對簡單,通常使用哈希表將鍵值對存儲在內存中。然而,由於內存空間的限制,單個服務器的存儲能力有限。為了在單個服務器上存儲更多數據,可以採用以下優化策略:
- 數據壓縮:通過壓縮算法減少數據的存儲空間。
- 緩存策略:僅在內存中存儲頻繁使用的數據,其餘數據存儲在磁盤上。
儘管有這些優化,單個服務器仍然可能很快達到其容量限制,因此需要分佈式鍵值存儲來支持更大的數據集。
4. 分佈式鍵值存儲
分佈式鍵值存儲將鍵值對分佈在多個服務器上,通過分佈式架構實現高可用性、高可擴展性和高性能。在設計分佈式系統時,瞭解CAP定理非常重要。
4.1 CAP定理
CAP定理指出,分佈式系統不可能同時提供超過以下三個保證中的兩個:一致性、可用性和分區容忍。
- 一致性:所有客户端看到相同的數據,無論他們連接到哪個節點。
- 可用性:任何請求數據的客户端即使在某些節點宕機時也能獲得響應。
- 分區容忍:系統在網絡分區的情況下繼續運行。
根據CAP定理,分佈式鍵值存儲系統通常分為以下兩類:
- AP系統:支持可用性和分區容忍,同時犧牲一致性。
- CP系統:支持一致性和分區容忍,同時犧牲可用性。
4.2 系統組件
構建鍵值存儲需要考慮以下核心組件和技術:
- 數據分區:將數據分成更小的分區,分佈在多個服務器上。
- 數據複製:為了實現高可用性和可靠性,數據必須在多個服務器上異步複製。
- 一致性:通過法定人數共識等機制保證讀寫操作的一致性。
- 不一致性解決:通過版本控制和向量時鐘等技術解決數據複製中的不一致性。
- 處理故障:通過故障檢測和數據恢復機制處理節點故障。
- 系統架構圖:描述系統的整體架構和各個組件的交互。
- 寫路徑:描述寫操作的流程。
- 讀路徑:描述讀操作的流程。
5. 數據分區
對於大型應用程序,將完整數據集放入單個服務器中是不切實際的。實現這一點的最簡單方法是將數據分成更小的分區,並在多個服務器中存儲它們。分區數據時有兩個挑戰:
- 均勻分佈數據:在多個服務器之間均勻分佈數據。
- 最小化數據移動:在添加或刪除節點時最小化數據移動。
一致性哈希是一種解決這些問題的技術。服務器被放置在一個哈希環上,鍵被哈希到同一個環上,並存儲在遇到的第一個服務器上,按順時針方向移動。
6. 數據複製
為了實現高可用性和可靠性,數據必須在N個服務器上異步複製。這些N個服務器是根據以下邏輯選擇的:在鍵被哈希到哈希環上的一個位置後,按順時針方向走,選擇環上的第一個N個服務器來存儲數據副本。
使用虛擬節點,環上的前N個節點不一定由少於N個物理服務器擁有。為了避免這個問題,我們只選擇執行時鐘邏輯的唯一服務器。為了更好的可靠性,副本被放置在不同的數據中心,並且數據中心通過高速網絡連接。
7. 一致性
由於數據在多個節點上覆制,必須在副本之間同步。Quorum共識可以保證讀寫操作的一致性。N表示副本的數量,W表示寫操作成功的寫入法定人數,R表示讀取操作成功的讀取法定人數。
- W = 1:寫操作只需等待一個副本的確認,操作會很快返回。
- R = 1:讀操作只需等待一個副本的響應,操作會很快返回。
- W + R > N:強一致性得到保證,因為必須至少有一個重疊節點擁有最新數據以確保一致性。
根據要求,我們可以調整W、R、N的值以實現所需的一致性水平。
8. 一致性模型
在設計鍵值存儲時,一致性模型是另一個重要的考慮因素。一致性模型定義了數據一致性的程度,以及可能存在的一致性模型的廣泛範圍:
- 強一致性:任何讀取操作返回與最近更新寫入數據相對應的值。
- 最終一致性:後續讀取操作可能會返回過時的數據。
- 因果一致性:特定形式的弱一致性。給定足夠的時間,所有更新都是一致的。
- 線性一致性:這是強一致性的特定形式。
Dynamo和Cassandra採用最終一致性,這是我們推薦的鍵值存儲的一致性模型。最終一致性允許不一致性與版本控制共存。
9. 不一致性解決/版本控制
複製提高了可用性,但也會引起不一致性。版本控制意味着將每次數據修改視為新不可變版本。向量時鐘是一種常見的解決此問題的技術。向量時鐘是一個與數據項相關聯的<服務器,版本>對,可以用來檢查一個版本是否在另一個版本之前、之後或與之衝突。
使用向量時鐘,可以輕鬆判斷版本X是否是版本Y的祖先(即沒有衝突)或版本Y是否與版本X衝突。向量時鐘的大小可能會迅速增長,為了解決這個問題,我們為向量長度設置了一個閾值,如果超過該閾值,則刪除最舊的對。
10. 處理故障
與任何大型系統一樣,故障不僅不可避免,而且很常見。在本節中,我們首先介紹處理故障的一般策略。然後,我們討論常見的故障處理策略。
10.1 故障檢測
在分佈式系統中,僅依賴一個服務器的説法是不夠的。通常,需要至少兩個獨立的信息源來標記服務器為宕機。Gossip協議是一種去中心化故障檢測方法。每個節點維護一個包含成員ID和心跳計數器的節點成員列表,定期將心跳發送到一組隨機節點。如果心跳在預定時間內沒有增加,則認為成員離線。
10.2 處理臨時故障
在嚴格的法定人數要求中,讀取和寫入操作可能會被阻止。一種稱為“鬆弛法定人數”的技術用於提高可用性。系統選擇前W個健康服務器進行寫入,前R個健康服務器進行讀取。忽略離線服務器。如果由於網絡故障服務器暫時不可用,另一台服務器將處理請求。當離線服務器恢復時,更改將被推送以實現數據一致性。此過程稱為隱式交接。
10.3 處理永久故障
如果副本永久不可用怎麼辦?為了處理這種情況,我們實現了一種稱為反熵協議的協議來保持副本同步。反熵涉及在副本之間交換數據並更新每個副本到最新版本。Merkle樹用於不一致性檢測和最小化數據傳輸量。
11. 處理數據中心故障
數據中心故障可能由電源故障、網絡故障、自然災害等引起。為了構建能夠處理數據中心故障的系統,重要的是在多個數據中心複製數據。如果一個數據中心完全離線,用户仍然可以通過其他數據中心訪問數據。
12. 系統架構圖
架構的主要特點如下:
- 客户端通過簡單的API:get(key)和put(key, value)與鍵值存儲通信。
- 協調器是客户端和鍵值存儲之間的代理節點。
- 節點分佈在使用一致性哈希的環上。
- 系統完全去中心化,因此添加和移動節點可以自動化。
- 數據在多個節點上覆制。
- 沒有單點故障,因為每個節點具有相同的一組職責。
13. 寫路徑
寫請求被持久化到提交日誌文件中,數據保存在內存緩存中。當內存緩存已滿或達到預定義閾值時,數據被刷新到磁盤上的SSTable。SSTable是一個按鍵排序的列表<key, value>對。
14. 讀路徑
在讀取請求指向特定節點後,它首先檢查內存緩存中的數據。如果是,則數據返回給客户端。如果數據不在內存中,它將從磁盤檢索。Bloom過濾器通常用於解決此問題。當數據不在內存中時的讀取路徑如下:
- 系統首先檢查數據是否在內存中。如果不在,請轉到步驟2。
- 如果數據不在內存中,系統檢查Bloom過濾器。
- 使用Bloom過濾器來找出可能包含鍵的SSTables。
- SSTables返回數據集的結果。
- 數據集的結果返回給客户端。
15. 總結
本章涵蓋了許多概念和技術。為了刷新您的記憶,以下表格總結了分佈式鍵值存儲中使用的特徵和相應技術:
| 目標/問題 | 技術 |
|---|---|
| 能夠存儲大量數據 | 使用一致性哈希在服務器之間分散負載 |
| 高可用性讀取 | 多數據中心設置 |
| 高可用性寫入 | 版本控制和向量時鐘 |
| 數據集分區 | 一致性哈希 |
| 增量可擴展性 | 一致性哈希 |
| 異構性 | 一致性哈希 |
| 可調一致性 | 法定人數共識 |
| 處理臨時故障 | 鬆弛法定人數和隱式交接 |
| 處理永久故障 | Merkle樹 |
| 處理數據中心故障 | 跨數據中心複製 |
通過以上內容的學習,我們對鍵值存儲的設計原理、核心概念、技術實現以及應用場景有了全面的瞭解。鍵值存儲在現代應用中具有重要的地位,掌握其設計和實現方法對於構建高性能、高可用性和高可擴展性的系統非常有幫助。
參考資料
ByteByteGo