代碼中先構(gòu)造出一個(gè)transport實(shí)例,然后將集群中其余節(jié)點(diǎn)的訪問地址添加到transport中,需通過地址來進(jìn)行節(jié)點(diǎn)之間的互相通信,最后啟動(dòng)一個(gè)TCPListener來接收和處理消息。
至此,一個(gè)簡單的RaftNode就算啟動(dòng)起來了,依據(jù)同樣的方式再啟動(dòng)其他兩個(gè)節(jié)點(diǎn),3節(jié)點(diǎn)的RaftCluster也運(yùn)行起來了,不過,只是服務(wù)啟動(dòng)成功還遠(yuǎn)遠(yuǎn)不夠。
數(shù)據(jù)提交及事件處理
1、 將數(shù)據(jù)提交到RaftNode,使用Propose方法將數(shù)據(jù)提交到leader節(jié)點(diǎn)
注:只能講數(shù)據(jù)Propose到leader節(jié)點(diǎn), 因?yàn)橹挥衛(wèi)eader才有能力讓follower復(fù)制自己的操作。
2、leader節(jié)點(diǎn)接收到數(shù)據(jù)會(huì)根據(jù)集群的狀態(tài)判斷是否已經(jīng)能接受數(shù)據(jù)的提交,leader確定能接收數(shù)據(jù)后會(huì)負(fù)責(zé)將數(shù)據(jù)發(fā)送到follower。
注:如果是集群節(jié)點(diǎn)的改動(dòng)需要調(diào)用ProposeConfChange方法。
3、RaftNode節(jié)點(diǎn)數(shù)據(jù)提交是一個(gè)異步的過程,通過Propose方法往RaftNode中提交數(shù)據(jù),而RaftNode則在經(jīng)過一系列的狀態(tài)判斷從另一個(gè)線程中通過 Ready()方法通知,此外,集群狀態(tài)的變化也會(huì)通過這個(gè)channel來通知,所以當(dāng)Propose數(shù)據(jù)之后不知道數(shù)據(jù)是否提交成功,如果服務(wù)的數(shù)據(jù)有高可用性的要求,這里可能需要進(jìn)行額外的處理,將異步的提交變成同步的(可以參考swarmkit ProposeValue)。
注:由于數(shù)據(jù)提交只有一個(gè)Propose接口,所以需要對(duì)不同的數(shù)據(jù)進(jìn)行不同的操作,提前定義好對(duì)哪些數(shù)據(jù)(比如app, cluster)進(jìn)行什么樣的操作(比如Add, Update, Delete),這種情況下就要先在Propose的對(duì)象里加上數(shù)據(jù)和操作之后再進(jìn)行序列化。
著重注意從 Ready()中收到數(shù)據(jù)之后的處理,先看代碼:
以上代碼可以看到最主要的三個(gè)處理:
檢查RaftCluster的狀態(tài)是否已經(jīng)改變,如果該節(jié)點(diǎn)已經(jīng)從follower升級(jí)成為leader,需要通知外部的服務(wù)這個(gè)變化,以便外部服務(wù)做出相應(yīng)的調(diào)整
publishEntries,其實(shí)就是講rd。CommittedEntries持久化或者存到相應(yīng)的地方,可以認(rèn)為這些CommittedEntries就是已經(jīng)被RaftCluster接收了的可靠消息。
關(guān)于節(jié)點(diǎn)狀態(tài)的變化,需要在外部服務(wù)中監(jiān)聽RaftNode的leadershipChange event,由于RaftNode只有在leader上才能Propose數(shù)據(jù)(相當(dāng)于寫操作),所以cluster中的所有節(jié)點(diǎn)地位并不是對(duì)等的,比如有的提交數(shù)據(jù)的功能可能需要等RaftCluster leader election完成后再leader上啟動(dòng);至于其他的follower節(jié)點(diǎn)如果對(duì)外想提供和leader一樣的服務(wù),則需要自己實(shí)現(xiàn)一個(gè)proxy,將請(qǐng)求proxy到leader節(jié)點(diǎn), 或者通過grpc來遠(yuǎn)程調(diào)用leader上相應(yīng)的接口,相關(guān)的代碼如下所示: