1.3 最終一致性
在上一個文檔「為什麼選擇CouchDB?」中,我們看到CouchDB的靈活性使我們能夠隨著應用程式的增長和變化而發展數據。在本主題中,我們將探討CouchDB的「細化」工作如何提高應用程式的簡單性,並幫助我們自然地構建可擴展的分布式系統。
1.3.1 與Grain合作
分布式系統是可以在廣泛的網絡上穩定運行的系統。網絡計算的一個特殊功能是網絡連結可能會消失,並且有許多策略可以管理這種類型的網絡分段。 CouchDB與其他資料庫的不同之處在於,它接受最終的一致性,而不是像RDBMS或Paxos這樣在原始可用性之前放置絕對一致性。這些系統的共同點是認識到,當許多人同時訪問數據時,數據的行為會有所不同。在優先考慮一致性,可用性或分區容忍的哪些方面時,他們的方法有所不同。
工程分布式系統是棘手的。隨著時間的推移,您將要面對的許多警告和「陷阱」並不是立即顯而易見的。我們還沒有所有解決方案,而且CouchDB並非萬能藥,但是當您使用CouchDB的精髓而不是反對時,阻力最小的途徑將使您自然地擴展應用程式。
當然,構建分布式系統僅僅是開始。一個僅擁有一半時間可訪問資料庫的網站幾乎一文不值。不幸的是,傳統的關係數據庫一致性方法使應用程式程式設計師很容易依賴全局狀態,全局時鐘和其他高可用性,甚至沒有意識到自己正在這樣做。在研究CouchDB如何提高可伸縮性之前,我們將研究分布式系統面臨的約束。當我們看到了當您的應用程式的各個部分無法相互依賴時會出現的問題之後,我們將看到CouchDB提供了一種直觀且有用的方式來圍繞高可用性對應用程式進行建模。
1.3.2 CAP定理
CAP定理描述了用於在網絡之間分布應用程式邏輯的幾種不同策略。 CouchDB的解決方案使用複製在參與的節點之間傳播應用程式更改。這是與共識算法和關係數據庫根本不同的方法,共識算法和關係數據庫在一致性,可用性和分區容忍度的不同交集處運行。
CAP定理,如圖1所示。CAP定理確定了三個不同的問題:
- 一致性:即使並發更新,所有資料庫客戶端也可以看到相同的數據。
- 可用性:所有資料庫客戶端都可以訪問某些版本的數據。
- 分區容限:資料庫可以拆分到多個伺服器上。
選擇兩個。
當系統增長到足以使單個資料庫節點無法處理施加在其上的負載時,明智的解決方案是添加更多伺服器。添加節點時,我們必須開始考慮如何在它們之間分區數據。我們有幾個共享完全相同數據的資料庫嗎?我們是否將不同的數據集放在不同的資料庫伺服器上?我們是否只允許某些資料庫伺服器寫入數據,而讓其他伺服器處理讀取?
無論採用哪種方法,我們都會遇到的一個問題是使所有這些資料庫伺服器保持同步。如果您將某些信息寫入一個節點,那麼如何確保對另一台資料庫伺服器的讀取請求反映了此最新信息?這些事件可能相隔毫秒。即使只有少量的資料庫伺服器,此問題也會變得非常複雜。
當絕對至關重要的是,所有客戶端都必須看到一致的資料庫視圖時,一個節點的用戶將必須等待其他任何節點達成協議,才能讀取或寫入資料庫。在這種情況下,我們看到可用性在一致性方面倒退了。但是,在某些情況下,可用性比一致性要好:
系統中的每個節點都應該能夠純粹基於本地狀態做出決策。如果您需要在高負載下做某事且發生故障並且需要達成協議,那麼您會迷失方向。如果您擔心可擴展性,那麼任何迫使您達成協議的算法最終都會成為瓶頸。以此為前提。
—亞馬遜首席技術官兼副總裁沃納·沃格斯(Werner Vogels)
如果優先考慮可用性,我們可以讓客戶端將數據寫入資料庫的一個節點,而無需等待其他節點達成協議。如果資料庫知道如何照顧節點之間的這些操作,那麼我們將獲得某種「最終一致性」,以換取高可用性。對於許多應用來說,這是一個令人驚訝的適用折衷。
與傳統的關係數據庫不同,傳統的關係數據庫必須對每個執行的操作進行資料庫範圍的一致性檢查,而CouchDB使得構建應用程式變得非常簡單,而這些應用程式卻犧牲了即時一致性,以簡化簡單分髮帶來的巨大性能提升。
1.3.3 本地一致性
在嘗試了解CouchDB如何在群集中運行之前,重要的是我們了解單個CouchDB節點的內部工作原理。 CouchDB API旨在提供圍繞資料庫核心的便捷但精簡的包裝。通過仔細研究資料庫核心的結構,我們將更好地了解圍繞它的API。
1.3.3.1 數據的Key
CouchDB的核心是功能強大的B樹存儲引擎。 B樹是一種排序的數據結構,允許以對數時間進行搜索,插入和刪除。如圖2所示。對視圖請求的剖析表明,CouchDB使用此B樹存儲引擎存儲所有內部數據,文檔和視圖。如果我們理解一個,我們將全部理解。
CouchDB使用MapReduce來計算視圖的結果。 MapReduce利用了兩個函數,即「 map」和「 reduce」,它們分別應用於每個文檔。能夠隔離這些操作意味著視圖計算可以進行並行和增量計算。更重要的是,由於這些函數產生鍵/值對,因此CouchDB能夠將它們按鍵排序插入B樹存儲引擎。通過鍵或鍵範圍進行的查找是使用B樹的極其有效的操作,用大O表示法分別表示為O(log N)和O(log N + K)。
在CouchDB中,我們按鍵或鍵範圍訪問文檔並查看結果。這是對CouchDB的B樹存儲引擎上執行的基礎操作的直接映射。與文檔插入和更新一起,這種直接映射是我們將CouchDB的API描述為圍繞資料庫核心的薄包裝的原因。
只能通過鍵訪問結果是一個非常重要的限制,因為它使我們獲得了巨大的性能提升。除了大幅提高速度外,我們還可以在多個節點上劃分數據,而不會影響我們獨立查詢每個節點的能力。正是由於這些原因,BigTable,Hadoop,SimpleDB和memcached通過鍵限制了對象查找。
1.3.3.2 無鎖
關係數據庫中的表是單個數據結構。如果要修改表(例如,更新行),資料庫系統必須確保沒有其他人試圖更新該行,並且在更新該行時沒有人可以從該行中讀取數據。解決此問題的常用方法是使用鎖。如果多個客戶端要訪問一個表,則第一個客戶端將獲得鎖,從而使其他所有人都在等待。當第一個客戶的請求得到處理時,下一個客戶將獲得訪問權限,而其他人都將等待,依此類推。即使是並行到達請求,這種串行執行請求也會浪費大量伺服器的處理能力。在高負載下,關係數據庫比進行任何實際工作要花費更多的時間來確定允許誰執行什麼工作以及按照什麼順序執行。
注意
現代的關係數據庫通過在幕後實施MVCC來避免鎖定,但對最終用戶隱藏了MVCC,要求它們協調單個行或欄位的並發更改。
CouchDB使用多版本並發控制(MVCC)代替鎖,來管理對資料庫的並發訪問。圖3. MVCC表示沒有鎖定說明了MVCC和傳統鎖定機制之間的差異。 MVCC意味著CouchDB即使在高負載下也可以一直全速運行。請求是並行運行的,從而充分利用了伺服器必須提供的每最後一滴處理能力。
圖3. MVCC意味著沒有鎖定
CouchDB中的文檔已經過版本控制,就像在常規版本控制系統(例如Subversion)中一樣。如果要更改文檔中的值,請創建該文檔的全新版本並將其保存在舊版本上。完成此操作後,您將獲得同一文檔的兩個版本,一個舊版本,一個新版本。
這如何提供對鎖的改進?考慮一組想要訪問文檔的請求。第一個請求讀取文檔。在處理過程中,第二個請求更改了文檔。由於第二個請求包含文檔的全新版本,因此CouchDB可以簡單地將其附加到資料庫,而不必等待讀取請求完成。
當第三個請求要讀取相同的文檔時,CouchDB將其指向剛剛編寫的新版本。在整個過程中,第一個請求可能仍在讀取原始版本。
讀取請求在請求開始時始終會看到您資料庫的最新快照。
1.3.4 驗證方式
作為應用程式開發人員,我們必須考慮應該接受什麼樣的輸入以及應該拒絕什麼輸入。在傳統的關係數據庫中對複雜數據進行這種類型的驗證的表達能力尚有許多不足之處。幸運的是,CouchDB提供了一種從資料庫內部執行按文檔驗證的強大方法。
CouchDB可以使用類似於MapReduce的JavaScript函數來驗證文檔。每次您嘗試修改文檔時,CouchDB都會通過驗證功能以傳遞現有文檔的副本,新文檔的副本以及其他信息的集合,例如用戶身份驗證詳細信息。驗證功能現在可以批准或拒絕更新。
通過使用Grain並讓CouchDB為我們做到這一點,我們為自己節省了大量的CPU周期,否則這些CPU周期將被用於從SQL序列化對象圖,將它們轉換為域對象並使用這些對象進行應用程式級驗證。
1.3.5 分布式一致性
對於大多數資料庫而言,在單個資料庫節點內維護一致性相對容易。當您嘗試維護多個資料庫伺服器之間的一致性時,真正的問題開始浮出水面。如果客戶端在伺服器A上執行寫操作,我們如何確保它與伺服器B或C或D一致?對於關係數據庫而言,這是一個非常複雜的問題,整本書都專門針對其解決方案。您可以使用多主機,單主機,分區,分片,直寫式高速緩存以及各種其他複雜技術。
1.3.6 增量複製
CouchDB的操作在單個文檔的上下文中進行。由於CouchDB通過使用增量複製實現了多個資料庫之間最終的一致性,因此您不必擔心資料庫伺服器能夠保持持續的通信。增量複製是在伺服器之間定期複製文檔更改的過程。我們能夠構建所謂的無共享資料庫集群,其中每個節點都是獨立且自給自足的,在整個系統中不存在任何爭用點。
需要擴展您的CouchDB資料庫集群嗎?只需投入另一台伺服器即可。
如圖4所示。在CouchDB節點之間進行增量複製,並使用CouchDB進行增量複製,您可以在任意兩個資料庫之間隨時隨地同步數據。複製後,每個資料庫都可以獨立工作。
您可以使用此功能通過cron之類的作業調度程序在群集內或數據中心之間同步資料庫伺服器,也可以使用它在可攜式計算機上同步數據與筆記本電腦以進行離線工作。可以按常規方式使用每個資料庫,並且以後可以在兩個方向上同步資料庫之間的更改。
當您在兩個不同的資料庫中更改同一文檔並希望彼此同步時會發生什麼? CouchDB的複製系統帶有自動衝突檢測和解決方案。當CouchDB在兩個資料庫中都檢測到文檔已被更改時,它將標記該文檔為衝突文檔,就像它們在常規版本控制系統中一樣。
這並不像第一次聽起來那樣麻煩。如果在複製過程中兩個版本的文檔發生衝突,則勝出版本將另存為文檔歷史記錄中的最新版本。 CouchDB不會像您期望的那樣丟掉丟失的版本,而是將其保存為文檔歷史記錄中的先前版本,以便您可以在需要時訪問它。這是自動且一致地發生的,因此兩個資料庫都將做出完全相同的選擇。
由您決定以對您的應用程式有意義的方式來處理衝突。您可以將選定的文檔版本保留在原位,還原為較舊的版本,或嘗試合併兩個版本並保存結果。
1.3.7 案例分析
朋友和同事Greg Borenstein建立了一個小型庫,用於將Songbird播放列錶轉換為JSON對象,並決定將它們存儲在CouchDB中作為備份應用程式的一部分。完整的軟體使用CouchDB的MVCC和文檔修訂版,以確保在節點之間可靠地備份Songbird播放列表。
注意
Songbird是基於Mozilla XULRunner平台的具有集成Web瀏覽器的免費軟體媒體播放器。 Songbird適用於Microsoft Windows,Apple Mac OS X,Solaris和Linux。
讓我們檢查Songbird備份應用程式的工作流程,首先是作為用戶從單台計算機備份,然後使用Songbird在多台計算機之間同步播放列表。我們將看到文檔修訂如何將本來很棘手的問題變成可以解決的問題。
第一次使用此備份應用程式時,我們會將播放列表饋入該應用程式並啟動備份。每個播放列表都將轉換為JSON對象,並傳遞到CouchDB資料庫。如圖5所示。備份到單個資料庫時,CouchDB會將每個播放列表的文檔ID和修訂版本保存到資料庫中。
幾天後,我們發現我們的播放列表已更新,我們希望備份所做的更改。將播放列表饋入備份應用程式後,它會從CouchDB獲取最新版本以及相應的文檔修訂版。當應用程式移交新的播放列表文檔時,CouchDB要求文檔修訂包含在請求中。
然後,CouchDB確保請求中傳遞給它的文檔修訂與資料庫中保存的當前修訂匹配。因為CouchDB每次修改都會更新修訂,所以如果這兩個修改不同步,則表明在我們從資料庫請求文檔到發送更新之間,有人對文檔進行了更改。在其他人沒有先檢查那些更改的情況下對其進行更改通常是一個壞主意。
強迫客戶交出正確的文檔修訂版是CouchDB樂觀並發的核心。
我們有一台筆記本電腦,希望與台式機保持同步。在台式機上播放所有播放列表後,第一步是「從備份還原」到筆記本電腦上。這是我們第一次這樣做,因此之後我們的筆記本電腦應保留桌面播放列表集合的精確副本。
在筆記本電腦上編輯我們的阿根廷探戈播放列表以添加一些我們購買的新歌曲後,我們要保存更改。備份應用程式替換了我們筆記本電腦CouchDB資料庫中的播放列表文檔,並生成了新的文檔修訂版。幾天後,我們記住了我們的新歌曲,並希望將播放列表複製到我們的台式計算機上。如圖6所示,備份應用程式在兩個資料庫之間進行同步,將新文檔和新修訂版本複製到桌面CouchDB資料庫中。現在,兩個CouchDB資料庫都具有相同的文檔修訂版。
因為CouchDB跟蹤文檔修訂,所以它確保僅當這些更新基於當前信息時這些更新才有效。 如果我們在同步之間對播放列表備份進行了修改,那麼事情就不會那麼順利。
我們在筆記本電腦上備份了一些更改,卻忘記了同步。 幾天後,我們正在台式計算機上編輯播放列表,進行備份,並希望將其同步到筆記本電腦。 如圖7所示。兩個資料庫之間的同步衝突,當我們的備份應用程式嘗試在兩個資料庫之間複製時,CouchDB看到從台式機發送的更改是對過時文檔的修改,並有幫助地通知我們 一直是一個衝突。
從應用程式的角度來看,從此錯誤中恢復很容易完成。 只需下載CouchDB的播放列表版本,即可提供合併更改或將本地修改保存到新播放列表中的機會。
1.3.8 總結
CouchDB的設計大量借鑑了Web架構,並汲取了在該架構上部署大規模分布式系統的經驗教訓。 通過了解這種體系結構為何能以這種方式工作,並通過學習發現可以輕鬆分發應用程式的哪些部分而不能輕鬆分發哪些部分,可以增強使用CouchDB或不使用CouchDB來設計分布式和可伸縮應用程式的能力。
我們已經介紹了有關CouchDB一致性模型的主要問題,並暗示了在使用CouchDB而不是反對使用CouchDB時將獲得的一些好處。 但是有足夠的理論–讓我們開始並運行,看看大驚小怪的是什麼!
原文:https://docs.couchdb.org/en/stable/intro/consistency.html
本文:http://jiagoushi.pro/node/919
討論:請加入知識星球或者微信圈子【首席架構師圈】
文章來源: https://twgreatdaily.com/zh-cn/HpzE5m8Bgx9BqZZIoWP1.html