婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > 使用GO實現Paxos共識算法的方法

使用GO實現Paxos共識算法的方法

熱門標簽:地圖標注測試 福州鐵通自動外呼系統 烏魯木齊人工電銷機器人系統 濮陽自動外呼系統代理 賺地圖標注的錢犯法嗎 智能電銷機器人營銷 澳門防封電銷卡 長沙ai機器人電銷 廣東語音外呼系統供應商

什么是Paxos共識算法

最初的服務往往都是通過單體架構對外提供的,即單Server-單Database模式。隨著業務的不斷擴展,用戶和請求數都在不斷上升,如何應對大量的請求就成了每個服務都需要解決的問題,這也就是我們常說的高并發。為了解決單臺服務器面對高并發的蒼白無力,可以通過增加服務器數量來解決,即多Server-單Database(Master-Slave)模式,此時的壓力就來到了數據庫一方,數據庫的IO效率決定了整個服務的效率,繼續增加Server數量將無法提升服務性能。這就衍生出了當前火熱的微服務架構。當用戶請求經由負載均衡分配到某一服務實例上后,如何保證該服務的其他實例最終能夠得到相同的數據變化呢?這就要用到Paxos分布式共識協議,Paxos解決的就是共識問題,也就是一段時間后,無論get哪一個服務實例,都能獲取到相同的數據。目前國內外的分布式產品很多都使用了Paxos協議,可以說Paxos幾乎就是共識協議的標準和代名詞。

Paxos有兩種協議,我們常常提到的其實是Basic Paxos,另一種叫Multi Paxos,如無特殊說明,本文中提到的Paxos協議均為Basic Paxos。

Paxos協議是由圖靈獎獲得者Leslie Lamport于1998年在其論文《The Part-Time Parliament》中首次提出的,講述了一個希臘小島Paxos是如何通過決議的。但由于該論文晦澀艱深,當時的計算機界大牛們也沒幾個人能理解。于是Lamport2001年再次發表了《Paxos Made Simple》,摘要部分是這么寫的:

The Paxos algorithm, when presented in plain English, is very simple.

翻譯過來就是:不會吧,不會吧,這么簡單的Paxos算法不會真的有人弄不懂吧?然而事實卻是很多人對Paxos都望而卻步,理解Paxos其實并不難,但是Paxos的難點在于工程化,如何利用Paxos協議寫出一個能過夠真正在生產環境中跑起來的服務才是Paxos最難的地方,關于Paxos的工程化可以參考微信后臺團隊撰寫的《微信自研生產級paxos類庫PhxPaxos實現原理介紹》

Paxos如何保證一致性的

Paxos協議一共有兩個階段:Prepare和Propose,兩種角色:Proposer和Acceptor,每一個服務實例既是Proposer,同時也是Acceptor,Proposer負責提議,Acceptor決定是否接收來自Proposer的提議,一旦提議被多數接受,那么我們就可以宣稱對該提議包含的值達成了一致,而且不會再改變。

階段一:Prepare 準備

  • Proposer生成全局唯一ProposalID(時間戳+ServerID)
  • Proposer向所有Acceptor(包括Proposer自己)發送Prepare(n = ProposalID)請求
  • Acceptor比較n和minProposal, if n > minProposal, minProposal = n,Acceptor返回已接受的提議(acceptedProposal, acceptedValue)
  • 承諾1:不再接受n = minProposal的Prepare請求
  • 承諾2:不再接受n minProposal的Propose請求
  • 應答1:返回此前已接受的提議
  • 當Proposer收到大于半數的返回后
  • Prepare請求被拒絕,重新生成ProposalID并發送Prepare請求
  • Prepare請求被接受且有已接受的提議,選擇最大的ProposalID對應的值作為提議的值
  • Prepare請求被接受且沒有已接受的提議,可選擇任意提議值

    階段二:Propose 提議

  • Proposer向所有Acceptor(包括Proposer自己)發送Accept(n=ProposalID,value=ProposalValue)請求
  • Acceptor比較n和minProposal, if n >= minProposal, minProposal = n, acceptedValue = value,返回已接受的提議(minProposal,acceptedValue)
  • 當Proposer收到大于半數的返回后
  • Propose請求被拒絕,重新生成ProposalID并發送Prepare請求
  • Propose請求被接受,則數據達成一致性

一旦提議被半數以上的服務接受,那么我們就可以宣稱整個服務集群在這一提議上達成了一致。

需要注意的是,在一個服務集群中以上兩個階段是很有可能同時發生的。 例如:實例A已完成Prepare階段,并發送了Propose請求。同時實例B開始了Prepare階段,并生成了更大的ProposalID發送Prepare請求,可能導致實例A的Propose請求被拒絕。 每個服務實例也是同時在扮演Proposer和Acceptor角色,向其他服務發送請求的同時,可能也在處理別的服務發來的請求。

使用GO語言實現Paxos協議

服務注冊與發現

由于每個服務實例都是在執行相同的代碼,那我們要如何知曉其他服務實例的入口呢(IP和端口號)?方法之一就是寫死在代碼中,或者提供一份配置文件。服務啟動后可以讀取該配置文件。但是這種方法不利于維護,一旦我們需要移除或添加服務則需要在每個機器上重新休息配置文件。

除此之外,我們可以通過一個第三方服務:服務的注冊與發現來注冊并獲知當前集群的總服務實例數,即將本地的配置文件改為線上的配置服務。

服務注冊:Register函數,服務實例啟動后通過調用這個RPC方法將自己注冊在服務管理中

func (s *Service) Register(args *RegisterArgs, reply *RegisterReply) error {
 s.mu.Lock()
 defer s.mu.Unlock()
 
 server := args.ServerInfo
 for _, server := range s.Servers {
  if server.IPAddress == args.ServerInfo.IPAddress  server.Port == args.ServerInfo.Port {
   reply.Succeed = false
   return nil
  }
 }
 reply.ServerID = len(s.Servers)
 reply.Succeed = true
 s.Servers = append(s.Servers, server)
 
 fmt.Printf("Current registerd servers:\n%v\n", s.Servers)
 
 return nil
}

服務發現:GetServers函數,服務通過調用該RPC方法獲取所有服務實例的信息(IP和端口號)

func (s *Service) GetServers(args *GetServersArgs, reply *GetServersReply) error {
 // return all servers
 reply.ServerInfos = s.Servers
 
 return nil
}

Prepare階段

Proposer,向所有的服務發送Prepare請求,并等待直到半數以上的服務返回結果,這里也可以等待所有服務返回后再處理,但是Paxos協議可以容忍小于半數的服務宕機,因此我們只等待大于N/2個返回即可。當返回的結果有任何一個請求被拒絕,那Proposer即認為這次的請求被拒絕,返回重新生成ProposalID并發送新一輪的Prepare請求。

func (s *Server) CallPrepare(allServers []ServerInfo, proposal Proposal) PrepareReply {
 returnedReplies := make([]PrepareReply, 0)
 for _, otherS := range allServers {
  // use a go routine to call every server
  go func(otherS ServerInfo) {
   delay := rand.Intn(10)
   time.Sleep(time.Second * time.Duration(delay))
   args := PrepareArgs{s.Info, proposal.ID}
   reply := PrepareReply{}
   fmt.Printf("【Prepare】Call Prepare on %v:%v with proposal id %v\n", otherS.IPAddress, otherS.Port, args.ProposalID)
   if Call(otherS, "Server.Prepare", args, reply) {
    if reply.HasAcceptedProposal {
     fmt.Printf("【Prepare】%v:%v returns accepted proposal: %v\n", otherS.IPAddress, otherS.Port, reply.AcceptedProposal)
    } else {
     fmt.Printf("【Prepare】%v:%v returns empty proposal\n", otherS.IPAddress, otherS.Port)
    }
    s.mu.Lock()
    returnedReplies = append(returnedReplies, reply)
    s.mu.Unlock()
   }
  }(otherS)
 }
 for {
  // wait for responses from majority
  if len(returnedReplies) > (len(allServers))/2.0 {
   checkReplies := returnedReplies
   // three possible response
   // 1. deny the prepare, and return an empty/accepted proposal
   // as the proposal id is not higher than minProposalID on server (proposal id = server.minProposalID)
   // 2. accept the prepare, and return an empty proposal as the server has not accept any proposal yet
   // 3. accept the prepare, and return an accepted proposal
   // check responses from majority
   // find the response with max proposal id
   acceptedProposal := NewProposal()
   for _, r := range checkReplies {
    // if any response refused the prepare, this server should resend prepare
    if !r.PrepareAccepted {
     return r
    }
    if r.HasAcceptedProposal  r.AcceptedProposal.ID > acceptedProposal.ID {
     acceptedProposal = r.AcceptedProposal
    }
   }
   // if some other server has accepted proposal, return that proposal with max proposal id
   // if no other server has accepted proposal, return an empty proposal
   return PrepareReply{HasAcceptedProposal: !acceptedProposal.IsEmpty(), AcceptedProposal: acceptedProposal, PrepareAccepted: true}
  }
  //fmt.Printf("Waiting for response from majority...\n")
  time.Sleep(time.Second * 1)
 }
}

Acceptor,通過比較ProposalID和minProposal,如果ProposalID小于等于minProposal,則拒絕該Prepare請求,否則更新minProposal為ProposalID。最后返回已接受的提議

func (s *Server) Prepare(args *PrepareArgs, reply *PrepareReply) error {
 s.mu.Lock()
 defer s.mu.Unlock()
 // 2 promises and 1 response
 // Promise 1
 // do not accept prepare request which ProposalID = minProposalID
 // Promise 2
 // do not accept propose request which ProposalID  minProposalID
 // Response 1
 // respond with accepted proposal if any
 if reply.PrepareAccepted = args.ProposalID > s.minProposalID; reply.PrepareAccepted {
  // ready to accept the proposal with Id s.minProposalID
  s.minProposalID = args.ProposalID
 }
 reply.HasAcceptedProposal = s.readAcceptedProposal()
 reply.AcceptedProposal = s.Proposal
 return nil
}

Propose階段

Proposer,同樣首先向所有的服務發送Propose請求,并等待知道半數以上的服務返回結果。如果返回的結果有任何一個請求被拒絕,則Proposer認為這次的請求被拒絕,返回重新生成ProposalID并發送新一輪的Prepare請求

func (s *Server) CallPropose(allServers []ServerInfo, proposal Proposal) ProposeReply {
 returnedReplies := make([]ProposeReply, 0)
 for _, otherS := range allServers {
  go func(otherS ServerInfo) {
   delay := rand.Intn(5000)
   time.Sleep(time.Millisecond * time.Duration(delay))
   args := ProposeArgs{otherS, proposal}
   reply := ProposeReply{}
   fmt.Printf("【Propose】Call Propose on %v:%v with proposal: %v\n", otherS.IPAddress, otherS.Port, args.Proposal)
   if Call(otherS, "Server.Propose", args, reply) {
    fmt.Printf("【Propose】%v:%v returns: %v\n", otherS.IPAddress, otherS.Port, reply)
    s.mu.Lock()
    returnedReplies = append(returnedReplies, reply)
    s.mu.Unlock()
   }
  }(otherS)
 }
 for {
  // wait for responses from majority
  if len(returnedReplies) > (len(allServers))/2.0 {
   checkReplies := returnedReplies
   for _, r := range checkReplies {
    if !r.ProposeAccepted {
     return r
    }
   }
   return checkReplies[0]
  }
  time.Sleep(time.Second * 1)
 }
}

Acceptor,通過比較ProposalID和minProposal,如果ProposalID小于minProposal,則拒絕該Propose請求,否則更新minProposal為ProposalID,并將提議持久化到本地磁盤中。

func (s *Server) Propose(args *ProposeArgs, reply *ProposeReply) error {
 if s.minProposalID = args.Proposal.ID {
  s.mu.Lock()
  s.minProposalID = args.Proposal.ID
  s.Proposal = args.Proposal
  s.SaveAcceptedProposal()
  s.mu.Unlock()
 
  reply.ProposeAccepted = true
 }
 
 reply.ProposalID = s.minProposalID
 
 return nil
}

運行

運行結果:

這里我一共開啟了3個服務實例,并在每次請求之前加入了隨機的延遲,模擬網絡通信中的延遲,因此每個服務的每個請求并不是同時發出的

動圖一張:

靜態結果一張:

可以看到3個服務盡管一開始會嘗試以他們自己的端口號(5001,5002,5003)作為提議值,在Prepare/Propose失敗后,都會重新生成更大的ProposalID并開啟新一輪的提議過程(Prepare,Propose),且最后都以5003達成一致。

小結

至此,我們就用GO實現了Paxos協議的核心邏輯。但顯而易見的是,這段代碼仍然存在很多問題,完全無法滿足生產環境的需求

  • 通過channel而不是mutex鎖來共享數據
  • 如何處理服務實例的移除和增加
  • 如何避免陷入活鎖

到此這篇關于使用GO實現Paxos共識算法的文章就介紹到這了,更多相關GO實現Paxos共識算法內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • Golang實現拓撲排序(DFS算法版)
  • 圖解Golang的GC垃圾回收算法
  • golang實現分頁算法實例代碼
  • C++實現分水嶺算法(Watershed Algorithm)

標簽:貴陽 德州 廣西 太原 慶陽 調研邀請 西雙版納 阿克蘇

巨人網絡通訊聲明:本文標題《使用GO實現Paxos共識算法的方法》,本文關鍵詞  使用,實現,Paxos,共識,算法,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《使用GO實現Paxos共識算法的方法》相關的同類信息!
  • 本頁收集關于使用GO實現Paxos共識算法的方法的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    国产欧美日韩激情| 亚洲人精品午夜| 精品亚洲国内自在自线福利| 欧美在线不卡一区| 99国产精品久久久久久久久久 | 亚洲综合免费观看高清完整版| 精品福利一二区| 日本精品视频一区二区| 国产精品亚洲а∨天堂免在线| 国产盗摄精品一区二区三区在线| 亚洲精品自拍动漫在线| 久久女同性恋中文字幕| 亚洲一区二区三区在线| 日韩美女视频19| 久久毛片高清国产| 国产精品国产自产拍高清av| 久久久久一区二区三区四区| 久久综合999| 欧美va亚洲va在线观看蝴蝶网| 欧美老年两性高潮| 日韩欧美成人一区| 亚洲一区二区三区在线| 免费视频一区二区| 免费欧美高清视频| 国产精品一二三区| 97久久精品人人做人人爽| 色国产精品一区在线观看| 日韩av一二三| av影院午夜一区| 欧美一区二区免费观在线| 国产精品伊人色| 欧美综合欧美视频| 精品国产91乱码一区二区三区 | 亚洲伦理在线免费看| 亚洲人成网站色在线观看| 亚洲乱码中文字幕综合| 欧美一区二区成人| 成人免费视频一区二区| 欧美高清在线视频| 国内精品免费**视频| 懂色av一区二区三区免费看| 老司机精品视频导航| 在线观看成人免费视频| 久久久噜噜噜久久人人看| 久久久久高清精品| 日本韩国欧美三级| 国产成人精品亚洲午夜麻豆| 亚洲成人av一区二区三区| 91视频观看视频| 777精品伊人久久久久大香线蕉| 91精品国产麻豆国产自产在线| 亚欧色一区w666天堂| 91看片淫黄大片一级在线观看| 国产精品情趣视频| 日本高清免费不卡视频| 日韩高清一区二区| 97久久精品人人爽人人爽蜜臀| 麻豆精品一区二区av白丝在线| 欧美精品粉嫩高潮一区二区| 一本大道av伊人久久综合| 午夜精品免费在线观看| 一区二区高清在线| 99精品视频在线免费观看| 国产农村妇女精品| aaa欧美色吧激情视频| 国产精品卡一卡二| 欧美性色综合网| 蜜桃久久精品一区二区| 国产日产亚洲精品系列| caoporn国产精品| 欧美精品成人一区二区三区四区| 美女视频免费一区| 国产一区二区伦理片| 日韩欧美激情一区| 欧美aaaaaa午夜精品| 久久亚洲精华国产精华液 | 亚洲动漫第一页| 亚洲欧洲99久久| a美女胸又www黄视频久久| 国产精品女人毛片| 一本到一区二区三区| 亚洲与欧洲av电影| 69av一区二区三区| 日韩成人免费电影| 日韩avvvv在线播放| 欧美一区二区三区免费在线看 | 国产在线精品免费av| 成人黄色在线看| **欧美大码日韩| 国产乱人伦偷精品视频不卡 | 亚洲天堂网中文字| 99视频有精品| 蜜桃一区二区三区四区| 国产欧美日韩综合| 亚洲高清不卡在线观看| 中文文精品字幕一区二区| 国产精品国产精品国产专区不片| 精品国产91乱码一区二区三区| 91麻豆精东视频| 在线视频一区二区三| 成人av网在线| 色欲综合视频天天天| va亚洲va日韩不卡在线观看| 成人短视频下载| 91福利视频在线| 亚洲第一狼人社区| 成人视屏免费看| 福利一区在线观看| www.欧美亚洲| av电影在线观看不卡| 亚洲欧美自拍偷拍色图| 欧美成人免费网站| 欧洲精品在线观看| 国产电影一区在线| 美女在线视频一区| 中文字幕一区二区三区四区| 精品国产乱码久久久久久图片 | 在线观看一区二区视频| 午夜久久久久久久久久一区二区| 日韩欧美在线网站| 欧美三级在线看| 成人黄色777网| 99久久精品费精品国产一区二区| 欧美性做爰猛烈叫床潮| 91精品欧美一区二区三区综合在| 欧美在线观看视频一区二区| 中文字幕视频一区| 欧洲一区在线观看| 91视视频在线观看入口直接观看www| 国产精品538一区二区在线| 免费成人在线观看| 2024国产精品视频| 91麻豆精品国产| 99国产精品久久久久久久久久久| 另类小说一区二区三区| 蜜桃久久久久久| 在线免费视频一区二区| 国产在线精品一区二区不卡了| 日韩欧美一二三| 黑人巨大精品欧美一区| 精品国产髙清在线看国产毛片| 亚洲精品一二三四区| 裸体一区二区三区| 国产精品一区二区男女羞羞无遮挡| 日韩高清电影一区| 在线观看亚洲成人| 欧美精品一区二区三区在线播放| 91麻豆精品国产自产在线观看一区| 国产精品电影一区二区| 亚洲视频小说图片| 亚洲五码中文字幕| 中文字幕制服丝袜成人av| 久久国产精品99久久久久久老狼 | 99精品在线观看视频| 99国产一区二区三精品乱码| 日韩欧美国产小视频| 中文字幕欧美三区| 国产精品无遮挡| 色悠悠亚洲一区二区| 亚洲日本va午夜在线影院| 国产精品高清亚洲| 日本一区二区成人| 免费人成精品欧美精品| 偷拍亚洲欧洲综合| 国产99久久久久| 欧美激情一区在线| 国产精品日产欧美久久久久| 精品精品欲导航| av不卡在线观看| 国产欧美日韩视频一区二区| 天天av天天翘天天综合网| 欧美高清视频不卡网| 国产精品一区免费视频| 亚洲欧美日韩在线| 欧美r级电影在线观看| www.亚洲免费av| 久久av老司机精品网站导航| 日韩精品一区二区三区蜜臀| 91视频在线观看| 国产成人丝袜美腿| 麻豆精品视频在线观看免费| 国产一区二区三区免费| 麻豆成人免费电影| 久久精品国产久精国产爱| 成人午夜视频免费看| 成人h动漫精品一区二区| 成人av网在线| 欧美日韩午夜在线视频| 在线播放国产精品二区一二区四区| 欧美日韩卡一卡二| 91超碰这里只有精品国产| 51精品秘密在线观看| 日韩欧美成人激情| 精品第一国产综合精品aⅴ| 一区二区三区在线看| 极品少妇xxxx偷拍精品少妇| 福利一区福利二区| 欧美日韩一区二区三区四区 | 亚洲精品免费在线播放| 亚洲国产色一区|