版本不一致_一致哈希:Beyond the basics
經(jīng)典的一致哈希算法解決了模塊化哈希算法的問題,其中哈希函數(shù)(鍵K的位置)與存儲單元的數(shù)量相關(guān),需要在按比例放大和縮小時重新分配所有鍵。
# modular hashinghash = key % N of nodes另一方面,利用一致哈希,哈希功能與存儲節(jié)點的數(shù)量無關(guān)。這使我們能夠在添加或刪除節(jié)點時動態(tài)地對數(shù)據(jù)進行分區(qū),從而逐步擴展。
哈希空間保持巨大且恒定。它通常被稱為 “環(huán)”。每個存儲節(jié)點都在此散列空間ring中分配了一個隨機位置。
通過哈希數(shù)據(jù)項的鍵以獲取其在環(huán)上的位置,然后順時針旋轉(zhuǎn)環(huán)以找到位置大于該項位置的第一個節(jié)點,將每個數(shù)據(jù)項分配給一個節(jié)點。
因此,每個節(jié)點都負責(zé)它與其前任節(jié)點之間的環(huán)中區(qū)域。因此,添加或刪除節(jié)點僅需要重新分配屬于其區(qū)域的密鑰,而不需要像模塊化哈希那樣重新分配所有密鑰。
模塊化與一致性哈希
一致性哈希提出了一些挑戰(zhàn)。最明顯的是圍繞環(huán)上節(jié)點位置的隨機分配,從而導(dǎo)致數(shù)據(jù)和負載分布不均勻。此外,當(dāng)添加或刪除節(jié)點時,必須通過從單個節(jié)點檢索一組鍵來復(fù)制一些數(shù)據(jù),這通常效率低下且速度慢。
受AWS DynamoDB的啟發(fā),本文討論了經(jīng)典的一致性哈希所帶來的挑戰(zhàn),涉及了不同的擴展方面,例如可用性,一致性,性能和持久性。此外,它還討論了數(shù)據(jù)版本控制和協(xié)調(diào),節(jié)點成員資格以及故障檢測和處理。它只是參考AWS DynamoDB已發(fā)表論文的一般想法和個人注釋的摘要。DynamoDB是Amazon的高可用性鍵值存儲。
將節(jié)點映射到T令牌
每個節(jié)點T個令牌
為了使用經(jīng)典的一致性哈希解決非均勻數(shù)據(jù)和負載分配問題,我們可以將每個節(jié)點映射到環(huán)中的T個位置(稱為“令牌”)。添加新節(jié)點時,會在環(huán)上為其分配隨機散布的T位置(令牌)。這具有以下好處:
添加節(jié)點后,與現(xiàn)有可用節(jié)點相比,其負載量大致相等。
當(dāng)某個節(jié)點被刪除或由于故障而變得不可用時,該節(jié)點處理的負載將以相反的過程分配回來,從而有效地將負載平均分配到其余可用節(jié)點上。
可用性
— 復(fù)制
跨多個節(jié)點復(fù)制數(shù)據(jù)對于實現(xiàn)高可用性至關(guān)重要。每個數(shù)據(jù)項都在N個節(jié)點上復(fù)制。節(jié)點協(xié)調(diào)寫請求,負責(zé)復(fù)制環(huán)中N-1個順時針后繼位置(令牌)中屬于其范圍內(nèi)的數(shù)據(jù)項。第一后繼位置可能是由另一個哈希函數(shù)確定的隨機性,也可能是跨不同的數(shù)據(jù)中心確定的以提高可用性。
一些有用的定義:N是每個數(shù)據(jù)項的副本數(shù),公共值為3;R是要確認/回復(fù)讀請求的副本數(shù);W則是要確認/保留寫請求的副本數(shù);S是系統(tǒng)中的節(jié)點數(shù);T是環(huán)上物理節(jié)點的令牌(位置)數(shù);密鑰范圍是指環(huán)上與令牌相關(guān)聯(lián)的一組密鑰(令牌由節(jié)點擁有)。
— 始終可寫
我們都知道,在分布式系統(tǒng)世界中,網(wǎng)絡(luò)故障和數(shù)據(jù)沖突并不少見,因此無法同時實現(xiàn)高一致性和數(shù)據(jù)可用性。傳統(tǒng)算法會在故障情況下權(quán)衡數(shù)據(jù)的可用性,因此在絕對確定數(shù)據(jù)正確之前,使數(shù)據(jù)不可用。
相反,我們可以通過解決答案的正確性的不確定性來提高可用性,允許更改傳播到后臺的副本中,并且允許并發(fā)的,斷開的工作。
這種方法的挑戰(zhàn)在于,它可能導(dǎo)致沖突的變化,必須加以檢測和解決。解決沖突的過程引入了兩個問題:何時解決問題以及誰來解決。
一致性
— 解決沖突:何時
在讀取或?qū)懭肫陂g是否應(yīng)解決沖突。許多傳統(tǒng)的數(shù)據(jù)存儲解決了寫入期間的沖突,并使讀取的復(fù)雜性保持簡單。如果數(shù)據(jù)存儲無法到達W節(jié)點,則會以拒絕寫入為代價,從而有效地降低了系統(tǒng)可用性。將沖突解決方案推送至讀取可確保永不拒絕寫入。檢測到數(shù)據(jù)版本沖突時,不會拒絕讀取;現(xiàn)在的問題是誰以及如何解決?
— 解決沖突:誰
這可以通過數(shù)據(jù)存儲本身或應(yīng)用程序客戶端來完成。
應(yīng)用程序客戶端知道數(shù)據(jù)模式和業(yè)務(wù)邏輯,因此可以決定沖突的解決方案。以購物車示例為例,當(dāng)客戶要將商品添加到購物車(或從購物車中刪除)而最新版本不可用時,則將商品添加到舊版本(或從舊版本中刪除),并且將不同版本以后和解。這種變化仍然有意義,應(yīng)該保留。讀取時,當(dāng)檢測到?jīng)_突版本時,應(yīng)用程序客戶端可以選擇“合并”沖突版本并返回單個統(tǒng)一購物車。
另一方面,如果數(shù)據(jù)存儲區(qū)正在處理沖突,則其選擇相當(dāng)有限,并且只能使用簡單的策略,例如基于時間戳的“最后寫入獲勝”對帳邏輯(即,選擇具有最新時間戳值的項目)作為正確的版本)。維護客戶會話信息的服務(wù)就是該用例的一個很好的例子。
— 解決沖突:如何
版本沖突對帳
數(shù)據(jù)版本控制使我們能夠檢測,解決沖突的版本,從而確保數(shù)據(jù)的一致性。節(jié)點執(zhí)行的每次更新都被視為數(shù)據(jù)的新的和不變的版本。一個版本由(節(jié)點,計數(shù)器)對組成,即[(N,c),…],其中N是協(xié)調(diào)寫請求的節(jié)點。
在大多數(shù)情況下,新版本包含以前的版本,并且數(shù)據(jù)存儲本身可以確定權(quán)威版本。
但是,在出現(xiàn)故障并發(fā)更新的情況下,可能會發(fā)生版本(并行)分支,從而導(dǎo)致項目的版本沖突。在這種情況下,數(shù)據(jù)的多個分支折疊為一個。前面解釋的一個典型示例是應(yīng)用程序客戶端“合并”客戶購物車的不同版本。
為了說明讀寫工作流程:
讀
協(xié)調(diào)讀取請求的節(jié)點將從所有N個節(jié)點中獲取給定項的鍵來請求該項的現(xiàn)有版本。
然后它將等待N個節(jié)點中的R個節(jié)點進行回復(fù)。
返回結(jié)果。如果檢測到版本沖突,特別是數(shù)據(jù)存儲無法協(xié)調(diào)的并行分支,它將把沖突的項目及其版本上下文信息返回給客戶端。客戶端通過將分支折疊成一個版本來協(xié)調(diào)不同版本后,執(zhí)行更新。
寫
協(xié)調(diào)寫請求的節(jié)點將在本地存儲它,生成一個新版本,并在N-1個位置(令牌)之間復(fù)制它。客戶端必須指定要更新的版本。通過傳遞從較早的讀取操作獲得的上下文來完成此操作。
一旦N個節(jié)點中的W個節(jié)點作出響應(yīng),就認為寫入請求成功。
性能
為讀和寫操作提供一致的高性能非常困難,因為性能受到R或W副本中最慢的限制。
一些應(yīng)用需要高水平的性能,并且可以權(quán)衡耐用性與性能(即R = 1,W = 1)。為此,每個存儲節(jié)點在其主內(nèi)存中維護一個對象緩沖區(qū)。每個寫操作都存儲在緩沖區(qū)中,并定期寫入持久性存儲中。每個讀取操作首先檢查緩沖區(qū)中是否存在請求的密鑰。如果是這樣,則從緩沖區(qū)而不是存儲引擎中讀取對象。
這將導(dǎo)致延遲降低很多,但要兼顧耐久性。服務(wù)器崩潰可能導(dǎo)致丟失在緩沖區(qū)中排隊的寫操作。
持久性
為了降低持久性風(fēng)險,處理寫請求的協(xié)調(diào)器節(jié)點從N-1個副本中選擇一個,將數(shù)據(jù)寫到其持久性存儲中。并且由于協(xié)調(diào)器節(jié)點僅等待W響應(yīng),因此寫操作的性能不會受到影響。
通常,增加成功寫入操作時需要確認的節(jié)點數(shù)量可以提高持久性,但同時也要犧牲可用性。如果沒有足夠多的活動節(jié)點可以答復(fù),則寫入請求可能會被拒絕。
跨數(shù)據(jù)中心復(fù)制數(shù)據(jù)項以承受因斷電,網(wǎng)絡(luò)故障和自然災(zāi)害導(dǎo)致的故障很重要。
節(jié)點成員資格
節(jié)點之間基于gossip的協(xié)議傳播成員身份更改(節(jié)點加入或離開環(huán))并維護成員身份的最終一致性。
每個節(jié)點每秒都與隨機選擇的一個對等方聯(lián)系,并且兩個節(jié)點有效地協(xié)調(diào)了其持久的成員資格更改歷史記錄。
因此,每個存儲節(jié)點都知道其對等節(jié)點處理的令牌。這允許每個節(jié)點直接將密鑰的讀/寫操作轉(zhuǎn)發(fā)到正確的節(jié)點集。
這消除了維護故障狀態(tài)的集中全局一致視圖的需要。
故障檢測與處理
故障檢測和處理可以避免失敗的讀取或?qū)懭雵L試,即使在最簡單的故障條件下,這樣做也會降低可用性和耐久性。
—臨時故障:提示切換
如果節(jié)點B不響應(yīng)節(jié)點A的消息,則節(jié)點A可能認為節(jié)點B暫時處于關(guān)閉狀態(tài)。然后,節(jié)點A使用備用節(jié)點執(zhí)行請求;節(jié)點A定期重試B以檢查后者的恢復(fù)情況。
在沒有客戶端請求來驅(qū)動兩個節(jié)點之間的流量的情況下,兩個節(jié)點都不真正需要知道另一個節(jié)點是否可訪問且是否響應(yīng)。
為了處理此問題,通常將原本存在于B上的數(shù)據(jù)項現(xiàn)在將發(fā)送到節(jié)點X(B的臨時副本)。發(fā)送到副本X的數(shù)據(jù)項將在其元數(shù)據(jù)中具有提示,提示哪個節(jié)點是副本的預(yù)期接收者(在本例中為B)。
接收提示數(shù)據(jù)項的節(jié)點會將它們保存在單獨的本地數(shù)據(jù)庫中,該數(shù)據(jù)庫會定期進行掃描。在檢測到B已恢復(fù)后,X將嘗試將數(shù)據(jù)傳遞給B。一旦傳輸成功,X可能會從其本地存儲中刪除該數(shù)據(jù)項。
使用提示切換,我們確保寫操作不會由于臨時節(jié)點或網(wǎng)絡(luò)故障而失敗。
—持久故障:副本同步
在某些情況下(例如節(jié)點中斷),節(jié)點B可能會長時間不可用,并且提示的數(shù)據(jù)項甚至可能無法返回。為解決此問題,使用了使用Merkle樹的副本同步協(xié)議來使副本保持同步并檢測不一致之處。
Merkle樹遍歷
Merkle樹是一種哈希樹,其中的葉子是各個鍵的值的哈希值。樹中較高的父節(jié)點是其各自子節(jié)點的哈希。Merkle樹的主要優(yōu)點是,樹的每個分支都可以獨立且并行地進行檢查。此外,Merkle樹有助于減少需要傳輸?shù)臄?shù)據(jù)量并減少執(zhí)行的磁盤讀取次數(shù)。兩個節(jié)點可以遍歷其Merkle樹,以共同擁有的關(guān)鍵范圍來確定它們是否存在差異。
每個節(jié)點為其承載的每個密鑰范圍(與令牌關(guān)聯(lián)的密鑰集)維護一個單獨的Merkle樹。這允許節(jié)點比較密鑰范圍內(nèi)的密鑰是否為最新。
回顧
因此,總結(jié)一下添加和刪除節(jié)點以及讀取和寫入的工作流程:
添加節(jié)點
當(dāng)節(jié)點X加入時,它會在環(huán)上選擇其隨機令牌集。
對于分配給節(jié)點X的每個密鑰范圍,當(dāng)前可能有許多節(jié)點負責(zé)處理屬于其令牌范圍內(nèi)的密鑰。由于將密鑰范圍分配給X,因此現(xiàn)有節(jié)點不再需要存儲這些密鑰,這些節(jié)點會將這些密鑰轉(zhuǎn)移到 X。
通過上面討論的基于八卦的協(xié)議,協(xié)調(diào)成員資格更改歷史并維護成員資格的最終一致性視圖。
刪除節(jié)點
當(dāng)節(jié)點被刪除或由于故障而變得不可用時,這表示永久離開,因此,成員資格更改會傳播,以通知其他節(jié)點有關(guān)節(jié)點刪除的信息。
對于由已刪除節(jié)點處理的密鑰范圍,它們被隨機分配到其余節(jié)點,因此,將負載平均分配到其余可用節(jié)點上。
讀
客戶端請求由負載均衡器統(tǒng)一分配給環(huán)中的節(jié)點。任何節(jié)點都可以充當(dāng)讀取請求的協(xié)調(diào)器。
協(xié)調(diào)讀取請求的節(jié)點會將請求發(fā)送到密鑰K的所有N個節(jié)點,并等待N個節(jié)點中的R個。
收集數(shù)據(jù),確定是否需要對帳(如前所述)。此過程稱為“讀取修復(fù)”,因為它會修復(fù)錯過了最近更新的副本,并使副本同步協(xié)議不必執(zhí)行此操作。
寫
與讀取不同,寫請求由帶有密鑰K的數(shù)據(jù)項的節(jié)點副本之一協(xié)調(diào)。如果接收到請求的節(jié)點不是該數(shù)據(jù)項的密鑰的節(jié)點副本,它將把請求轉(zhuǎn)發(fā)到N個副本之一此限制是由于這些首選節(jié)點還具有創(chuàng)建新版本標記的責(zé)任。如果版本控制方案基于物理時間戳,則任何節(jié)點都可以協(xié)調(diào)寫請求。
等待N個節(jié)點之外的W個節(jié)點作出響應(yīng)。
應(yīng)用程序客戶端庫可以是可感知分區(qū)的客戶端庫,可將請求直接路由到適當(dāng)?shù)膮f(xié)調(diào)器節(jié)點。在這種情況下,我們可以實現(xiàn)較低的延遲,因為如果負載均衡器將請求分配給隨機節(jié)點,它會跳過額外的網(wǎng)絡(luò)躍點。
挑戰(zhàn)性
由于令牌是在環(huán)上隨機選擇的,因此范圍的大小會有所不同。隨著節(jié)點的加入和離開系統(tǒng),令牌集也會更改,因此范圍也會更改。因此,“將節(jié)點映射到T令牌”策略提出了以下挑戰(zhàn):
當(dāng)新節(jié)點加入系統(tǒng)時,在關(guān)鍵范圍內(nèi)處理該數(shù)據(jù)的節(jié)點到新節(jié)點必須掃描其本地持久性存儲以檢索適當(dāng)?shù)臄?shù)據(jù)項集。掃描操作占用大量資源,因此需要在后臺執(zhí)行,而又不影響客戶性能。此外,以最低優(yōu)先級運行引導(dǎo)任務(wù)會極大地減慢引導(dǎo)過程,并在繁忙時段變得很麻煩。
當(dāng)一個節(jié)點加入或離開系統(tǒng)時,其他一些節(jié)點處理的關(guān)鍵范圍將發(fā)生變化,并且需要重新計算新范圍的Merkle樹,這對于在生產(chǎn)系統(tǒng)上執(zhí)行來說是一項不平凡的操作。
最后,由于密鑰范圍的隨機性,沒有簡單的方法可以對整個密鑰空間進行快照,這使歸檔過程變得復(fù)雜。在這種情況下,歸檔整個密鑰空間需要分別從每個節(jié)點檢索密鑰,這是非常低效的。
這種策略的根本問題是數(shù)據(jù)分區(qū)(按令牌劃分)和數(shù)據(jù)放置(存儲節(jié)點)是相互依賴的。在不影響數(shù)據(jù)分區(qū)的情況下添加或刪除節(jié)點是不可能的。
將節(jié)點映射到T令牌和相等大小的Q分區(qū)
每個節(jié)點T個令牌和相等大小的Q分區(qū)
在這種策略中,將哈希空間劃分為Q個大小相等的固定分區(qū)(或鍵范圍),并且為每個節(jié)點分配T個隨機令牌。這里的令牌不決定分區(qū),因此兩個連續(xù)的令牌不定義鍵范圍或分區(qū)(它們僅定義環(huán)上的節(jié)點位置)。
通過這種策略,我們可以獲得以下好處:
分區(qū)和分區(qū)放置的分離。數(shù)據(jù)項在給定鍵K的情況下映射到Q個分區(qū)中的一個,而負責(zé)存儲該數(shù)據(jù)項的節(jié)點是通過從包含鍵K的分區(qū)的末尾順時針旋轉(zhuǎn)環(huán)來選擇的,從而找到第一個令牌的方式,然后找到它的存儲節(jié)點。
啟用在運行時更改放置方案的可能性。添加或刪除節(jié)點不會更改任何數(shù)據(jù)項的分區(qū)(鍵范圍)。
通常將Q設(shè)置為Q > S * T,其中S是系統(tǒng)中的節(jié)點數(shù)。
但是,分配的T令牌的隨機性以及密鑰范圍仍然是一個難題。傳遞數(shù)據(jù)的節(jié)點會掃描其本地持久性存儲,從而導(dǎo)致引導(dǎo)速度變慢;重新計算Merkle樹;并沒有簡單的快照方法。
將節(jié)點映射到Q / S令牌和相等大小的Q分區(qū)
每個節(jié)點的Q / S令牌和相等大小的Q分區(qū)
與策略2相似,此策略將哈希空間劃分為Q個大小相等的分區(qū),并且數(shù)據(jù)放置與數(shù)據(jù)分區(qū)分離。
此外,為每個節(jié)點分配Q / S令牌(即T = Q / S)。令牌數(shù)量隨著我們添加或刪除節(jié)點而改變。
當(dāng)節(jié)點離開系統(tǒng)時,其令牌將隨機分配到其余節(jié)點,以便保留這些屬性。同樣,當(dāng)節(jié)點加入系統(tǒng)時,它會以保留這些屬性的方式從系統(tǒng)中的節(jié)點竊取令牌。
此策略具有以下優(yōu)點:
更快的引導(dǎo)和恢復(fù)。由于分區(qū)鍵范圍是固定的,因此可以將它們存儲在單獨的文件中,因此,只需簡單地傳輸文件,就可以將分區(qū)作為一個單元重新放置,從而避免了定位特定項目所需的隨機訪問。
易于歸檔:分區(qū)文件可以單獨歸檔。相比之下,與以前的策略相比,令牌是隨機選擇的,并且對存儲的數(shù)據(jù)進行歸檔需要分別從各個節(jié)點檢索密鑰,并且通常效率低下且速度慢。
這種策略的缺點是添加或刪除節(jié)點需要我們保留其屬性(即T = Q / S)。
參考文獻:
Dynamo:亞馬遜的高可用鍵值存儲
鏈接:
https://medium.com/omarelgabrys-blog/consistent-hashing-beyond-the-basics-525304a12ba
翻譯:奶酪二哈-BKing
The article is only for learning,?if? infringement, please contact BKing8@88.com to delete.
總結(jié)
以上是生活随笔為你收集整理的版本不一致_一致哈希:Beyond the basics的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个Setup Factory的Lua脚
- 下一篇: 每天学习一点点(2010年二月)