怎樣用Nacos實現Raft演算法
為了提高理解性,Raft 將一致性演算法分為了幾個部分,包括領導選取(leader selection)、日誌複製(log replication)、安全(safety),並且使用了更強的一致性來減少了必須需要考慮的狀態。 |
Raft 適用於一個管理日誌一致性的協議,相比於 Paxos 協議 Raft 更易於理解和去實現它。為了提高理解性,Raft 將一致性演算法分為了幾個部分,包括領導選取(leader selection)、日誌複製(log replication)、安全(safety),並且使用了更強的一致性來減少了必須需要考慮的狀態。
相比Paxos,Raft演算法理解起來更加直觀。
Raft演算法將Server劃分為3種狀態,或者也可以稱作角色:
Leader:負責Client互動和log複製,同一時刻系統中最多存在1個。
Follower:被動響應請求RPC,從不主動發起請求RPC。
Candidate:一種臨時的角色,只存在於leader的選舉階段,某個節點想要變成leader,那麼就發起投票請求,同時自己變成candidate。如果選舉成功,則變為candidate,否則退回為follower
狀態或者說角色的流轉如下:
在Raft中,問題分解為:領導選取、日誌複製、安全和成員變化。
複製狀態機透過複製日誌來實現:
日誌:每臺機器儲存一份日誌,日誌來自於客戶端的請求,包含一系列的
狀態機:狀態機會按順序執行這些
一致性模型:分散式環境下,保證多機的日誌是一致的,這樣回放到狀態機中的狀態是一致的
Raft中有Term的概念,Term類比中國歷史上的朝代更替,Raft 演算法將時間劃分成為任意不同長度的任期(term)。
follower增加當前的term,轉變為candidate。
candidate投票給自己,併傳送RequestVote RPC給叢集中的其他伺服器。
收到RequestVote的伺服器,在同一term中只會按照先到先得投票給至多一個candidate。且只會投票給log至少和自身一樣新的candidate。
Spring Cloud Alibaba Nacos 在 1.0.0 正式支援 AP 和 CP 兩種一致性協議,其中的CP一致性協議實現,是基於簡化的 Raft 的 CP 一致性。
Nacos server在啟動時,會透過RunningConfig.onApplicationEvent()方法呼叫RaftCore.init()方法。
public static void init() throws Exception { Loggers.RAFT.info("initializing Raft sub-system"); // 啟動Notifier,輪詢Datums,通知RaftListener executor.submit(notifier); // 獲取Raft叢集節點,更新到PeerSet中 peers.add(NamingProxy.getServers()); long start = System.currentTimeMillis(); // 從磁碟載入Datum和term資料進行資料恢復 RaftStore.load(); Loggers.RAFT.info("cache loaded, peer count: {}, datum count: {}, current term: {}", peers.size(), datums.size(), peers.getTerm()); while (true) { if (notifier.tasks.size() <= 0) { break; } Thread.sleep(1000L); System.out.println(notifier.tasks.size()); } Loggers.RAFT.info("finish to load data from disk, cost: {} ms.", (System.currentTimeMillis() - start)); GlobalExecutor.register(new MasterElection()); // Leader選舉 GlobalExecutor.register1(new HeartBeat()); // Raft心跳 GlobalExecutor.register(new AddressServerUpdater(), GlobalExecutor.ADDRESS_SERVER_UPDATE_INTERVAL_MS); if (peers.size() > 0) { if (lock.tryLock(INIT_LOCK_TIME_SECONDS, TimeUnit.SECONDS)) { initialized = true; lock.unlock(); } } else { throw new Exception("peers is empty."); } Loggers.RAFT.info("timer started: leader timeout ms: {}, heart-beat timeout ms: {}", GlobalExecutor.LEADER_TIMEOUT_MS, GlobalExecutor.HEARTBEAT_INTERVAL_MS); }
在init方法主要做了如下幾件事:
獲取Raft叢集節點 peers.add(NamingProxy.getServers()); Raft叢集資料恢復 RaftStore.load(); Raft選舉 GlobalExecutor.register(new MasterElection()); Raft心跳 GlobalExecutor.register(new HeartBeat()); Raft釋出內容 Raft保證內容一致性
其中,raft叢集內部節點間是透過暴露的Restful介面,程式碼在 RaftController 中。RaftController控制器是raft叢集內部節點間通訊使用的,具體的資訊如下:
POST HTTP://{ip:port}/v1/ns/raft/vote : 進行投票請求 POST HTTP://{ip:port}/v1/ns/raft/beat : Leader向Follower傳送心跳資訊 GET HTTP://{ip:port}/v1/ns/raft/peer : 獲取該節點的RaftPeer資訊 PUT HTTP://{ip:port}/v1/ns/raft/datum/reload : 重新載入某日誌資訊 POST HTTP://{ip:port}/v1/ns/raft/datum : Leader接收傳來的資料並存入 DELETE HTTP://{ip:port}/v1/ns/raft/datum : Leader接收傳來的資料刪除操作 GET HTTP://{ip:port}/v1/ns/raft/datum : 獲取該節點儲存的資料資訊 GET HTTP://{ip:port}/v1/ns/raft/state : 獲取該節點的狀態資訊{UP or DOWN} POST HTTP://{ip:port}/v1/ns/raft/datum/commit : Follower節點接收Leader傳來得到資料存入操作 DELETE HTTP://{ip:port}/v1/ns/raft/datum : Follower節點接收Leader傳來的資料刪除操作 GET HTTP://{ip:port}/v1/ns/raft/leader : 獲取當前叢集的Leader節點資訊 GET HTTP://{ip:port}/v1/ns/raft/listeners : 獲取當前Raft叢集的所有事件監聽者 RaftPeerSet
Raft中使用心跳機制來觸發leader選舉。心跳定時任務是在GlobalExecutor 中,透過 GlobalExecutor.register(new HeartBeat())註冊心跳定時任務,具體操作包括:
重置Leader節點的heart timeout、election timeout;
sendBeat()傳送心跳包 public class HeartBeat implements Runnable { @Override public void run() { try { if (!peers.isReady()) { return; } RaftPeer local = peers.local(); local.heartbeatDueMs -= GlobalExecutor.TICK_PERIOD_MS; if (local.heartbeatDueMs > 0) { return; } local.resetHeartbeatDue(); sendBeat(); } catch (Exception e) { Loggers.RAFT.warn("[RAFT] error while sending beat {}", e); } } }
簡單說明了下Nacos中的Raft一致性實現,更詳細的流程,可以下載原始碼,檢視 RaftCore 進行了解。原始碼可以透過以下地址檢出:
git clone
原文地址:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2675682/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 實現 Raft 協議Raft協議
- tikv/raft-rs:在 Rust 中實現的 Raft 分散式共識演算法原始碼RaftRust分散式演算法原始碼
- 4.3 Raft演算法Raft演算法
- 怎樣用純CSS實現禁止滑鼠點選事件?CSS事件
- zarusz/SlimCluster:在.NET中實現的Raft分散式共識演算法Raft分散式演算法
- 用Python寫演算法 | 蓄水池演算法實現隨機抽樣Python演算法隨機
- cornerstone中RAFT的buffer的實現Raft
- 怎樣用一行 Python 程式碼實現並行Python並行
- web 報表專案中想嵌入地圖?用什麼工具實現?怎樣實現?Web地圖
- Go實現Raft第二篇:選舉GoRaft
- Go 實現 Raft 第二篇:選舉GoRaft
- consul 原始碼解析(一)raft 協議實現原始碼Raft協議
- MCMC 、抽樣演算法與軟體實現演算法
- 怎麼實現像這樣草稿功能
- Raft共識演算法詳解Raft演算法
- 10分鐘弄懂Raft演算法Raft演算法
- 分散式入門,怎樣用PyTorch實現多GPU分散式訓練分散式PyTorchGPU
- Go實現Raft第一篇:介紹GoRaft
- Go 實現 Raft 第一篇:介紹GoRaft
- 開源 BI 的 實用性怎麼樣
- 分散式協議與演算法-Raft演算法分散式協議演算法Raft
- 螞蟻金服生產級 Raft 演算法庫儲存模組剖析 | SOFAJRaft 實現原理Raft演算法
- 幻影成像的實現原理是怎樣的?
- 怎樣實現填報表定時提交
- 深入剖析共識性演算法 Raft演算法Raft
- 分散式系統的Raft演算法分散式Raft演算法
- Spring Boot + Nacos 實現不停服釋出Spring Boot
- etcd學習(6)-etcd實現raft原始碼解讀Raft原始碼
- rnacos——用rust重新實現的nacos開源配置、註冊中心服務Rust
- POST 怎麼樣用
- 用 PHP 實現經典排序演算法PHP排序演算法
- Lumen XSS 防禦 和 SQL 注入怎樣實現SQL
- 那些算頻率的演算法,現在都怎麼樣了?演算法
- SpringCloudAlibaba - 整合 Nacos 實現服務註冊與發現SpringGCCloud
- Dubbo+Nacos實現服務註冊和發現
- Raft 演算法之叢集成員變更Raft演算法
- 保姆教程系列二、Nacos實現註冊中心
- Go 實現 Raft 第四篇:持久化和調優GoRaft持久化