国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

SOFAJRaft 線性一致讀實現剖析 | SOFAJRaft 實現原理

calx / 696人閱讀

摘要:實現線性一致讀最常規的辦法是走協議,將讀請求同樣按照處理,通過復制和狀態機執行來獲取讀結果,然后再把讀取的結果返回給。使用發起線性一致讀請求,當安全讀取時傳入的將被調用,正常情況下從狀態機中讀取數據返回給客戶端,將保證讀取的線性一致性。

SOFAStack
Scalable?Open?Financial?Architecture?Stack
是螞蟻金服自主研發的金融級分布式架構,包含了構建金融級云原生架構所需的各個組件,是在金融場景里錘煉出來的最佳實踐。

本文為《剖析 | SOFAJRaft 實現原理》第三篇,本篇作者米麒麟,來自陸金所。《剖析 | SOFAJRaft 實現原理》系列由 SOFA 團隊和源碼愛好者們出品,項目代號:,目前領取已經完成,感謝大家的參與。

SOFAJRaft?是一個基于?Raft?一致性算法的生產級高性能?Java?實現,支持?MULTI-RAFT-GROUP,適用于高負載低延遲的場景。

SOFAJRaft?:https://github.com/sofastack/sofa-jraft

前言

線性一致讀是在分布式系統中實現?Java?volatile?語義,當客戶端向集群發起寫操作的請求并且獲得成功響應之后,該寫操作的結果要對所有后來的讀請求可見。實現線性一致讀常規手段是走?Raft?協議,將讀請求同樣按照?Log?處理,通過日志復制和狀態機執行獲取讀結果返回給客戶端,SOFAJRaft?采用?ReadIndex?替代走?Raft?狀態機的方案。本文將圍繞?Raft Log Read,ReadIndex Read?以及?Lease Read?等方面剖析線性一致讀原理,闡述?SOFAJRaft?如何使用?ReadIndex?和?Lease Read?實現線性一致讀:

什么是線性一致讀?共識算法只能保證多個節點對某個對象的狀態是一致的,以?Raft?為例只能保證不同節點對?Raft Log?達成一致,那么?Log?后面的狀態機的一致性呢?

基于?ReadIndex?和?Lease Read?方式?SOFAJRaft?如何實現高效的線性一致讀?

線性一致讀

什么是線性一致讀? 所謂線性一致讀,一個簡單的例子是在?t1 的時刻我們寫入了一個值,那么在?t1 之后,我們一定能讀到這個值,不可能讀到?t1?之前的舊值(想想?Java?中的?volatile?關鍵字,即線性一致讀就是在分布式系統中實現?Java?volatile?語義)。簡而言之是需要在分布式環境中實現?Java?volatile?語義效果,即當?Client?向集群發起寫操作的請求并且獲得成功響應之后,該寫操作的結果要對所有后來的讀請求可見。和?volatile?的區別在于?volatile?是實現線程之間的可見,而?SOFAJRaft?需要實現?Server?之間的可見。

如上圖?Client A、B、C、D?均符合線性一致讀,其中?D?看起來是?Stale Read,其實并不是,D?請求橫跨 3 個階段,而?Read?可能發生在任意時刻,所以讀到 1 或 2 都行。

Raft Log read

實現線性一致讀最常規的辦法是走?Raft?協議,將讀請求同樣按照?Log?處理,通過?Log?復制和狀態機執行來獲取讀結果,然后再把讀取的結果返回給?Client。因為?Raft?本來就是一個為了實現分布式環境下線性一致性的算法,所以通過?Raft?非常方便的實現線性?Read,也就是將任何的讀請求走一次?Raft Log,等此?Log?提交之后在?apply?的時候從狀態機里面讀取值,一定能夠保證這個讀取到的值是滿足線性要求的。

當然,因為每次?Read?都需要走?Raft?流程,Raft?Log?存儲、復制帶來刷盤開銷、存儲開銷、網絡開銷,走?Raft Log不僅僅有日志落盤的開銷,還有日志復制的網絡開銷,另外還有一堆的?Raft?“讀日志” 造成的磁盤占用開銷,導致?Read?操作性能是非常低效的,所以在讀操作很多的場景下對性能影響很大,在讀比重很大的系統中是無法被接受的,通常都不會使用。

在?Raft?里面,節點有三個狀態:Leader,Candidate?和?Follower,任何?Raft?的寫入操作都必須經過?Leader,只有?Leader?將對應的?Raft Log?復制到?Majority?的節點上面認為此次寫入是成功的。所以如果當前?Leader?能確定一定是?Leader,那么能夠直接在此?Leader?上面讀取數據,因為對于?Leader?來說,如果確認一個?Log?已經提交到大多數節點,在?t1?的時候?apply?寫入到狀態機,那么在?t1?后的?Read?就一定能讀取到這個新寫入的數據。

那么如何確認?Leader?在處理這次?Read?的時候一定是?Leader?呢?在?Raft?論文里面,提到兩種方法:

ReadIndex Read

Lease Read

ReadIndex Read

第一種是?ReadIndex?Read,當?Leader?需要處理?Read?請求時,Leader?與過半機器交換心跳信息確定自己仍然是?Leader?后可提供線性一致讀:

Leader?將自己當前?Log?的?commitIndex?記錄到一個?Local?變量?ReadIndex?里面;

接著向?Followers?節點發起一輪 Heartbeat,如果半數以上節點返回對應的?Heartbeat?Response,那么?Leader就能夠確定現在自己仍然是?Leader;

Leader?等待自己的?StateMachine?狀態機執行,至少應用到?ReadIndex?記錄的?Log,直到?applyIndex?超過?ReadIndex,這樣就能夠安全提供?Linearizable?Read,也不必管讀的時刻是否?Leader?已飄走;

Leader?執行?Read?請求,將結果返回給?Client。

使用?ReadIndex Read?提供?Follower?Read?的功能,很容易在?Followers?節點上面提供線性一致讀,Follower?收到?Read?請求之后:

Follower?節點向?Leader?請求最新的?ReadIndex;

Leader?仍然走一遍之前的流程,執行上面前 3 步的過程(確定自己真的是?Leader),并且返回?ReadIndex?給?Follower;

Follower?等待當前的狀態機的?applyIndex?超過?ReadIndex;

Follower?執行?Read?請求,將結果返回給?Client。

不同于通過?Raft?Log?的?Read,ReadIndex Read?使用?Heartbeat?方式來讓?Leader?確認自己是?Leader,省去?Raft?Log?流程。相比較于走?Raft?Log?方式,ReadIndex?Read?省去磁盤的開銷,能夠大幅度提升吞吐量。雖然仍然會有網絡開銷,但是?Heartbeat?本來就很小,所以性能還是非常好的。

Lease Read

雖然?ReadIndex?Read?比原來的?Raft?Log?Read?快很多,但畢竟還是存在?Heartbeat?網絡開銷,所以考慮做更進一步的優化。Raft?論文里面提及一種通過?Clock +?Heartbeat?的?Lease?Read?優化方法,也就是?Leader?發送?Heartbeat?的時候首先記錄一個時間點?Start,當系統大部分節點都回復?Heartbeat?Response,由于?Raft?的選舉機制,Follower?會在?Election Timeout?的時間之后才重新發生選舉,下一個?Leader?選舉出來的時間保證大于?Start+Election?Timeout/Clock Drift Bound,所以可以認為?Leader?的?Lease?有效期可以到?Start+Election?Timeout/Clock Drift Bound?時間點。Lease?Read?與?ReadIndex?類似但更進一步優化,不僅節省?Log,而且省掉網絡交互,大幅提升讀的吞吐量并且能夠顯著降低延時。

Lease?Read?基本思路是?Leader?取一個比?Election Timeout?小的租期(最好小一個數量級),在租約期內不會發生選舉,確保?Leader?不會變化,所以跳過?ReadIndex?的第二步也就降低延時。由此可見?Lease?Read?的正確性和時間是掛鉤的,依賴本地時鐘的準確性,因此雖然采用?Lease?Read?做法非常高效,但是仍然面臨風險問題,也就是存在預設的前提即各個服務器的?CPU Clock?的時間是準的,即使有誤差,也會在一個非常小的?Bound?范圍里面,時間的實現至關重要,如果時鐘漂移嚴重,各個服務器之間?Clock?走的頻率不一樣,這套?Lease?機制可能出問題。

Lease?Read?實現方式包括:

定時?Heartbeat?獲得多數派響應,確認?Leader?的有效性;

在租約有效時間內,可以認為當前?Leader?是?Raft?Group?內的唯一有效?Leader,可忽略?ReadIndex?中的?Heartbeat?確認步驟(2);

Leader?等待自己的狀態機執行,直到?applyIndex?超過?ReadIndex,這樣就能夠安全的提供?Linearizable?Read。

SOFAJRaft?線性一致讀實現

SOFAJRaft?采用?ReadIndex?替代走?Raft?狀態機的方案,簡而言之是依靠?ReadIndex?原則直接從?Leader?讀取結果:所有已經復制到多數派上的?Log(可視為寫操作)被視為安全的?Log,Leader?狀態機只要按照順序執行到此條?Log之后,該?Log?所體現的數據就能對客戶端?Client?可見,具體分解為以下四個步驟:

Client?發起?Read?請求;

Leader?確認最新復制到多數派的?LogIndex;

Leader?確認身份;

在?LogIndex apply?后執行?Read?操作。

通過?ReadIndex?優化,SOFAJRaft?能夠達到?RPC?上限的 80%。上面的步驟中發現第 3 步仍然需要?Leader?通過向?Followers?發送心跳確認自己的?Leader?身份,因為?Raft?集群中的?Leader?身份隨時可能發生改變。所以?SOFAJRaft?采用?Lease Read?的方式把第 3 步?RPC?省略掉。租約理解為?Raft?集群給?Leader?一段租期?Lease?的身份保證,在此期間不會剝奪?Leader?的身份,這樣當?Leader?收到?Read?請求之后,如果發現租期尚未到期,無需再通過和?Followers?通信來確認自己的?Leader?身份,這樣跳過第 3 步的網絡通信開銷。通過?Lease Read?優化,SOFAJRaft?幾乎已經能夠達到?RPC?的上限。然而通過時鐘維護租期本身并不是絕對的安全(時鐘漂移問題),所以?SOFAJRaft?默認配置是線性一致讀,因為通常情況下線性一致讀性能已足夠好。

ReadIndex Read?實現

默認情況下,SOFAJRaft?提供的線性一致讀是基于?Raft?協議的?ReadIndex?實現,三副本的情況下?Leader?讀的吞吐接近于?RPC?的吞吐上限,延遲取決于多數派中最慢的一個?Heartbeat?Response。使用?Node#readIndex(byte?[]?requestContext,?ReadIndexClosure?done)?發起線性一致讀請求,當安全讀取時傳入的?Closure?將被調用,正常情況下從狀態機中讀取數據返回給客戶端,?SOFAJRaft?將保證讀取的線性一致性。線性一致讀在任何集群內的節點發起,并不需要強制要求放到?Leader?節點上,允許在?Follower?節點執行,因此大大降低?Leader?的讀取壓力。

SOFAJRaft?基于?Raft?協議的?ReadIndex?線性一致讀實現是調用?RaftServerService#handleReadIndexRequest?接口根據當前節點狀態為?STATE_LEADER,STATE_FOLLOWER?以及?STATE_TRANSFERRING?情況處理?ReadIndex?請求:

1、當前節點狀態是?STATE_LEADER?即為?Leader?節點,接收?ReadIndex?請求調用?readLeader(request,?ReadIndexResponse.newBuilder(),?done)?方法提供線性一致讀:

檢查當前?Raft?集群節點數量,如果集群只有一個?Peer?節點直接獲取投票箱?BallotBox?最新提交索引?lastCommittedIndex?即?Leader?節點當前?Log?的?commitIndex?構建?ReadIndexClosure?響應;

日志管理器?LogManager?基于投票箱?BallotBox?的?lastCommittedIndex?獲取任期檢查是否等于當前任期,如果不等于當前任期表示此?Leader?節點未在其任期內提交任何日志,需要拒絕只讀請求;

校驗?Raft?集群節點數量以及?lastCommittedIndex?所屬任期符合預期,那么響應構造器設置其索引為投票箱?BallotBox?的?lastCommittedIndex,并且來自?Follower?的請求需要檢查?Follower?是否在當前配置;

獲取?ReadIndex?請求級別?ReadOnlyOption?配置,ReadOnlyOption?參數默認值為?ReadOnlySafe,ReadOnlySafe?通過與?Quorum?通信來保證只讀請求的可線性化。按照?ReadOnlyOption?配置為ReadOnlySafe?調用?Replicator#sendHeartbeat(rid,?closure) 方法向?Followers?節點發送?Heartbeat?心跳請求,發送心跳成功執行?ReadIndexHeartbeatResponseClosure?心跳響應回調;

ReadIndex?心跳響應回調檢查是否超過半數節點包括?Leader?節點自身投票贊成,半數以上節點返回客戶端Heartbeat?請求成功響應,即?applyIndex?超過?ReadIndex?說明已經同步到?ReadIndex?對應的?Log?能夠提供?Linearizable?Read。

2、當前節點狀態是?STATE_FOLLOWER?即為?Follower?節點,接收?ReadIndex?請求通過?readFollower(request,??done)?方法支持線性一致讀:

檢查當前?Leader?節點是否為空,如果?Leader?節點為空表示當然任期沒有?Leader?節點;

Follower?節點調用?RpcService#readIndex(leaderId.getEndpoint(),?newRequest,?-1,?closure)?方法向?Leader?發送?ReadIndex?請求,Leader?節點調用?readIndex(requestContext,?done)?方法啟動可線性化只讀查詢請求,只讀服務添加請求發布?ReadIndex?事件到隊列?readIndexQueue?即?Disruptor?的?Ring Buffer;

ReadIndex?事件處理器?ReadIndexEventHandler?通過?MPSC?Queue?模型攢批消費觸發使用?executeReadIndexEvents(events) 執行?ReadIndex?事件,輪詢?ReadIndex?事件封裝?ReadIndexState?狀態列表構建?ReadIndexResponseClosure?響應回調提交給?Leader?節點處理?ReadIndex?請求;

Leader?節點調用?handleReadIndexRequest(request,?readIndexResponseClosure) 方法進行?readLeader?線性一致讀過程,返回投票箱?BallotBox?的?lastCommittedIndex。ReadIndex?響應回調遍歷狀態列表記錄當前提交日志?Index,檢查申請狀態機最新?Log Entry?的?committedIndex?是否已經申請即比較狀態機?appliedIndex?是否大于等于當前?committedIndex。由于?Leader?節點處理添加?Log Entry?請求發送心跳后投票箱?BallotBox?更新?lastCommittedIndex,當?Leader?節點的?lastCommittedIndex?大于當前的?lastCommittedIndex?就會創建提交?Log Entry?異步任務發布到?taskQueue?隊列,申請任務處理器?ApplyTaskHandler?執行提交?LogEntry?申請任務,通知?Follower?節點最新申請的?committedIndex?已經更新。如果當前申請狀態機的?applyIndex?超過?ReadIndex,那么通知?ReadIndex?請求成功返回給客戶端。當前?Follower?節點落后于?Leader?時把?Leader?節點返回的committedIndex?放到?pendingNotifyStatus?緩存等待?Leader?節點同步完日志更新?applyIndex。

SOFAJRaft?基于?Batch+Pipeline?Ack+ 全異步機制的?ReadIndex?核心邏輯:

Lease Read?實現

SOFAJRaft?針對更高性能要求場景保證集群內機器的?CPU?時鐘同步需求,采用?Clock+Heartbeat?的?Lease Read?優化,通過服務端設置?RaftOptions?的?ReadOnlyOption?參數為?ReadOnlyLeaseBased?實現,ReadOnlyLeaseBased?通過依賴?Leader?租約確保只讀請求的可線性化,可能受時鐘漂移的影響。如果時鐘漂移無限制,Leader?節點可能保持租約長于應有的時間(時鐘可以向后移動/暫停而沒有任何限制),此種情況下?ReadIndex?是不安全的。

SOFAJRaft?基于?Lease Read?線性一致讀實現是通過?Leader?節點調用?handleReadIndexRequest?接口接收?ReadIndex?請求獲取?ReadIndex?請求級別?ReadOnlyOption?配置,當?ReadOnlyOption?配置為?ReadOnlyLeaseBased?時確認?Leader?租約是否有效即檢查?Heartbeat?間隔是否小于?election?timeout?時間,Leader?租約超時需要轉變為?ReadIndex?模式。Leader?租約有效期間認為當前?Leader?是?Raft Group?內的唯一有效?Leader,忽略?ReadIndex?發送?Heartbeat?確認身份步驟,直接返回?Follower?節點和本地節點 Read 請求成功響應。Leader?節點繼續等待狀態機執行,直到 applyIndex 超過?ReadIndex?安全提供?Linearizable?Read。

SOFAJRaft?基于時鐘和心跳實現的線性一致讀?Lease Read?優化邏輯:

總結

本文圍繞?Raft Log Read,ReadIndex Read?以及?Lease Read?線性一致讀實現細節方面剖析?SOFAJRaft?線性一致讀基本原理,闡述?SOFAJRaft?如何使用?Batch+Pipeline?Ack+全異步機制和?Clock+Heartbeat?手段優化?ReadIndex?和?Lease Read?線性一致讀具體實現。

《剖析 | SOFAJRaft 實現原理》系列文章回顧:

SOFAJRaft-RheaKV 是如何使用 Raft 的 | SOFAJRaft 實現原理

螞蟻金服生產級 Raft 算法庫 SOFAJRaft 存儲模塊剖析 | SOFAJRaft 實現原理

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/75108.html

相關文章

  • Elasticsearch分布式一致原理剖析(三)-Data篇

    摘要:前言分布式一致性原理剖析系列將會對的分布式一致性原理進行詳細的剖析,介紹其實現方式原理以及其存在的問題等基于版本。使用額外的一致性組件維護。管理的全局組件,其保證數據的一致性。將這個加入自己的,同時向所有發送請求,要求將這個加入。 前言Elasticsearch分布式一致性原理剖析系列將會對Elasticsearch的分布式一致性原理進行詳細的剖析,介紹其實現方式、原理以及其存在的問題...

    RyanQ 評論0 收藏0
  • Elasticsearch分布式一致原理剖析(三)-Data篇

    摘要:前言分布式一致性原理剖析系列將會對的分布式一致性原理進行詳細的剖析,介紹其實現方式原理以及其存在的問題等基于版本。使用額外的一致性組件維護。管理的全局組件,其保證數據的一致性。將這個加入自己的,同時向所有發送請求,要求將這個加入。 前言Elasticsearch分布式一致性原理剖析系列將會對Elasticsearch的分布式一致性原理進行詳細的剖析,介紹其實現方式、原理以及其存在的問題...

    cfanr 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<