日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

分布式一致性协议Raft原理与实例

發(fā)布時(shí)間:2024/9/20 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 分布式一致性协议Raft原理与实例 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

來源:http://m635674608.iteye.com/blog/2283621

1.Raft協(xié)議

1.1 Raft簡介

Raft是由Stanford提出的一種更易理解的一致性算法,意在取代目前廣為使用的Paxos算法。目前,在各種主流語言中都有了一些開源實(shí)現(xiàn),比如本文中將使用的基于JGroups的Raft協(xié)議實(shí)現(xiàn)。關(guān)于Raft的原理,強(qiáng)烈推薦動(dòng)畫版Raft講解。

1.2 Raft原理

在Raft中,每個(gè)結(jié)點(diǎn)會(huì)處于下面三種狀態(tài)中的一種:

  • follower:所有結(jié)點(diǎn)都以follower的狀態(tài)開始。如果沒收到leader消息則會(huì)變成candidate狀態(tài)
  • candidate:會(huì)向其他結(jié)點(diǎn)“拉選票”,如果得到大部分的票則成為leader。這個(gè)過程就叫做Leader選舉(Leader Election)
  • leader:所有對(duì)系統(tǒng)的修改都會(huì)先經(jīng)過leader。每個(gè)修改都會(huì)寫一條日志(log entry)。leader收到修改請求后的過程如下,這個(gè)過程叫做日志復(fù)制(Log Replication):?
  • 復(fù)制日志到所有follower結(jié)點(diǎn)(replicate entry)
  • 大部分結(jié)點(diǎn)響應(yīng)時(shí)才提交日志
  • 通知所有follower結(jié)點(diǎn)日志已提交
  • 所有follower也提交日志
  • 現(xiàn)在整個(gè)系統(tǒng)處于一致的狀態(tài)

1.2.1 Leader Election

當(dāng)follower在選舉超時(shí)時(shí)間(election timeout)內(nèi)未收到leader的心跳消息(append entries),則變成candidate狀態(tài)。為了避免選舉沖突,這個(gè)超時(shí)時(shí)間是一個(gè)150~300ms之間的隨機(jī)數(shù)

成為candidate的結(jié)點(diǎn)發(fā)起新的選舉期(election term)去“拉選票”:

  • 重置自己的計(jì)時(shí)器
  • 投自己一票
  • 發(fā)送?Request Vote消息
  • 如果接收結(jié)點(diǎn)在新term內(nèi)沒有投過票那它就會(huì)投給此candidate,并重置它自己的選舉超時(shí)時(shí)間。candidate拉到大部分選票就會(huì)成為leader,并定時(shí)發(fā)送心跳——Append Entries消息,去重置各個(gè)follower的計(jì)時(shí)器。當(dāng)前Term會(huì)繼續(xù)直到某個(gè)follower接收不到心跳并成為candidate。

    如果不巧兩個(gè)結(jié)點(diǎn)同時(shí)成為candidate都去“拉票”怎么辦?這時(shí)會(huì)發(fā)生Splite Vote情況。兩個(gè)結(jié)點(diǎn)可能都拉到了同樣多的選票,難分勝負(fù),選舉失敗,本term沒有l(wèi)eader。之后又有計(jì)時(shí)器超時(shí)的follower會(huì)變成candidate,將term加一并開始新一輪的投票。

    1.2.2 Log Replication

    當(dāng)發(fā)生改變時(shí),leader會(huì)復(fù)制日志給follower結(jié)點(diǎn),這也是通過Append Entries心跳消息完成的。前面已經(jīng)列舉了Log Replication的過程,這里就不重復(fù)了。

    Raft能夠正確地處理網(wǎng)絡(luò)分區(qū)(“腦裂”)問題。假設(shè)A~E五個(gè)結(jié)點(diǎn),B是leader。如果發(fā)生“腦裂”,A、B成為一個(gè)子分區(qū),C、D、E成 為一個(gè)子分區(qū)。此時(shí)C、D、E會(huì)發(fā)生選舉,選出C作為新term的leader。這樣我們在兩個(gè)子分區(qū)內(nèi)就有了不同term的兩個(gè)leader。這時(shí)如果 有客戶端寫A時(shí),因?yàn)锽無法復(fù)制日志到大部分follower所以日志處于uncommitted未提交狀態(tài)。而同時(shí)另一個(gè)客戶端對(duì)C的寫操作卻能夠正確 完成,因?yàn)镃是新的leader,它只知道D和E。

    當(dāng)網(wǎng)絡(luò)通信恢復(fù),B能夠發(fā)送心跳給C、D、E了,卻發(fā)現(xiàn)“改朝換代”了,因?yàn)镃的term值更大,所以B自動(dòng)降格為follower。然后A和B都回滾未提交的日志,并從新leader那里復(fù)制最新的日志。但這樣是不是就會(huì)丟失更新?


    2.JGroups-raft介紹

    2.1 JGroups中的Raft

    JGroups是Java里比較流行的網(wǎng)絡(luò)通信框架,近期順應(yīng)潮流,它也推出了Raft基于JGroups的實(shí)現(xiàn)。簡單試用了一下,還比較容易上 手,底層Raft的內(nèi)部機(jī)制都被API屏蔽掉了。下面就通過一個(gè)分布式計(jì)數(shù)器的實(shí)例來學(xué)習(xí)一下Raft協(xié)議在JGroups中的實(shí)際用法。

    Maven依賴如下:

    Prettyprint代碼??
  • <code?class="language-xml?hljs??has-numbering">????<span?class="hljs-tag"><<span?class="hljs-title">dependency</span>></span>??
  • ????????<span?class="hljs-tag"><<span?class="hljs-title">groupId</span>></span>org.jgroups<span?class="hljs-tag"></<span?class="hljs-title">groupId</span>></span>??
  • ????????<span?class="hljs-tag"><<span?class="hljs-title">artifactId</span>></span>jgroups-raft<span?class="hljs-tag"></<span?class="hljs-title">artifactId</span>></span>??
  • ????????<span?class="hljs-tag"><<span?class="hljs-title">version</span>></span>0.2<span?class="hljs-tag"></<span?class="hljs-title">version</span>></span>??
  • ????<span?class="hljs-tag"></<span?class="hljs-title">dependency</span>></span></code>??
    • 1
    • 2
    • 3
    • 4
    • 5

    其實(shí)JGroups-raft的Jar包中已經(jīng)自帶了一個(gè)Counter的Demo,但仔細(xì)看了一下,有的地方寫的有些麻煩,不太容易把握住Raft這根主線。所以這里就參照官方的例子,進(jìn)行了簡寫,突出Raft協(xié)議的基本使用方法。JGroups-raft目前資料不多,InfoQ上的這篇文章很不錯(cuò),還有官方文檔。

    2.2 核心API

    使用JGroups-raft時(shí),我們一般會(huì)實(shí)現(xiàn)兩個(gè)接口:RAFT.RoleChange和StateMachine

    • 實(shí)現(xiàn)RAFT.RoleChange接口的方法能通知我們當(dāng)前哪個(gè)結(jié)點(diǎn)是leader
    • 實(shí)現(xiàn)StateMachine執(zhí)行要實(shí)現(xiàn)一致性的操作

    典型單點(diǎn)服務(wù)實(shí)現(xiàn)方式就是:

    Prettyprint代碼??
  • <code?class="language-java?hljs??has-numbering">JChannel?ch?=?<span?class="hljs-keyword">null</span>;??
  • RaftHandle?handle?=?<span?class="hljs-keyword">new</span>?RaftHandle(ch,?<span?class="hljs-keyword">this</span>);??
  • handle.addRoleListener(role?->?{??
  • ????<span?class="hljs-keyword">if</span>(role?==?Role.Leader)??
  • ????????<span?class="hljs-comment">//?start?singleton?services</span>??
  • ????<span?class="hljs-keyword">else</span>??
  • ????????<span?class="hljs-comment">//?stop?singleton?services</span>??
  • });</code>??
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.3 默認(rèn)配置

    jgroups-raft.jar中已經(jīng)帶了一個(gè)raft.xml配置文件,作為實(shí)例程序我們可以直接使用它。

    簡要解釋一下最核心的幾個(gè)配置項(xiàng),參照GitHub上的文檔:

    • UDP:IP多播配置
    • raft.NO_DUPES:是否檢測新加入結(jié)點(diǎn)的ID與老結(jié)點(diǎn)有重復(fù)
    • raft.ELECTION:選舉超時(shí)時(shí)間的隨機(jī)化范圍
    • raft.RAFT所有Raft集群的成員必須在這里聲明,也可以在運(yùn)行時(shí)通過addServer/removeServer動(dòng)態(tài)修改
    • raft.REDIRECT:是否轉(zhuǎn)發(fā)請求給leader
    • raft.CLIENT:在哪個(gè)IP和端口上接收客戶端請求
    Prettyprint代碼??
  • <code?class="language-xml?hljs??has-numbering"><span?class="hljs-comment"><!--??
  • ??Default?stack?using?IP?multicasting.?It?is?similar?to?the?"udp"??
  • ??stack?in?stacks.xml,?but?doesn't?use?streaming?state?transfer?and?flushing??
  • ??author:?Bela?Ban??
  • --></span>??
  • ??
  • <span?class="hljs-tag"><<span?class="hljs-title">config</span>?<span?class="hljs-attribute">xmlns</span>=<span?class="hljs-value">"urn:org:jgroups"</span>??
  • ????????<span?class="hljs-attribute">xmlns:xsi</span>=<span?class="hljs-value">"http://www.w3.org/2001/XMLSchema-instance"</span>??
  • ????????<span?class="hljs-attribute">xsi:schemaLocation</span>=<span?class="hljs-value">"urn:org:jgroups?http://www.jgroups.org/schema/jgroups.xsd"</span>></span>??
  • ????<span?class="hljs-tag"><<span?class="hljs-title">UDP??
  • </span>?????????<span?class="hljs-attribute">mcast_addr</span>=<span?class="hljs-value">"228.5.5.5"</span>??
  • ?????????<span?class="hljs-attribute">mcast_port</span>=<span?class="hljs-value">"${jgroups.udp.mcast_port:45588}"</span>??
  • ?????????<span?class="hljs-attribute">...</span>?/></span>??
  • ????...??
  • ????<span?class="hljs-tag"><<span?class="hljs-title">raft.NO_DUPES</span>/></span>??
  • ????<span?class="hljs-tag"><<span?class="hljs-title">raft.ELECTION</span>?<span?class="hljs-attribute">election_min_interval</span>=<span?class="hljs-value">"100"</span>?<span?class="hljs-attribute">election_max_interval</span>=<span?class="hljs-value">"500"</span>/></span>??
  • ????<span?class="hljs-tag"><<span?class="hljs-title">raft.RAFT</span>?<span?class="hljs-attribute">members</span>=<span?class="hljs-value">"A,B,C"</span>?<span?class="hljs-attribute">raft_id</span>=<span?class="hljs-value">"${raft_id:undefined}"</span>/></span>??
  • ????<span?class="hljs-tag"><<span?class="hljs-title">raft.REDIRECT</span>/></span>??
  • ????<span?class="hljs-tag"><<span?class="hljs-title">raft.CLIENT</span>?<span?class="hljs-attribute">bind_addr</span>=<span?class="hljs-value">"0.0.0.0"</span>?/></span>??
  • <span?class="hljs-tag"></<span?class="hljs-title">config</span>></span></code>??
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.JGroups-raft實(shí)例

    實(shí)例很簡單,只有JGroupsRaftTest和CounterService兩個(gè)類組成。JGroupsRaftTest是測試啟動(dòng)類,而CounterService就是利用Raft協(xié)議實(shí)現(xiàn)的分布式計(jì)數(shù)服務(wù)類。

    3.1 JGroupsRaftTest

    JGroupsRaftTest的職責(zé)主要有三個(gè):

    • 創(chuàng)建Raft協(xié)議的JChannel
    • 創(chuàng)建CounterService
    • 循環(huán)讀取用戶輸入

    目前簡單實(shí)現(xiàn)了幾種操作包括:初始化計(jì)數(shù)器、加一、減一、讀取計(jì)數(shù)器、查看Raft日志、做Raft快照(用于壓縮日志文件)等。其中對(duì)計(jì)數(shù)器的操作,因?yàn)橐c其他Raft成員進(jìn)行分布式通信,所以當(dāng)前集群必須要多于一個(gè)結(jié)點(diǎn)時(shí)才能進(jìn)行操作。如果要支持單結(jié)點(diǎn)時(shí)的操作,需要做特殊處理

    Prettyprint代碼??
  • <code?class="language-java?hljs??has-numbering"><span?class="hljs-keyword">import</span>?org.jgroups.JChannel;??
  • <span?class="hljs-keyword">import</span>?org.jgroups.protocols.raft.RAFT;??
  • <span?class="hljs-keyword">import</span>?org.jgroups.util.Util;??
  • ??
  • <span?class="hljs-javadoc">/**??
  • ?*?Test?jgroups?raft?algorithm?implementation.??
  • ?*/</span>??
  • <span?class="hljs-keyword">public</span>?<span?class="hljs-class"><span?class="hljs-keyword">class</span>?<span?class="hljs-title">JGroupsRaftTest</span>?{</span>??
  • ??
  • ????<span?class="hljs-keyword">private</span>?<span?class="hljs-keyword">static</span>?<span?class="hljs-keyword">final</span>?String?CLUSTER_NAME?=?<span?class="hljs-string">"ctr-cluster"</span>;??
  • ????<span?class="hljs-keyword">private</span>?<span?class="hljs-keyword">static</span>?<span?class="hljs-keyword">final</span>?String?COUNTER_NAME?=?<span?class="hljs-string">"counter"</span>;??
  • ????<span?class="hljs-keyword">private</span>?<span?class="hljs-keyword">static</span>?<span?class="hljs-keyword">final</span>?String?RAFT_XML?=?<span?class="hljs-string">"raft.xml"</span>;??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">static</span>?<span?class="hljs-keyword">void</span>?<span?class="hljs-title">main</span>(String[]?args)?<span?class="hljs-keyword">throws</span>?Exception?{??
  • ????????JChannel?ch?=?<span?class="hljs-keyword">new</span>?JChannel(RAFT_XML).name(args[<span?class="hljs-number">0</span>]);??
  • ????????CounterService?counter?=?<span?class="hljs-keyword">new</span>?CounterService(ch);??
  • ??
  • ????????<span?class="hljs-keyword">try</span>?{??
  • ????????????doConnect(ch,?CLUSTER_NAME);??
  • ????????????doLoop(ch,?counter);??
  • ????????}?<span?class="hljs-keyword">finally</span>?{??
  • ????????????Util.close(ch);??
  • ????????}??
  • ????}??
  • ??
  • ????<span?class="hljs-keyword">private</span>?<span?class="hljs-keyword">static</span>?<span?class="hljs-keyword">void</span>?<span?class="hljs-title">doConnect</span>(JChannel?ch,?String?clusterName)?<span?class="hljs-keyword">throws</span>?Exception?{??
  • ????????ch.connect(clusterName);??
  • ????}??
  • ??
  • ????<span?class="hljs-keyword">private</span>?<span?class="hljs-keyword">static</span>?<span?class="hljs-keyword">void</span>?<span?class="hljs-title">doLoop</span>(JChannel?ch,?CounterService?counter)?{??
  • ????????<span?class="hljs-keyword">boolean</span>?looping?=?<span?class="hljs-keyword">true</span>;??
  • ????????<span?class="hljs-keyword">while</span>?(looping)?{??
  • ????????????<span?class="hljs-keyword">int</span>?key?=?Util.keyPress(<span?class="hljs-string">"\n[0]?Create?[1]?Increment?[2]?Decrement?[3]?Dump?log?[4]?Snapshot?[x]?Exit\n"</span>?+??
  • ????????????????????<span?class="hljs-string">"first-applied="</span>?+?((RAFT)?ch.getProtocolStack().findProtocol(RAFT.class)).log().firstApplied()?+??
  • ????????????????????<span?class="hljs-string">",?last-applied="</span>?+?counter.lastApplied()?+??
  • ????????????????????<span?class="hljs-string">",?commit-index="</span>?+?counter.commitIndex()?+??
  • ????????????????????<span?class="hljs-string">",?log?size="</span>?+?Util.printBytes(counter.logSize())?+?<span?class="hljs-string">":?"</span>);??
  • ??
  • ????????????<span?class="hljs-keyword">if</span>?((key?==?<span?class="hljs-string">'0'</span>?||?key?==?<span?class="hljs-string">'1'</span>?||?key?==?<span?class="hljs-string">'2'</span>)?&&?!counter.isLeaderExist())?{??
  • ????????????????System.out.println(<span?class="hljs-string">"Cannot?perform?cause?there?is?no?leader?by?now"</span>);??
  • ????????????????<span?class="hljs-keyword">continue</span>;??
  • ????????????}??
  • ??
  • ????????????<span?class="hljs-keyword">long</span>?val;??
  • ????????????<span?class="hljs-keyword">switch</span>?(key)?{??
  • ????????????????<span?class="hljs-keyword">case</span>?<span?class="hljs-string">'0'</span>:??
  • ????????????????????counter.getOrCreateCounter(COUNTER_NAME,?<span?class="hljs-number">1</span>L);??
  • ????????????????????<span?class="hljs-keyword">break</span>;??
  • ????????????????<span?class="hljs-keyword">case</span>?<span?class="hljs-string">'1'</span>:??
  • ????????????????????val?=?counter.incrementAndGet(COUNTER_NAME);??
  • ????????????????????System.out.printf(<span?class="hljs-string">"%s:?%s\n"</span>,?COUNTER_NAME,?val);??
  • ????????????????????<span?class="hljs-keyword">break</span>;??
  • ????????????????<span?class="hljs-keyword">case</span>?<span?class="hljs-string">'2'</span>:??
  • ????????????????????val?=?counter.decrementAndGet(COUNTER_NAME);??
  • ????????????????????System.out.printf(<span?class="hljs-string">"%s:?%s\n"</span>,?COUNTER_NAME,?val);??
  • ????????????????????<span?class="hljs-keyword">break</span>;??
  • ????????????????<span?class="hljs-keyword">case</span>?<span?class="hljs-string">'3'</span>:??
  • ????????????????????counter.dumpLog();??
  • ????????????????????<span?class="hljs-keyword">break</span>;??
  • ????????????????<span?class="hljs-keyword">case</span>?<span?class="hljs-string">'4'</span>:??
  • ????????????????????counter.snapshot();??
  • ????????????????????<span?class="hljs-keyword">break</span>;??
  • ????????????????<span?class="hljs-keyword">case</span>?<span?class="hljs-string">'x'</span>:??
  • ????????????????????looping?=?<span?class="hljs-keyword">false</span>;??
  • ????????????????????<span?class="hljs-keyword">break</span>;??
  • ????????????????<span?class="hljs-keyword">case</span>?<span?class="hljs-string">'\n'</span>:??
  • ????????????????????System.out.println(COUNTER_NAME?+?<span?class="hljs-string">":?"</span>?+?counter.get(COUNTER_NAME)?+?<span?class="hljs-string">"\n"</span>);??
  • ????????????????????<span?class="hljs-keyword">break</span>;??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??
  • }</code>??
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    3.2 CounterService

    CounterService是我們的核心類,利用Raft實(shí)現(xiàn)了分布式的計(jì)數(shù)器操作,它的API主要由四部分組成:

    • Raft Local API:操作本地Raft的狀態(tài),像日志大小、做快照等
    • Raft API:實(shí)現(xiàn)Raft的監(jiān)聽器和狀態(tài)機(jī)的方法?
      • roleChanged:本地Raft的角色發(fā)生變化
      • apply:分布式通信消息
      • readContentFrom/writeContentTo:讀寫快照
    • Counter API:計(jì)數(shù)器的分布式API
    • Counter Native API:計(jì)數(shù)器的本地API。直接使用的話相當(dāng)于臟讀
    Prettyprint代碼??
  • <code?class="language-java?hljs??has-numbering"><span?class="hljs-keyword">import</span>?org.jgroups.Channel;??
  • <span?class="hljs-keyword">import</span>?org.jgroups.protocols.raft.RAFT;??
  • <span?class="hljs-keyword">import</span>?org.jgroups.protocols.raft.Role;??
  • <span?class="hljs-keyword">import</span>?org.jgroups.protocols.raft.StateMachine;??
  • <span?class="hljs-keyword">import</span>?org.jgroups.raft.RaftHandle;??
  • <span?class="hljs-keyword">import</span>?org.jgroups.util.AsciiString;??
  • <span?class="hljs-keyword">import</span>?org.jgroups.util.Bits;??
  • <span?class="hljs-keyword">import</span>?org.jgroups.util.ByteArrayDataInputStream;??
  • <span?class="hljs-keyword">import</span>?org.jgroups.util.ByteArrayDataOutputStream;??
  • <span?class="hljs-keyword">import</span>?org.jgroups.util.Util;??
  • ??
  • <span?class="hljs-keyword">import</span>?java.io.DataInput;??
  • <span?class="hljs-keyword">import</span>?java.io.DataOutput;??
  • <span?class="hljs-keyword">import</span>?java.io.IOException;??
  • <span?class="hljs-keyword">import</span>?java.text.SimpleDateFormat;??
  • <span?class="hljs-keyword">import</span>?java.util.Date;??
  • <span?class="hljs-keyword">import</span>?java.util.HashMap;??
  • <span?class="hljs-keyword">import</span>?java.util.Map;??
  • ??
  • <span?class="hljs-javadoc">/**??
  • ?*?Distribute?counter?service?based?on?Raft?consensus?algorithm.??
  • ?*/</span>??
  • class?CounterService?implements?StateMachine,?RAFT.RoleChange?{??
  • ??
  • ????<span?class="hljs-keyword">private</span>?RaftHandle?raft;??
  • ??
  • ????<span?class="hljs-keyword">private</span>?<span?class="hljs-keyword">final</span>?Map<String,?Long>?counters;??
  • ??
  • ????<span?class="hljs-keyword">private</span>?<span?class="hljs-keyword">enum</span>?Command?{??
  • ????????CREATE,?INCREMENT_AND_GET,?DECREMENT_AND_GET,?GET,?SET??
  • ????}??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-title">CounterService</span>(Channel?ch)?{??
  • ????????<span?class="hljs-keyword">this</span>.raft?=?<span?class="hljs-keyword">new</span>?RaftHandle(ch,?<span?class="hljs-keyword">this</span>);??
  • ????????<span?class="hljs-keyword">this</span>.counters?=?<span?class="hljs-keyword">new</span>?HashMap<>();??
  • ??
  • ????????raft.raftId(ch.getName())??
  • ????????????.addRoleListener(<span?class="hljs-keyword">this</span>);??
  • ????}??
  • ??
  • ????<span?class="hljs-comment">//?===========================================</span>??
  • ????<span?class="hljs-comment">//??????????????Raft?Status?API</span>??
  • ????<span?class="hljs-comment">//?===========================================</span>??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">int</span>?<span?class="hljs-title">lastApplied</span>()?{??
  • ????????<span?class="hljs-keyword">return</span>?raft.lastApplied();??
  • ????}??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">int</span>?<span?class="hljs-title">commitIndex</span>()?{??
  • ????????<span?class="hljs-keyword">return</span>?raft.commitIndex();??
  • ????}??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">int</span>?<span?class="hljs-title">logSize</span>()?{??
  • ????????<span?class="hljs-keyword">return</span>?raft.logSize();??
  • ????}??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">void</span>?<span?class="hljs-title">dumpLog</span>()?{??
  • ????????System.out.println(<span?class="hljs-string">"\nindex?(term):?command\n---------------------"</span>);??
  • ????????raft.logEntries((entry,?index)?->?{??
  • ????????????StringBuilder?log?=?<span?class="hljs-keyword">new</span>?StringBuilder()??
  • ????????????????????.append(index)??
  • ????????????????????.append(<span?class="hljs-string">"?("</span>).append(entry.term()).append(<span?class="hljs-string">"):?"</span>);??
  • ??
  • ????????????<span?class="hljs-keyword">if</span>?(entry.command()?==?<span?class="hljs-keyword">null</span>?)?{??
  • ????????????????System.out.println(log.append(<span?class="hljs-string">"<marker?record>"</span>));??
  • ????????????????<span?class="hljs-keyword">return</span>;??
  • ????????????}?<span?class="hljs-keyword">else</span>?<span?class="hljs-keyword">if</span>?(entry.internal())?{??
  • ????????????????System.out.println(log.append(<span?class="hljs-string">"<internal?command>"</span>));??
  • ????????????????<span?class="hljs-keyword">return</span>;??
  • ????????????}??
  • ??
  • ????????????ByteArrayDataInputStream?in?=?<span?class="hljs-keyword">new</span>?ByteArrayDataInputStream(??
  • ????????????????????entry.command(),?entry.offset(),?entry.length()??
  • ????????????);??
  • ????????????<span?class="hljs-keyword">try</span>?{??
  • ????????????????Command?cmd?=?Command.values()[in.readByte()];??
  • ????????????????String?name?=?Bits.readAsciiString(in).toString();??
  • ????????????????<span?class="hljs-keyword">switch</span>?(cmd)?{??
  • ????????????????????<span?class="hljs-keyword">case</span>?CREATE:??
  • ????????????????????????log.append(cmd)??
  • ????????????????????????????.append(<span?class="hljs-string">"("</span>).append(name).append(<span?class="hljs-string">",?"</span>)??
  • ????????????????????????????.append(Bits.readLong(in))??
  • ????????????????????????????.append(<span?class="hljs-string">")"</span>);??
  • ????????????????????????<span?class="hljs-keyword">break</span>;??
  • ????????????????????<span?class="hljs-keyword">case</span>?GET:??
  • ????????????????????<span?class="hljs-keyword">case</span>?INCREMENT_AND_GET:??
  • ????????????????????<span?class="hljs-keyword">case</span>?DECREMENT_AND_GET:??
  • ????????????????????????log.append(cmd)??
  • ????????????????????????????.append(<span?class="hljs-string">"("</span>).append(name).append(<span?class="hljs-string">")"</span>);??
  • ????????????????????????<span?class="hljs-keyword">break</span>;??
  • ????????????????????<span?class="hljs-keyword">default</span>:??
  • ????????????????????????<span?class="hljs-keyword">throw</span>?<span?class="hljs-keyword">new</span>?IllegalArgumentException(<span?class="hljs-string">"Command?"</span>?+?cmd?+?<span?class="hljs-string">"is?unknown"</span>);??
  • ????????????????}??
  • ????????????????System.out.println(log);??
  • ????????????}??
  • ????????????<span?class="hljs-keyword">catch</span>?(IOException?e)?{??
  • ????????????????<span?class="hljs-keyword">throw</span>?<span?class="hljs-keyword">new</span>?IllegalStateException(<span?class="hljs-string">"Error?when?dump?log"</span>,?e);??
  • ????????????}??
  • ????????});??
  • ????????System.out.println();??
  • ????}??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">void</span>?<span?class="hljs-title">snapshot</span>()?{??
  • ????????<span?class="hljs-keyword">try</span>?{??
  • ????????????raft.snapshot();??
  • ????????}?<span?class="hljs-keyword">catch</span>?(Exception?e)?{??
  • ????????????<span?class="hljs-keyword">throw</span>?<span?class="hljs-keyword">new</span>?IllegalStateException(<span?class="hljs-string">"Error?when?snapshot"</span>,?e);??
  • ????????}??
  • ????}??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">boolean</span>?<span?class="hljs-title">isLeaderExist</span>()?{??
  • ????????<span?class="hljs-keyword">return</span>?raft.leader()?!=?<span?class="hljs-keyword">null</span>;??
  • ????}??
  • ??
  • ????<span?class="hljs-comment">//?===========================================</span>??
  • ????<span?class="hljs-comment">//??????????????Raft?API</span>??
  • ????<span?class="hljs-comment">//?===========================================</span>??
  • ??
  • ????<span?class="hljs-annotation">@Override</span>??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">void</span>?<span?class="hljs-title">roleChanged</span>(Role?role)?{??
  • ????????System.out.println(<span?class="hljs-string">"roleChanged?to:?"</span>?+?role);??
  • ????}??
  • ??
  • ????<span?class="hljs-annotation">@Override</span>??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">byte</span>[]?<span?class="hljs-title">apply</span>(<span?class="hljs-keyword">byte</span>[]?data,?<span?class="hljs-keyword">int</span>?offset,?<span?class="hljs-keyword">int</span>?length)?<span?class="hljs-keyword">throws</span>?Exception?{??
  • ????????ByteArrayDataInputStream?in?=?<span?class="hljs-keyword">new</span>?ByteArrayDataInputStream(data,?offset,?length);??
  • ????????Command?cmd?=?Command.values()[in.readByte()];??
  • ????????String?name?=?Bits.readAsciiString(in).toString();??
  • ????????System.out.println(<span?class="hljs-string">"["</span>?+?<span?class="hljs-keyword">new</span>?SimpleDateFormat(<span?class="hljs-string">"HH:mm:ss.SSS"</span>).format(<span?class="hljs-keyword">new</span>?Date())??
  • ????????????????+?<span?class="hljs-string">"]?Apply:?cmd=["</span>?+?cmd?+?<span?class="hljs-string">"]"</span>);??
  • ??
  • ????????<span?class="hljs-keyword">long</span>?v1,?retVal;??
  • ????????<span?class="hljs-keyword">switch</span>?(cmd)?{??
  • ????????????<span?class="hljs-keyword">case</span>?CREATE:??
  • ????????????????v1?=?Bits.readLong(in);??
  • ????????????????retVal?=?create0(name,?v1);??
  • ????????????????<span?class="hljs-keyword">return</span>?Util.objectToByteBuffer(retVal);??
  • ????????????<span?class="hljs-keyword">case</span>?GET:??
  • ????????????????retVal?=?get0(name);??
  • ????????????????<span?class="hljs-keyword">return</span>?Util.objectToByteBuffer(retVal);??
  • ????????????<span?class="hljs-keyword">case</span>?INCREMENT_AND_GET:??
  • ????????????????retVal?=?add0(name,?<span?class="hljs-number">1</span>L);??
  • ????????????????<span?class="hljs-keyword">return</span>?Util.objectToByteBuffer(retVal);??
  • ????????????<span?class="hljs-keyword">case</span>?DECREMENT_AND_GET:??
  • ????????????????retVal?=?add0(name,?-<span?class="hljs-number">1</span>L);??
  • ????????????????<span?class="hljs-keyword">return</span>?Util.objectToByteBuffer(retVal);??
  • ????????????<span?class="hljs-keyword">default</span>:??
  • ????????????????<span?class="hljs-keyword">throw</span>?<span?class="hljs-keyword">new</span>?IllegalArgumentException(<span?class="hljs-string">"Command?"</span>?+?cmd?+?<span?class="hljs-string">"is?unknown"</span>);??
  • ????????}??
  • ????}??
  • ??
  • ????<span?class="hljs-annotation">@Override</span>??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">void</span>?<span?class="hljs-title">readContentFrom</span>(DataInput?in)?<span?class="hljs-keyword">throws</span>?Exception?{??
  • ????????<span?class="hljs-keyword">int</span>?size?=?in.readInt();??
  • ????????System.out.println(<span?class="hljs-string">"ReadContentFrom:?size=["</span>?+?size?+?<span?class="hljs-string">"]"</span>);??
  • ????????<span?class="hljs-keyword">for</span>?(<span?class="hljs-keyword">int</span>?i?=?<span?class="hljs-number">0</span>;?i?<?size;?i++)?{??
  • ????????????AsciiString?name?=?Bits.readAsciiString(in);??
  • ????????????Long?value?=?Bits.readLong(in);??
  • ????????????counters.put(name.toString(),?value);??
  • ????????}??
  • ????}??
  • ??
  • ????<span?class="hljs-annotation">@Override</span>??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">void</span>?<span?class="hljs-title">writeContentTo</span>(DataOutput?out)?<span?class="hljs-keyword">throws</span>?Exception?{??
  • ????????<span?class="hljs-keyword">synchronized</span>?(counters)?{??
  • ????????????<span?class="hljs-keyword">int</span>?size?=?counters.size();??
  • ????????????System.out.println(<span?class="hljs-string">"WriteContentFrom:?size=["</span>?+?size?+?<span?class="hljs-string">"]"</span>);??
  • ????????????out.writeInt(size);??
  • ????????????<span?class="hljs-keyword">for</span>?(Map.Entry<String,?Long>?entry?:?counters.entrySet())?{??
  • ????????????????AsciiString?name?=?<span?class="hljs-keyword">new</span>?AsciiString(entry.getKey());??
  • ????????????????Long?value?=?entry.getValue();??
  • ????????????????Bits.writeAsciiString(name,?out);??
  • ????????????????Bits.writeLong(value,?out);??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??
  • ????<span?class="hljs-comment">//?===========================================</span>??
  • ????<span?class="hljs-comment">//??????????????Counter?API</span>??
  • ????<span?class="hljs-comment">//?===========================================</span>??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">void</span>?<span?class="hljs-title">getOrCreateCounter</span>(String?name,?<span?class="hljs-keyword">long</span>?initVal)?{??
  • ????????Object?retVal?=?invoke(Command.CREATE,?name,?<span?class="hljs-keyword">false</span>,?initVal);??
  • ????????counters.put(name,?(Long)?retVal);??
  • ????}??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">long</span>?<span?class="hljs-title">incrementAndGet</span>(String?name)?{??
  • ????????<span?class="hljs-keyword">return</span>?(<span?class="hljs-keyword">long</span>)?invoke(Command.INCREMENT_AND_GET,?name,?<span?class="hljs-keyword">false</span>);??
  • ????}??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">long</span>?<span?class="hljs-title">decrementAndGet</span>(String?name)?{??
  • ????????<span?class="hljs-keyword">return</span>?(<span?class="hljs-keyword">long</span>)?invoke(Command.DECREMENT_AND_GET,?name,?<span?class="hljs-keyword">false</span>);??
  • ????}??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">long</span>?<span?class="hljs-title">get</span>(String?name)?{??
  • ????????<span?class="hljs-keyword">return</span>?(<span?class="hljs-keyword">long</span>)?invoke(Command.GET,?name,?<span?class="hljs-keyword">false</span>);??
  • ????}??
  • ??
  • ????<span?class="hljs-keyword">private</span>?Object?<span?class="hljs-title">invoke</span>(Command?cmd,?String?name,?<span?class="hljs-keyword">boolean</span>?ignoreRetVal,?<span?class="hljs-keyword">long</span>...?values)?{??
  • ????????ByteArrayDataOutputStream?out?=?<span?class="hljs-keyword">new</span>?ByteArrayDataOutputStream(<span?class="hljs-number">256</span>);??
  • ????????<span?class="hljs-keyword">try</span>?{??
  • ????????????out.writeByte(cmd.ordinal());??
  • ????????????Bits.writeAsciiString(<span?class="hljs-keyword">new</span>?AsciiString(name),?out);??
  • ????????????<span?class="hljs-keyword">for</span>?(<span?class="hljs-keyword">long</span>?val?:?values)?{??
  • ????????????????Bits.writeLong(val,?out);??
  • ????????????}??
  • ??
  • ????????????<span?class="hljs-keyword">byte</span>[]?rsp?=?raft.set(out.buffer(),?<span?class="hljs-number">0</span>,?out.position());??
  • ????????????<span?class="hljs-keyword">return</span>?ignoreRetVal???<span?class="hljs-keyword">null</span>?:?Util.objectFromByteBuffer(rsp);??
  • ????????}??
  • ????????<span?class="hljs-keyword">catch</span>?(IOException?ex)?{??
  • ????????????<span?class="hljs-keyword">throw</span>?<span?class="hljs-keyword">new</span>?RuntimeException(<span?class="hljs-string">"Serialization?failure?(cmd="</span>??
  • ????????????????????+?cmd?+?<span?class="hljs-string">",?name="</span>?+?name?+?<span?class="hljs-string">")"</span>,?ex);??
  • ????????}??
  • ????????<span?class="hljs-keyword">catch</span>?(Exception?ex)?{??
  • ????????????<span?class="hljs-keyword">throw</span>?<span?class="hljs-keyword">new</span>?RuntimeException(<span?class="hljs-string">"Raft?set?failure?(cmd="</span>??
  • ????????????????????+?cmd?+?<span?class="hljs-string">",?name="</span>?+?name?+?<span?class="hljs-string">")"</span>,?ex);??
  • ????????}??
  • ????}??
  • ??
  • ????<span?class="hljs-comment">//?===========================================</span>??
  • ????<span?class="hljs-comment">//??????????????Counter?Native?API</span>??
  • ????<span?class="hljs-comment">//?===========================================</span>??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">synchronized</span>?Long?<span?class="hljs-title">create0</span>(String?name,?<span?class="hljs-keyword">long</span>?initVal)?{??
  • ????????counters.putIfAbsent(name,?initVal);??
  • ????????<span?class="hljs-keyword">return</span>?counters.get(name);??
  • ????}??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">synchronized</span>?Long?<span?class="hljs-title">get0</span>(String?name)?{??
  • ????????<span?class="hljs-keyword">return</span>?counters.getOrDefault(name,?<span?class="hljs-number">0</span>L);??
  • ????}??
  • ??
  • ????<span?class="hljs-keyword">public</span>?<span?class="hljs-keyword">synchronized</span>?Long?<span?class="hljs-title">add0</span>(String?name,?<span?class="hljs-keyword">long</span>?delta)?{??
  • ????????Long?oldVal?=?counters.getOrDefault(name,?<span?class="hljs-number">0</span>L);??
  • ????????<span?class="hljs-keyword">return</span>?counters.put(name,?oldVal?+?delta);??
  • ????}??
  • }</code>??
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238

    3.3 運(yùn)行測試

    我們分別以A、B、C為參數(shù),啟動(dòng)三個(gè)JGroupsRaftTest服務(wù)。這樣會(huì)自動(dòng)在C:\Users\cdai\AppData\Local\Temp下生成A.log、B.log、C.log三個(gè)日志文件夾。

    Prettyprint代碼??
  • <code?class="hljs?livecodeserver?has-numbering">cdai@vm?/cygdrive/c/Users/cdai/AppData/Local/Temp??
  • $?tree?A.<span?class="hljs-built_in">log</span>/?B.<span?class="hljs-built_in">log</span>/?C.<span?class="hljs-built_in">log</span>/??
  • A.<span?class="hljs-built_in">log</span>/??
  • |<span?class="hljs-comment">--?000005.sst</span>??
  • |<span?class="hljs-comment">--?000006.log</span>??
  • |<span?class="hljs-comment">--?CURRENT</span>??
  • |<span?class="hljs-comment">--?LOCK</span>??
  • |<span?class="hljs-comment">--?LOG</span>??
  • |<span?class="hljs-comment">--?LOG.old</span>??
  • `<span?class="hljs-comment">--?MANIFEST-000004</span>??
  • B.<span?class="hljs-built_in">log</span>/??
  • |<span?class="hljs-comment">--?000003.log</span>??
  • |<span?class="hljs-comment">--?CURRENT</span>??
  • |<span?class="hljs-comment">--?LOCK</span>??
  • |<span?class="hljs-comment">--?LOG</span>??
  • `<span?class="hljs-comment">--?MANIFEST-000002</span>??
  • C.<span?class="hljs-built_in">log</span>/??
  • |<span?class="hljs-comment">--?000003.log</span>??
  • |<span?class="hljs-comment">--?CURRENT</span>??
  • |<span?class="hljs-comment">--?LOCK</span>??
  • |<span?class="hljs-comment">--?LOG</span>??
  • `<span?class="hljs-comment">--?MANIFEST-000002</span>??
  • ??
  • <span?class="hljs-number">0</span>?<span?class="hljs-built_in">directories</span>,?<span?class="hljs-number">17</span>?<span?class="hljs-built_in">files</span></code>??
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3.3.1 分布式一致性

    首先A創(chuàng)建計(jì)數(shù)器,B“加一”,C“減一”。可以看到盡管我們是分別在A、B、C上執(zhí)行這三個(gè)操作,但三個(gè)結(jié)點(diǎn)都先后(leader提交日志后通知follower)通過apply()方法收到消息,并在本地的計(jì)數(shù)器Map上同步執(zhí)行操作,保證了數(shù)據(jù)的一致性。最后停掉A服務(wù),可以看到B通過roleChanged()得到消息,提升為新的Leader,并與C一同繼續(xù)提供服務(wù)。

    A的控制臺(tái)輸出:

    Prettyprint代碼??
  • <code?class="hljs?asciidoc?has-numbering"><span?class="hljs-code">-------------------------------------------------------------------??
  • GMS:?address=A,?cluster=ctr-cluster,?physical?address=2001:0:9d38:6abd:cbb:1f78:3f57:50f6:50100??
  • -------------------------------------------------------------------</span>??
  • ??
  • [0]?Create?[1]?Increment?[2]?Decrement?[3]?Dump?log?[4]?Snapshot?[x]?Exit??
  • first-applied=0,?last-applied=0,?commit-index=0,?log?size=0b:???
  • roleChanged?to:?Candidate??
  • roleChanged?to:?Leader??
  • 0??
  • <span?class="hljs-attribute">[14:16:00.744]?Apply:?cmd=[CREATE]</span>??
  • ??
  • [0]?Create?[1]?Increment?[2]?Decrement?[3]?Dump?log?[4]?Snapshot?[x]?Exit??
  • first-applied=0,?last-applied=1,?commit-index=1,?log?size=1b:???
  • <span?class="hljs-attribute">[14:16:07.002]?Apply:?cmd=[INCREMENT_AND_GET]</span>??
  • <span?class="hljs-attribute">[14:16:14.264]?Apply:?cmd=[DECREMENT_AND_GET]</span>??
  • 3??
  • ??
  • <span?class="hljs-header">index?(term):?command??
  • ---------------------</span>??
  • 1?(29):?CREATE(counter,?1)??
  • 2?(29):?INCREMENT<span?class="hljs-emphasis">_AND_</span>GET(counter)??
  • 3?(29):?DECREMENT<span?class="hljs-emphasis">_AND_</span>GET(counter)</code>??
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    B的控制臺(tái)輸出:

    Prettyprint代碼??
  • <code?class="hljs?sql?has-numbering"><span?class="hljs-comment">-------------------------------------------------------------------</span>??
  • GMS:?address=B,?cluster=ctr-cluster,?physical?address=2001:0:9d38:6abd:cbb:1f78:3f57:50f6:50101??
  • <span?class="hljs-comment">-------------------------------------------------------------------</span>??
  • ??
  • [0]?<span?class="hljs-operator"><span?class="hljs-keyword">Create</span>?[<span?class="hljs-number">1</span>]?Increment?[<span?class="hljs-number">2</span>]?Decrement?[<span?class="hljs-number">3</span>]?Dump?log?[<span?class="hljs-number">4</span>]?Snapshot?[x]?Exit??
  • <span?class="hljs-keyword">first</span>-applied=<span?class="hljs-number">0</span>,?<span?class="hljs-keyword">last</span>-applied=<span?class="hljs-number">0</span>,?<span?class="hljs-keyword">commit</span>-index=<span?class="hljs-number">0</span>,?log?<span?class="hljs-keyword">size</span>=<span?class="hljs-number">0</span>b:???
  • [<span?class="hljs-number">14</span>:<span?class="hljs-number">16</span>:<span?class="hljs-number">01.300</span>]?Apply:?cmd=[<span?class="hljs-keyword">CREATE</span>]??
  • <span?class="hljs-number">1</span>??
  • counter:?<span?class="hljs-number">2</span>??
  • ??
  • [<span?class="hljs-number">0</span>]?<span?class="hljs-keyword">Create</span>?[<span?class="hljs-number">1</span>]?Increment?[<span?class="hljs-number">2</span>]?Decrement?[<span?class="hljs-number">3</span>]?Dump?log?[<span?class="hljs-number">4</span>]?Snapshot?[x]?Exit??
  • <span?class="hljs-keyword">first</span>-applied=<span?class="hljs-number">0</span>,?<span?class="hljs-keyword">last</span>-applied=<span?class="hljs-number">2</span>,?<span?class="hljs-keyword">commit</span>-index=<span?class="hljs-number">1</span>,?log?<span?class="hljs-keyword">size</span>=<span?class="hljs-number">2</span>b:???
  • [<span?class="hljs-number">14</span>:<span?class="hljs-number">16</span>:<span?class="hljs-number">07.299</span>]?Apply:?cmd=[INCREMENT_AND_GET]??
  • [<span?class="hljs-number">14</span>:<span?class="hljs-number">16</span>:<span?class="hljs-number">14.304</span>]?Apply:?cmd=[DECREMENT_AND_GET]??
  • roleChanged?<span?class="hljs-keyword">to</span>:?Candidate??
  • roleChanged?<span?class="hljs-keyword">to</span>:?Leader</span></code>??
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    C的控制臺(tái)輸出:

    Prettyprint代碼??
  • <code?class="hljs?sql?has-numbering"><span?class="hljs-comment">-------------------------------------------------------------------</span>??
  • GMS:?address=C,?cluster=ctr-cluster,?physical?address=2001:0:9d38:6abd:cbb:1f78:3f57:50f6:55800??
  • <span?class="hljs-comment">-------------------------------------------------------------------</span>??
  • ??
  • [0]?<span?class="hljs-operator"><span?class="hljs-keyword">Create</span>?[<span?class="hljs-number">1</span>]?Increment?[<span?class="hljs-number">2</span>]?Decrement?[<span?class="hljs-number">3</span>]?Dump?log?[<span?class="hljs-number">4</span>]?Snapshot?[x]?Exit??
  • <span?class="hljs-keyword">first</span>-applied=<span?class="hljs-number">0</span>,?<span?class="hljs-keyword">last</span>-applied=<span?class="hljs-number">0</span>,?<span?class="hljs-keyword">commit</span>-index=<span?class="hljs-number">0</span>,?log?<span?class="hljs-keyword">size</span>=<span?class="hljs-number">0</span>b:???
  • [<span?class="hljs-number">14</span>:<span?class="hljs-number">16</span>:<span?class="hljs-number">01.300</span>]?Apply:?cmd=[<span?class="hljs-keyword">CREATE</span>]??
  • [<span?class="hljs-number">14</span>:<span?class="hljs-number">16</span>:<span?class="hljs-number">07.299</span>]?Apply:?cmd=[INCREMENT_AND_GET]??
  • <span?class="hljs-number">2</span>??
  • counter:?<span?class="hljs-number">3</span>??
  • ??
  • [<span?class="hljs-number">0</span>]?<span?class="hljs-keyword">Create</span>?[<span?class="hljs-number">1</span>]?Increment?[<span?class="hljs-number">2</span>]?Decrement?[<span?class="hljs-number">3</span>]?Dump?log?[<span?class="hljs-number">4</span>]?Snapshot?[x]?Exit??
  • <span?class="hljs-keyword">first</span>-applied=<span?class="hljs-number">0</span>,?<span?class="hljs-keyword">last</span>-applied=<span?class="hljs-number">3</span>,?<span?class="hljs-keyword">commit</span>-index=<span?class="hljs-number">2</span>,?log?<span?class="hljs-keyword">size</span>=<span?class="hljs-number">3</span>b:???
  • [<span?class="hljs-number">14</span>:<span?class="hljs-number">16</span>:<span?class="hljs-number">14.304</span>]?Apply:?cmd=[DECREMENT_AND_GET]</span></code>??
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3.3.2 服務(wù)恢復(fù)

    在只有B和C的集群中,我們執(zhí)行了一次“加一”。當(dāng)我們重新啟動(dòng)A服務(wù)時(shí),它會(huì)自動(dòng)執(zhí)行這條日志,保持與B和C的一致。從日志的index能夠看出,69是一個(gè)Term,也就是A為Leader時(shí)的“任期”,而70也就是B為Leader時(shí)。

    A的控制臺(tái)輸出:

    Prettyprint代碼??
  • <code?class="hljs?asciidoc?has-numbering"><span?class="hljs-code">-------------------------------------------------------------------??
  • GMS:?address=A,?cluster=ctr-cluster,?physical?address=2001:0:9d38:6abd:cbb:1f78:3f57:50f6:53237??
  • -------------------------------------------------------------------</span>??
  • ??
  • [0]?Create?[1]?Increment?[2]?Decrement?[3]?Dump?log?[4]?Snapshot?[x]?Exit??
  • first-applied=0,?last-applied=3,?commit-index=3,?log?size=3b:???
  • <span?class="hljs-attribute">[14:18:45.275]?Apply:?cmd=[INCREMENT_AND_GET]</span>??
  • <span?class="hljs-attribute">[14:18:45.277]?Apply:?cmd=[GET]</span>??
  • 3??
  • ??
  • <span?class="hljs-header">index?(term):?command??
  • ---------------------</span>??
  • 1?(69):?CREATE(counter,?1)??
  • 2?(69):?INCREMENT<span?class="hljs-emphasis">_AND_</span>GET(counter)??
  • 3?(69):?DECREMENT<span?class="hljs-emphasis">_AND_</span>GET(counter)??
  • 4?(70):?INCREMENT<span?class="hljs-emphasis">_AND_</span>GET(counter)??
  • 5?(70):?GET(counter)</code>??
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    http://blog.csdn.net/dc_726/article/details/48832405

    總結(jié)

    以上是生活随笔為你收集整理的分布式一致性协议Raft原理与实例的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。