溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么進(jìn)行PBFT共識(shí)算法分析及Java實(shí)現(xiàn)

發(fā)布時(shí)間:2021-12-18 13:44:26 來源:億速云 閱讀:239 作者:柒染 欄目:互聯(lián)網(wǎng)科技

怎么進(jìn)行PBFT共識(shí)算法分析及Java實(shí)現(xiàn),針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。

PBFT共識(shí)算法詳細(xì)分析及Java實(shí)現(xiàn)

為什么寫這個(gè)

最近研究了區(qū)塊鏈相關(guān)的一些東西,其實(shí)就三大塊:

  1. 分布式存儲(chǔ)(去中心)

  2. 共識(shí)機(jī)制

  3. 安全加密 分布式存儲(chǔ),就是一個(gè)分布式數(shù)據(jù)庫,每個(gè)節(jié)點(diǎn)都保存一份副本。通過非對(duì)稱秘鑰,hash等技術(shù)對(duì)操作數(shù)據(jù)進(jìn)行簽名,驗(yàn)證摘要,可追溯,以鏈?zhǔn)浇Y(jié)構(gòu)存儲(chǔ),互相以hash摘要校驗(yàn)數(shù)據(jù),防篡改。以拜占庭容錯(cuò)共識(shí)算法解決節(jié)點(diǎn)間的通信,達(dá)成一致協(xié)議。

區(qū)塊鏈協(xié)議簡介

分布式共識(shí)算法是分布式系統(tǒng)的核心,常見的有Paxos、pbft、bft、raft、pow等。區(qū)塊鏈中常見的是POW、POS、DPOS、pbft等。 其中:

  • POW、POS、DPOS是開放式的共識(shí)協(xié)議

  • PBFT為半開放式的共識(shí)協(xié)議

  • Paxos、raft等是封閉式共識(shí)協(xié)議

區(qū)別:

  • 開放式,無法確切的知道節(jié)點(diǎn)的多少及連接狀態(tài),每個(gè)節(jié)點(diǎn)都可能是惡意的,但是大多數(shù)是非惡意的

  • 半開放式,可以確定節(jié)點(diǎn)的多少及連接狀態(tài),每個(gè)節(jié)點(diǎn)都可能是惡意的,但是有滿足一定條件的非惡意節(jié)點(diǎn)

  • 封閉式,每個(gè)節(jié)點(diǎn)都是非惡意的,只不過可能斷開連接或crash。

性能: 從上往下越來越高

總結(jié):

  • 私有鏈?zhǔn)欠忾]生態(tài)的存儲(chǔ)系統(tǒng),采用Paxos、raft最佳

  • 聯(lián)盟鏈有半公開半開放特性,因此拜占庭容錯(cuò)的PBFT算法比較合適

  • 公有鏈來說,POW、POS、DPOS是比較適合的高安全性的協(xié)議

那么,下面我們要說的就是聯(lián)盟鏈性質(zhì)的共識(shí)協(xié)議:PBFT算法協(xié)議。 協(xié)議誕生已經(jīng)很久了,網(wǎng)上的文章也不少,然而基本都是翻譯原論文,稍加一些個(gè)人的閱讀心得,細(xì)致的分析還是比較少,一些關(guān)鍵的銜接點(diǎn)沒有說清楚,粗看好像都懂,但是真正要實(shí)現(xiàn)起來,還是有比較多坑。于是本人采用demo的方式,以多線程模擬多節(jié)點(diǎn),實(shí)現(xiàn)完整的PBFT算法,其中有一些問題,記錄下來,供各位參考,討論。

PBFT算法簡介


PBFT協(xié)議簡單步驟:

主要有三個(gè)階段:預(yù)準(zhǔn)備(pre-prepare)、準(zhǔn)備(prepare)、和確認(rèn)(commit)

  1. 從全網(wǎng)節(jié)點(diǎn)選舉出一個(gè)主節(jié)點(diǎn)(Leader),新區(qū)塊由主節(jié)點(diǎn)負(fù)責(zé)生成。

  2. 其中一個(gè)節(jié)點(diǎn)的客戶端向主節(jié)點(diǎn)發(fā)起請(qǐng)求。

  3. Pre-Prepare:主節(jié)點(diǎn)分配一個(gè)序列號(hào)n給收到的請(qǐng)求(順序的保證?。?,并向全網(wǎng)廣播<<PRE-PREPARE,v,n,d>,m>

  4. Prepare:每個(gè)節(jié)點(diǎn)接收到交易請(qǐng)求后,模擬執(zhí)行這些交易,驗(yàn)證交易報(bào)文的正確性。驗(yàn)證通過后,存入預(yù)備列表,并向全網(wǎng)廣播<PREPARE,v,n,d,i>

  5. Commit:如果一個(gè)節(jié)點(diǎn)收到的2f(f為可容忍的拜占庭節(jié)點(diǎn)數(shù))個(gè)其它節(jié)點(diǎn)發(fā)來的PREPARE消息摘要都和自己相等,就向全網(wǎng)廣播一條commit消息<COMMIT,v,n,D(m),i>

  6. Reply:如果一個(gè)節(jié)點(diǎn)收到2f+1條commit消息,即可提交新區(qū)塊及其交易到本地的區(qū)塊鏈和狀態(tài)數(shù)據(jù)庫(操作確認(rèn)完成)。

問題分析


整個(gè)協(xié)議理解起來還算比較簡單,但是這里面有好些問題,需要一一的剖析。

  1. 主節(jié)點(diǎn)怎么產(chǎn)生?

  2. 主節(jié)點(diǎn)失效了怎么辦?

  3. 主節(jié)點(diǎn)造假怎么辦?

  4. 數(shù)據(jù)怎么重傳?

主節(jié)點(diǎn)的產(chǎn)生

因?yàn)楣?jié)點(diǎn)的操作都需要通過主節(jié)點(diǎn),所以每個(gè)節(jié)點(diǎn)啟動(dòng)后的第一件事,找主節(jié)點(diǎn)。 主節(jié)點(diǎn)由公式p = v mod |R|計(jì)算得到,這里v是視圖編號(hào),p是副本編號(hào),|R|是副本集合的個(gè)數(shù)。 所以其實(shí)找主節(jié)點(diǎn)就是初始化視圖view。

  1. 全網(wǎng)廣播獲取視圖協(xié)議:

public static final int VIEW = -1;
  1. 超過2f+1的節(jié)點(diǎn)回復(fù)的view作為初始化的view(q1:如果無法滿足怎么辦?)

if(this.viewOk)return;
long count = vnumAggreCount.incrementAndGet(msg.getVnum());
if(count >= 2*maxf+1){
	vnumAggreCount.clear();
	this.view = msg.getVnum();
	viewOk = true;
	System.out.println("視圖初始化完成["+index+"]:"+ view);
}
主節(jié)點(diǎn)失效了(這里失效指應(yīng)用掛掉、或被他人控制作惡)

誰先發(fā)現(xiàn)主節(jié)點(diǎn)失效了,當(dāng)然,這里是不能通過連接斷開來看,因?yàn)榧词箃cp連接正常,也不一定業(yè)務(wù)處理正常。答案是,超時(shí)控制。 當(dāng)發(fā)起請(qǐng)求的節(jié)點(diǎn)在超時(shí)時(shí)間內(nèi)沒有完成操作確認(rèn),則可以懷疑主節(jié)點(diǎn)失效,于是:

  1. 客戶端全網(wǎng)廣播超時(shí)的請(qǐng)求報(bào)文,為什么不用一個(gè)專門的包來發(fā)起失效提議?主要是防止發(fā)起請(qǐng)求的節(jié)點(diǎn)作惡,比如循環(huán)發(fā)起提議。導(dǎo)致不斷產(chǎn)生提議檢驗(yàn),導(dǎo)致網(wǎng)絡(luò)擁堵

  2. 副本節(jié)點(diǎn)檢查,如果處理過(說明可能是網(wǎng)絡(luò)問題),重新將處理結(jié)果返回即可,如果未處理,則可能主節(jié)點(diǎn)宕機(jī),將請(qǐng)求重新轉(zhuǎn)發(fā)給主節(jié)點(diǎn),且增加超時(shí)校驗(yàn)。這時(shí),如果主節(jié)點(diǎn)是正常的,那么就會(huì)走正常流程,最終會(huì)確認(rèn)操作請(qǐng)求。如果主節(jié)點(diǎn)真的有問題,則設(shè)置的超時(shí)將觸發(fā)

  3. 超時(shí)后全網(wǎng)廣播主節(jié)點(diǎn)切換提議

if(!this.viewOk) return; // 已經(jīng)開始選舉視圖,不用重復(fù)發(fā)起
this.viewOk = false;
// 作為副本節(jié)點(diǎn),廣播視圖變更投票
PbftMsg cv = new PbftMsg(CV, this.index);
cv.setVnum(this.view+1);
PbftMain.publish(cv);

當(dāng)每個(gè)節(jié)點(diǎn)都收到2f+1個(gè)對(duì)同一個(gè)view的提議后,則切換成新的view。且檢查是否有請(qǐng)求待發(fā)送,一切恢復(fù)正常邏輯:

long count = vnumAggreCount.incrementAndGet(msg.getVnum());
if(count >= 2*maxf+1){
	vnumAggreCount.clear();
	this.view = msg.getVnum();
	viewOk = true;
	System.out.println("視圖變更完成["+index+"]:"+ view);
	// 可以繼續(xù)發(fā)請(qǐng)求
	if(curMsg != null){
		curMsg.setVnum(this.view);
		System.out.println("請(qǐng)求重傳["+index+"]:"+ curMsg);
		doSendCurMsg();
	}
}

提議時(shí),如果有惡意節(jié)點(diǎn)重復(fù)多次發(fā)起,需要檢測每個(gè)節(jié)點(diǎn)只能投票一次。

String vkey = msg.getNode()+"@"+msg.getVnum();
if(votes_vnum.contains(vkey)){
	return;
}
votes_vnum.add(vkey);
清理狀態(tài)

當(dāng)commit通過后,即確認(rèn)了操作,則可以對(duì)該消息相關(guān)的狀態(tài)進(jìn)行清理:

// 清理請(qǐng)求相關(guān)狀態(tài)
	private void remove(String it) {
		votes_pre.remove(it);
		votes_pare.removeIf((vp)->{
			return StringUtils.startsWith(vp, it);
		});
		votes_comm.removeIf((vp)->{
			return StringUtils.startsWith(vp, it);
		});
		aggre_pare.remove(it);
		aggre_comm.remove(it);
		timeOuts.remove(it);
	}
其他關(guān)鍵點(diǎn)

PbftMsg消息的DataKey必須是唯一的,可以通過uuid或者其他方式定義

private int type; // 消息類型
	private int node; // 節(jié)點(diǎn)
	private int onode; // 發(fā)起請(qǐng)求的節(jié)點(diǎn)
	private int vnum; // 視圖編號(hào)
	private int no; // 序列號(hào)
	private long time; // 時(shí)間戳
	private String data; // 數(shù)據(jù),表示數(shù)據(jù)的hash,必須唯一

關(guān)于怎么進(jìn)行PBFT共識(shí)算法分析及Java實(shí)現(xiàn)問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI