1. 最終一致性 1.1. 在一些應用領域,通常談論的是銀行和金融行業,最終一致性根本不合適 1.2. 事實上,最終一致性在銀行業已經使用了很多年 1.2.1. 支票需要幾天時間才能在你的賬戶上進行核對,而且你可以輕鬆地開出比賬戶餘額多的支票 1.2.2. 當處理檢查並建立一致性後,你才能看到一些後 ...
1. 最終一致性
1.1. 在一些應用領域,通常談論的是銀行和金融行業,最終一致性根本不合適
1.2. 事實上,最終一致性在銀行業已經使用了很多年
-
1.2.1. 支票需要幾天時間才能在你的賬戶上進行核對,而且你可以輕鬆地開出比賬戶餘額多的支票
-
1.2.2. 當處理檢查並建立一致性後,你才能看到一些後果
1.3. 在過去的好日子里,系統的所有數據項都有一個單一的真實來源,即資料庫,不存在副本一致性的問題,因為根本沒有副本
1.4. 為了保證每個節點的數據高可用,還需要對每個節點的內容進行複製,以消除單點故障
-
1.4.1. 當資料庫節點和網路快速且可靠地工作時,用戶不知道他們正在與分散式系統交互
-
1.4.2. 副本似乎是即時被更新的,同時用戶請求的處理響應時間很短
-
1.4.2.1. 不一致的讀取很少見
-
1.4.3. 出現故障意味著你的資料庫副本保持不一致的時間可能比你的應用程式能容忍的時間更長
1.5. 不一致視窗
-
1.5.1. 最終一致系統中的不一致視窗是數據對象被更新並傳播到所有副本所需的持續時間
-
1.5.2. 在領導者-追隨者模式的系統中,領導者協調其他副本進行更新
-
1.5.3. 在無領導系統中,任何副本(或者是任何資料庫節點——這取決於實現)都會協調更新
-
1.5.4. 當所有副本都具有相同的值時,不一致視窗結束
-
1.5.5. 影響不一致視窗持續時間的因素
-
1.5.5.1. 副本數目
> 1.5.5.1.1. 副本越多,需要協調的副本更新就越多
> 1.5.5.1.2. 只有當所有副本都相同時,不一致視窗才會關閉
> 1.5.5.1.3. 擁有的副本越多,不一致視窗受個別響應緩慢的副本影響而導致視窗延長的可能性就會增加
- 1.5.5.2. 運維環境
> 1.5.5.2.1. 任何瞬時操作故障,例如瞬時網路故障或數據包丟失,都會延長不一致視窗
> 1.5.5.2.2. 副本存在更新延遲的主要原因可能是節點上的大量讀/寫工作負載
> 1.5.5.2.2.1. 導致副本過載並產生額外的數據傳播延遲
> 1.5.5.2.3. 資料庫承受的負載越多,不一致視窗可能就越長
- 1.5.5.3. 副本之間的距離
> 1.5.5.3.1. 如果所有副本都在同一個區域網子網上,通信延遲可能是亞毫秒級的
> 1.5.5.3.2. 只要有一個副本跨越大陸或世界各地,不一致視窗的最小值都將是副本之間的往返時間
- 1.5.5.4. 所有這些問題都意味著你無法控制不一致視窗的持續時間
1.6. 讀寫一致性
-
1.6.1. 讀寫一致性是系統的一個屬性,它確保如果客戶端對數據進行持久更改,更新後的數據值由同一客戶端的任何後續讀取返回
-
1.6.2. 不一致視窗期間客戶端有可能的情況
-
1.6.2.1. 發佈對資料庫數據對象鍵的更新
-
1.6.2.2. 對相同的資料庫對象鍵發出後續讀取操作,由於它訪問的是一個副本,未保留最近的更新,導致訪問到過時的數據
-
1.6.3. 採用領導者-追隨者副本時,實現讀寫一致性很簡單
-
1.6.3.1. 對於要求讀寫一致性的用例,你只需確保後續讀取由領導者副本處理
> 1.6.3.1.1. 可以保證讀取的是最新的數據對象值
-
1.6.4. MongoDB的預設行為是通過訪問主副本實現
-
1.6.5. 在Neo4j集群中,所有寫入操作都由領導者處理,領導者非同步更新只讀的副本
-
1.6.5.1. 讀取操作可能由副本處理
1.7. 最終一致資料庫廣泛應用於大型系統中
-
1.7.1. 線上博彩和游戲行業依賴於高可用性和低延遲
-
1.7.2. 寫入Riak KV的數據自動寫入跨全球分散式集群的多個副本,具有可調節一致性,以便用戶訪問靠近其物理位置的副本來提供高可用性和低延遲
1.8. 最終一致資料庫已經成為可擴展分散式系統領域的一個既定部分
-
1.8.1. 簡單的、可演化的數據模型通過自然分區和複製來實現可擴展性和可用性,為許多互聯網規模的系統提供了出色的解決方案
-
1.8.2. 最終一致資料庫難免為系統提供過時的數據
-
1.8.3. 大多數資料庫都提供可調節一致性,允許系統設計人員平衡讀取和寫入的延遲,並權衡可用性和一致性以滿足應用程式需求
-
1.8.4. 對資料庫中不同副本的同一對象的併發寫入會導致衝突
2. 可調節一致性
2.1. 許多最終一致的資料庫允許你通過配置選項和API參數來定製資料庫的最終一致行為,可以根據用例能容忍的副本最終一致性級別來權衡讀寫操作的性能
2.2. 可調節一致性基於要完成資料庫請求必須訪問的特定副本數
3. 讀取和寫入仲裁
3.1. 法定數仲裁是多數副本,即(N/2)+1
3.2. 對於三個副本,法定數仲裁意味著寫入必須在兩個副本上成功,而讀取必須訪問兩個副本
3.3. 仲裁的直觀表現是,始終在大多數副本中讀取和寫入,讀取請求將看到資料庫對象最新版本的值
3.4. 如果法定數的節點不可用,寫入和讀取將失敗
3.5. 寬鬆仲裁(sloppy quorum)
-
3.5.1. 寬鬆仲裁第一次出現在Amazon的早期Dynamo論文的描述中,併在DynamoDB、Cassandra、Riak和Voldemort多個資料庫中實現
-
3.5.2. 如果副本節點不可用而導致寫入操作無法達到給定的法定數,則將更新臨時存儲在另一個可訪問的節點上
4. 副本修複
4.1. 在分散式、自我複製資料庫中,你希望每個副本都是一致的
4.2. 系統會隨著時間的推移趨向於熵(無序)
- 4.2.1. 資料庫需要採取積極措施來確保副本保持一致,這些措施統稱為反熵修複
4.3. 主動修複
-
4.3.1. 在訪問對象時應用程式的主動修複
-
4.3.2. 主動修複對於頻繁讀取的資料庫對象有效
-
4.3.3. 主動副本修複也稱為讀取修複,是在響應資料庫讀取請求時發生的
-
4.3.4. 如果有任何值不一致,協調器將向副本發回最新值以更新過時的值
-
4.3.5. 讀取修複的工作方式取決於資料庫實現
4.4. 被動修複
-
4.4.1. 對於不常訪問的對象(很可能是你的絕大多數數據),使用被動修複策略
-
4.4.2. 被動反熵修複通常是一個定期運行的進程,旨在修複不常訪問的副本
-
4.4.3. 構建Merkle樹是一種CPU和記憶體密集型操作,該操作要麼按需啟動(由管理工具啟動),要麼定期安排
5. 衝突處理
5.1. 在無領導系統中,寫入操作可以由任何副本處理
5.2. 最後寫入者勝出
-
5.2.1. 決定最終值的一種方法是使用時間戳
-
5.2.2. 為更新請求生成一個時間戳,資料庫確保併發寫入發生時,具有最新時間戳的更新成為最終版本
-
5.2.3. 機器上的時鐘會漂移
-
5.2.3.1. 更新請求由兩個或多個獨立進程在不同副本上的同一數據對象執行
-
5.2.3.2. 這些更新必須被視為同時的或併發的
-
5.2.3.3. 附加到更新請求的時間戳只是施加了任意順序來解決衝突罷了
-
5.2.4. 使用最後寫入者勝出策略來解決衝突,數據丟失是不可避免的
-
5.2.5. 在資料庫中安全地使用純粹的最後寫入者勝出策略的唯一方法是確保所有寫入都使用唯一鍵存儲數據對象,並且對象在後續操作中是不可變的
-
5.2.5.1. 對資料庫中數據的任何更改都需要讀取現有數據對象,並使用新鍵將新內容寫入資料庫
5.3. 版本向量
-
5.3.1. 每個唯一的資料庫對象都與版本號一起存儲
-
5.3.2. 如果寫入的版本號與資料庫對象版本不匹配,則發生衝突,資料庫必須採取補救措施以確保數據不丟失
-
5.3.3. 管理版本向量是資料庫的責任
-
5.3.3.1. 資料庫客戶端只需要提供帶有更新的最新版本,併在衝突發生時進行處理
-
5.3.4. 邏輯時鐘
-
5.3.4.1. CPU測量的物理時間在分散式系統中不是可靠的時間來源
-
5.3.4.2. Leslie Lamport在他的開創性論文中首次提到了邏輯時鐘
> 5.3.4.2.1. 這項工作的本質是happens-before關係的定義
> 5.3.4.2.2. 如果一個進程發生操作a(例如,一個資料庫請求),併在它完成後發生操作b,則a happens-before b。這由a→b表示
> 5.3.4.2.3. 如果一個進程向另一個進程發送消息m,則發送發生在接收之前,即發送happens-before接收
> 5.3.4.2.4. 如果兩個獨立的進程執行操作a→b和c→d,則無法定義{a,b}和{c,d}之間的順序
> 5.3.4.2.5. 關係happens-before是可傳遞的,如果a→b和b→c,則a→c
- 5.3.4.3. 系統可以使用邏輯時鐘捕獲happens-before關係,使用簡單的計數器和演算法達成
> 5.3.4.3.1. 每個進程都有一個本地時鐘,進程啟動時將其初始化為零
- 5.3.4.4. Lamport時鐘定義了部分事件之間的順序,然而它無法辨別沒有因果關係的併發請求
> 5.3.4.4.1. 它不能用於檢測資料庫衝突
> 5.3.4.4.1.1. 這便是版本向量的使用場景了
-
5.3.5. Redis、Cosmos DB和Riak等資料庫正在利用研究社區的最新成果來支持名為CRDT(無衝突數據副本類型)的數據類型集合
-
5.3.5.1. CRDT的一個簡單示例是一個可用於維護社交媒體網站上用戶的關註者數量的計數器