网络知识 娱乐 拜占庭简单实现

拜占庭简单实现

PBFT(拜占庭容错)

基于拜占庭将军问题,一致性的确保主要分为这三个阶段:预准备(pre-prepare)、准备(prepare)和确认(commit)。

其中C为发送请求端,0123为服务端,3为宕机的服务端,具体步骤如下:

  1. Request:请求端C发送请求到任意一节点,这里是0
  2. Pre-Prepare:服务端0收到C的请求后进行广播,扩散至123
  3. Prepare:123,收到后记录并再次广播,1->023,2->013,3因为宕机无法广播
  4. Commit:0123节点在Prepare阶段,若收到超过一定数量的相同请求,则进入Commit阶段,广播Commit请求 5.Reply:0123节点在Commit阶段,若收到超过一定数量的相同请求,则对C进行反馈

代码实现

package mainnnimport (nt"os"nt"fmt"nt"net/http"nt"io"n)nn//声明节点信息,代表各个小国家ntype nodeInfo struct {nt//标示ntid stringnt//准备访问的方法ntpath stringnt//服务器做出的相应ntwriter http.ResponseWriternn}nn/存放四个国家的地址nvar nodeTable = make(map[string]string)nn//拜占庭在Fabric中的使用nfunc main() {nnt//获取执行的参数ntuserId :=os.Args[1]//获取执行的第一个参数ntfmt.Println(userId)nnt//./main Applennt//创建四个国家的地址ntnodeTable = map[string]string {ntt"Apple":"localhost:1111",ntt"MS":"localhost:1112",ntt"Google":"localhost:1113",ntt"IBM":"localhost:1114",nt}nntnode:=nodeInfo{userId,nodeTable[userId],nil}ntfmt.Println(node)nn//http协议的回调函数nt//http://localhost:1111/req?warTime=8888nthttp.HandleFunc("/req",node.request)nthttp.HandleFunc("/prePrepare",node.prePrepare)nthttp.HandleFunc("/prepare",node.prepare)nthttp.HandleFunc("/commit",node.commit)nnt//启动服务器ntif err:=http.ListenAndServe(node.path,nil);err!=nil {nttfmt.Print(err)nt}nnnn}nn//此函数是http访问时候req命令的请求回调函数nfunc (node *nodeInfo)request(writer http.ResponseWriter,request *http.Request){nt//设置允许解析参数ntrequest.ParseForm()nt//如果有参数值,则继续处理ntif (len(request.Form["warTime"])>0){nttnode.writer = writerntt//激活主节点后,广播给其他节点,通过Apple向其他节点做广播nttnode.broadcast(request.Form["warTime"][0],"/prePrepare")nnt}nnn}nn//由主节点向其他节点做广播nfunc (node *nodeInfo)broadcast(msg string ,path string ){nt//遍历所有的国家ntfor nodeId,url:=range nodeTable {nnttif nodeId == node.id {ntttcontinuentt}ntt//调用Get请求ntt//http.Get("http://localhost:1112/prePrepare?warTime=8888&nodeId=Apple")ntthttp.Get("http://"+url+path+"?warTime="+msg+"&nodeId="+node.id)nt}nn}nnfunc (node *nodeInfo)prePrepare(writer http.ResponseWriter,request *http.Request) {ntrequest.ParseForm()nt//fmt.Println("hello world")nt//在做分发ntif(len(request.Form["warTime"])>0){ntt//分发给其他三个人nttnode.broadcast(request.Form["warTime"][0],"/prepare")nt}nn}nnfunc (node *nodeInfo)prepare(writer http.ResponseWriter,request *http.Request){nntrequest.ParseForm()nt//调用验证ntif len(request.Form["warTime"])>0{nttfmt.Println(request.Form["warTime"][0])nt}ntif len(request.Form["nodeId"])>0 {nttfmt.Println(request.Form["nodeId"][0])nt}nntnode.authentication(request)n}nnvar authenticationsuccess = truenvar authenticationMap = make(map[string]string)n//获得除了本节点外的其他节点数据nfunc (node *nodeInfo)authentication(request *http.Request) {nnt//接收参数ntrequest.ParseForm()nntif authenticationsuccess!=false {nttif len(request.Form["nodeId"])>0 {ntttauthenticationMap[request.Form["nodeId"][0]]="ok"ntt}nt}nntif len(authenticationMap)>len(nodeTable)/3 {ntt//则拜占庭原理实现,通过commit反馈给浏览器nttnode.broadcast(request.Form["warTime"][0],"/commit")nnt}n}nnfunc (node *nodeInfo)commit(writer http.ResponseWriter,request *http.Request){nnt//给浏览器反馈相应ntio.WriteString(node.writer,"ok")nn}n拜占庭简单实现