區塊鏈 和 一致性哈希的結合

怎么結合呢?

我們先來回顧一下一致性哈希代碼實現里面的結構

// Consistent holds the information about the members of the consistent hash circle.
type Consistent struct {mu sync.RWMutex // 讀寫鎖,用于保護并發訪問共享數據config         Config         // 存儲配置信息hasher         Hasher         // 存儲哈希器實例,直接從 config 復制過來sortedSet      []uint64       // 存儲所有虛擬節點(通過成員名稱+副本索引哈希得到)的哈希值,并保持升序排列。這是哈希環的骨架。partitionCount uint64         // 邏輯分區的總數,從 config.PartitionCount 轉換而來loads          map[string]float64 // 存儲每個真實成員當前的負載(即它擁有的邏輯分區數量)members        map[string]*Member // 存儲所有真實成員的映射,鍵是成員的 String() 返回值,值是指向 Member 接口的指針partitions     map[int]*Member    // 核心映射:存儲每個邏輯分區ID(0到PartitionCount-1)對應的真實成員(指向 Member 接口的指針)ring           map[uint64]*Member // 存儲虛擬節點哈希值到真實成員的映射。它是 sortedSet 的補充,sortedSet 提供有序列表,ring 提供哈希值到成員的查找。
}

現在就是加入一個新的服務器后,會修改什么內容

func (c *Consistent) add(member Member) {for i := 0; i < c.config.ReplicationFactor; i++ {key := []byte(fmt.Sprintf("%s%d", member.String(), i))h := c.hasher.Sum64(key)c.ring[h] = &memberc.sortedSet = append(c.sortedSet, h)}// sort hashes ascendinglysort.Slice(c.sortedSet, func(i int, j int) bool {return c.sortedSet[i] < c.sortedSet[j]})// Storing member at this map is useful to find backup members of a partition.c.members[member.String()] = &member
}

我們每次增加服務器都會修改sortedset以及ring(虛擬節點和服務器的映射),但是如果我們能夠得到服務器列表,那么是可以在本地構建sortedset和ring

分區和服務器映射需要存儲到區塊鏈中嗎?不需要

它是通過確定性算法計算出來的:partitions 的內容是根據成員列表、虛擬節點哈希環和有界負載等參數,通過 distributePartitions() 方法計算得出的。這個過程是確定性的,只要輸入(成員列表、配置)相同,輸出(partitions 映射)也一定相同。
它與 sortedSet 是強關聯的:partitions 映射的構建依賴于 sortedSet 和 ring。distributePartitions() 函數正是通過遍歷 sortedSet 來為每個邏輯分區尋找歸屬成員的。
它是高頻查詢的關鍵:Consistent.LocateKey 方法的最后一步就是查詢 partitions 映射。如果這個映射也需要從區塊鏈上獲取,那么每次鍵的定位都會變成一個慢速的區塊鏈查詢,這會徹底破壞系統的性能。

下面開始構建
鏈碼
我們先創建一個鏈碼
找一個位置存下下面的代碼

package mainimport ("encoding/json""fmt""log"// "strconv"// "github.com/hyperledger/fabric-chaincode-go/shim""github.com/hyperledger/fabric-contract-api-go/contractapi"
)// ConsistentHashManager 鏈碼的智能合約結構體
type ConsistentHashManager struct {contractapi.Contract
}// 成員列表鍵,用于在世界狀態中存儲成員列表
const membersKey = "all_members_key"// Member represents a member in the consistent hash ring.
// This is the same structure we used in our previous local Go program.
type Member struct {Name string `json:"name"`
}// InitLedger 初始化鏈碼。
// 在這里,我們將創建一個空的成員列表并將其寫入世界狀態。
func (s *ConsistentHashManager) InitLedger(ctx contractapi.TransactionContextInterface) error {log.Printf("Initializing the ledger with an empty member list.")// 創建一個空成員列表members := []Member{}membersJSON, err := json.Marshal(members)if err != nil {return err}// 將空成員列表寫入世界狀態return ctx.GetStub().PutState(membersKey, membersJSON)
}// AddMember 添加一個新成員到哈希環中。
func (s *ConsistentHashManager) AddMember(ctx contractapi.TransactionContextInterface, memberName string) error {log.Printf("Attempting to add member: %s", memberName)// 從世界狀態中讀取當前成員列表membersJSON, err := ctx.GetStub().GetState(membersKey)if err != nil {return fmt.Errorf("failed to read from world state: %w", err)}// 如果列表不存在,創建一個空列表if membersJSON == nil {membersJSON = []byte("[]")}// 反序列化成員列表var members []Membererr = json.Unmarshal(membersJSON, &members)if err != nil {return fmt.Errorf("failed to unmarshal member list: %w", err)}// 檢查成員是否已存在for _, member := range members {if member.Name == memberName {return fmt.Errorf("member '%s' already exists", memberName)}}// 添加新成員members = append(members, Member{Name: memberName})// 將更新后的列表序列化membersJSON, err = json.Marshal(members)if err != nil {return err}// 將更新后的列表寫入世界狀態return ctx.GetStub().PutState(membersKey, membersJSON)
}// RemoveMember 從哈希環中移除一個成員。
func (s *ConsistentHashManager) RemoveMember(ctx contractapi.TransactionContextInterface, memberName string) error {log.Printf("Attempting to remove member: %s", memberName)// 從世界狀態中讀取當前成員列表membersJSON, err := ctx.GetStub().GetState(membersKey)if err != nil {return fmt.Errorf("failed to read from world state: %w", err)}if membersJSON == nil {return fmt.Errorf("member list is empty, cannot remove '%s'", memberName)}// 反序列化成員列表var members []Membererr = json.Unmarshal(membersJSON, &members)if err != nil {return fmt.Errorf("failed to unmarshal member list: %w", err)}// 查找并移除成員found := falsefor i, member := range members {if member.Name == memberName {// 移除切片中的元素members = append(members[:i], members[i+1:]...)found = truebreak}}if !found {return fmt.Errorf("member '%s' not found", memberName)}// 將更新后的列表序列化membersJSON, err = json.Marshal(members)if err != nil {return err}// 將更新后的列表寫入世界狀態return ctx.GetStub().PutState(membersKey, membersJSON)
}// GetMembers 查詢并返回當前所有成員。
func (s *ConsistentHashManager) GetMembers(ctx contractapi.TransactionContextInterface) ([]*Member, error) {log.Println("Querying for all members.")// 從世界狀態中讀取成員列表membersJSON, err := ctx.GetStub().GetState(membersKey)if err != nil {return nil, fmt.Errorf("failed to read from world state: %w", err)}if membersJSON == nil {log.Println("No members found, returning empty list.")return []*Member{}, nil}// 反序列化成員列表var members []Membererr = json.Unmarshal(membersJSON, &members)if err != nil {return nil, fmt.Errorf("failed to unmarshal member list: %w", err)}// 將 []Member 轉換為 []*Member 以符合 contractapi 接口var result []*Memberfor i := range members {result = append(result, &members[i])}return result, nil
}func main() {chaincode, err := contractapi.NewChaincode(&ConsistentHashManager{})if err != nil {log.Panicf("Error creating consistent hash manager chaincode: %v", err)}if err := chaincode.Start(); err != nil {log.Panicf("Error starting consistent hash manager chaincode: %v", err)}
}

然后我們再運行

go mod init consistent-hash-manager # 你可以替換成你喜歡的模塊名
go mod tidy

下面就可以去部署網絡,部署鏈碼

./network.sh deployCC -ccn consistent-hash-manager -ccp ../chaincode/ConsistentHashManager -ccv 1.0 -ccl go -c mychannel

接著我們運行我們的客戶端代碼

package mainimport ("bytes""crypto/x509""encoding/json""fmt""log""os""path"// "time""github.com/hyperledger/fabric-gateway/pkg/client""github.com/hyperledger/fabric-gateway/pkg/identity""google.golang.org/grpc""google.golang.org/grpc/credentials"
)// 定義鏈碼名稱、通道名稱和網絡配置路徑
const (mspID       = "Org1MSP"cryptoPath  = "../../test-network/organizations/peerOrganizations/org1.example.com"certPath    = cryptoPath + "/users/User1@org1.example.com/msp/signcerts"keyPath     = cryptoPath + "/users/User1@org1.example.com/msp/keystore"tlsCertPath = cryptoPath + "/peers/peer0.org1.example.com/tls/ca.crt"peerEndpoint = "localhost:7051"         // Fabric Peer 的 Gateway 服務地址gatewayPeer  = "peer0.org1.example.com" // Gateway Peer 的主機名,用于 TLS 驗證channelName   = "mychannel"chaincodeName = "consistent-hash-manager" // 使用我們自己的鏈碼名稱
)// Member 結構體,用于解析鏈碼返回的成員列表
type Member struct {Name string `json:"name"`
}// newGrpcConnection 創建與 Gateway 服務器的 gRPC 連接
func newGrpcConnection() *grpc.ClientConn {log.Println("--> Creating gRPC client connection...")certificatePEM, err := os.ReadFile(tlsCertPath)if err != nil {log.Fatalf("Failed to read TLS certificate file at %s: %v", tlsCertPath, err)}certPool := x509.NewCertPool()if !certPool.AppendCertsFromPEM(certificatePEM) {log.Fatalf("Failed to append TLS CA certificate to pool")}transportCredentials := credentials.NewClientTLSFromCert(certPool, gatewayPeer)connection, err := grpc.NewClient(peerEndpoint, grpc.WithTransportCredentials(transportCredentials), grpc.WithBlock())if err != nil {log.Fatalf("Failed to create gRPC connection: %v", err)}log.Println("--> gRPC client connection created successfully.")return connection
}// newIdentity 為 Gateway 連接創建一個客戶端身份 (X.509 證書)
func newIdentity() *identity.X509Identity {log.Println("--> Creating new client identity...")certificatePEM, err := readFirstFile(certPath)if err != nil {log.Fatalf("Failed to read certificate file from %s: %v", certPath, err)}certificate, err := identity.CertificateFromPEM(certificatePEM)if err != nil {log.Fatalf("Failed to parse identity certificate: %v", err)}id, err := identity.NewX509Identity(mspID, certificate)if err != nil {log.Fatalf("Failed to create X.509 identity: %v", err)}log.Println("--> Client identity created successfully.")return id
}// newSign 創建一個函數,該函數使用私鑰從消息摘要生成數字簽名。
func newSign() identity.Sign {log.Println("--> Creating new private key signer...")privateKeyPEM, err := readFirstFile(keyPath)if err != nil {log.Fatalf("Failed to read private key file from %s: %v", keyPath, err)}privateKey, err := identity.PrivateKeyFromPEM(privateKeyPEM)if err != nil {log.Fatalf("Failed to parse private key: %v", err)}sign, err := identity.NewPrivateKeySign(privateKey)if err != nil {log.Fatalf("Failed to create private key signer: %v", err)}log.Println("--> Private key signer created successfully.")return sign
}// readFirstFile 從指定目錄中讀取第一個文件
func readFirstFile(dirPath string) ([]byte, error) {dir, err := os.Open(dirPath)if err != nil {return nil, fmt.Errorf("failed to open directory %s: %w", dirPath, err)}defer dir.Close()fileNames, err := dir.Readdirnames(1)if err != nil {return nil, fmt.Errorf("failed to read file names from directory %s: %w", dirPath, err)}if len(fileNames) == 0 {return nil, fmt.Errorf("no files found in directory: %s", dirPath)}filePath := path.Join(dirPath, fileNames[0])fileContent, err := os.ReadFile(filePath)if err != nil {return nil, fmt.Errorf("failed to read file %s: %w", filePath, err)}return fileContent, nil
}// formatJSON 格式化 JSON 數據,使其更易讀
func formatJSON(data []byte) string {if len(data) == 0 {return "[]" // 如果數據為空,返回一個空的 JSON 數組字符串}var prettyJSON bytes.Bufferif err := json.Indent(&prettyJSON, data, "", "  "); err != nil {log.Printf("Warning: Failed to parse JSON, returning raw data. Error: %v", err)return string(data)}return prettyJSON.String()
}func main() {// 1. 創建 gRPC 客戶端連接clientConnection := newGrpcConnection()defer clientConnection.Close()// 2. 創建客戶端身份和簽名函數id := newIdentity()sign := newSign()// 3. 連接 Fabric Gatewaygw, err := client.Connect(id,client.WithSign(sign),client.WithClientConnection(clientConnection),)if err != nil {log.Fatalf("Failed to connect to Gateway: %v", err)}defer gw.Close()// 獲取網絡和合約對象network := gw.GetNetwork(channelName)contract := network.GetContract(chaincodeName)// memberNameToAdd := "node-a"// // 4. 調用 AddMember 提交事務// log.Printf("\n--> 提交 AddMember 事務以添加 '%s'...", memberNameToAdd)// _, err = contract.SubmitTransaction("AddMember", memberNameToAdd)// if err != nil {// 	log.Fatalf("Failed to submit AddMember transaction: %v", err)// }// log.Printf("成員 '%s' 添加成功。", memberNameToAdd)// memberNameToAdd2 := "node-b"// // 4. 調用 AddMember 提交事務// log.Printf("\n--> 提交 AddMember 事務以添加 '%s'...", memberNameToAdd2)// _, err = contract.SubmitTransaction("AddMember", memberNameToAdd2)// if err != nil {// 	log.Fatalf("Failed to submit AddMember transaction: %v", err)// }// log.Printf("成員 '%s' 添加成功。", memberNameToAdd2)// 5. 調用 GetMembers 查詢當前成員列表log.Println("\n--> 查詢所有成員...")result, err := contract.EvaluateTransaction("GetMembers")if err != nil {log.Fatalf("Failed to evaluate GetMembers transaction: %v", err)}log.Printf("當前成員列表:\n%s", formatJSON(result))// // 6. 調用 RemoveMember 提交事務// log.Printf("\n--> 提交 RemoveMember 事務以移除 '%s'...", memberNameToAdd)// _, err = contract.SubmitTransaction("RemoveMember", memberNameToAdd)// if err != nil {// 	log.Fatalf("Failed to submit RemoveMember transaction: %v", err)// }// log.Printf("成員 '%s' 移除成功。", memberNameToAdd)// // 7. 再次調用 GetMembers 查詢以確認移除// log.Println("\n--> 再次查詢所有成員以確認移除...")// result, err = contract.EvaluateTransaction("GetMembers")// if err != nil {// 	log.Fatalf("Failed to evaluate GetMembers transaction: %v", err)// }// log.Printf("移除后成員列表:\n%s", formatJSON(result))// log.Println("\n所有操作已完成。")
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/917561.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/917561.shtml
英文地址,請注明出處:http://en.pswp.cn/news/917561.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用yolo11訓練智慧醫療-孤獨癥兒童行為檢測數據集VOC+YOLO格式7295張34類別步驟和流程

【數據集介紹】數據集中有很多增強圖片&#xff0c;也有很多視頻連續截取圖片請查看圖片預覽數據集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路徑的txt文件&#xff0c;僅僅包含jpg圖片以及對應的VOC格式xml文件和yolo格式txt文件)圖片數量(jpg文件個數)&#xff1a;…

vim 組件 使用pysocket進行sock連接

vim組件實現 以下是使用 Vim 插件架構實現 Python Socket 客戶端的完整方案&#xff0c;支持集成到 Vim 控件并實現雙向通信&#xff1a; ~/.vim/plugin/socket_client.vim" 定義全局命令和快捷鍵 command! -nargs* SocketConnect call s:StartSocketClient(<f-args>…

FFmpeg+javacpp中純音頻播放

FFmpegjavacpp中純音頻播放1. Java Sound播放2、整合音頻信息AudioInfo3、添加ExecutorService執行播放FFmpegjavacppjavacv使用 FFmpegjavacpp中FFmpegFrameGrabber FFmpegjavacpp中仿ffplay播放 JavaCV 1.5.12 API JavaCPP Presets for FFmpeg 7.1.1-1.5.12 API1. Java Soun…

洛谷P1036 [NOIP 2002 普及組] 選數

P1036 [NOIP 2002 普及組] 選數 題目描述 已知 nnn 個整數 x1,x2,??,xnx_1,x_2,\cdots,x_nx1?,x2?,?,xn?&#xff0c;以及 111 個整數 kkk&#xff08;k<nk<nk<n&#xff09;。從 nnn 個整數中任選 kkk 個整數相加&#xff0c;可分別得到一系列的和。例如當 n4n…

Linux學習記錄(八)文件共享

本文記錄在Vmware中啟用文件共享時的一些注意事項&#xff1a;1.提前安裝vmware-tools&#xff0c;可以通過Vmware的虛擬機菜單欄中拿到文件&#xff0c;然后直接運行vmware-install.pl文件進行安裝&#xff1b;也可以通過指令sudo apt-get install open-vm-tools進行安裝。推薦…

洛谷 火燒赤壁 差分/貪心

題目背景曹操平定北方以后&#xff0c;公元 208 年&#xff0c;率領大軍南下&#xff0c;進攻劉表。他的人馬還沒有到荊州&#xff0c;劉表已經病死。他的兒子劉琮聽到曹軍聲勢浩大&#xff0c;嚇破了膽&#xff0c;先派人求降了。孫權任命周瑜為都督&#xff0c;撥給他三萬水軍…

Linux 用戶與組管理全解析

Linux 用戶與組管理一、用戶和組的基本概念 1. 用戶賬號類型 超級用戶&#xff08;root&#xff09;&#xff1a;默認擁有系統最高權限&#xff08;UID0&#xff09;&#xff0c;僅建議用于系統管理與維護&#xff0c;日常操作應使用普通用戶。普通用戶&#xff1a;由管理員創建…

開疆智能ModbusTCP轉Profient網關連接ER機器人配置案例

本案例時西門子1200PLC通過ModbusTCP轉Profinet網關連接埃斯頓機器人的配置案例&#xff0c;網關作為ModbusTCP的客戶端連接機器人。配置過程&#xff1a;首先打開機器人通訊手冊。查詢機器人支持的功能碼及默認IP和端口號打開網關配置軟件“Gateway Configuration Studio”新建…

Docker換源加速(更換鏡像源)詳細教程(2025.3最新可用鏡像,全網最詳細)

文章目錄前言可用鏡像源匯總換源方法1-臨時換源換源方法2-永久換源&#xff08;推薦&#xff09;常見問題及對應解決方案1.換源后&#xff0c;可以成功pull&#xff0c;但是search會出錯補充1.如何測試鏡像源是否可用2.Docker內的Linux換源教程換源速通版&#xff08;可以直接無…

機器學習【三】SVM

本文系統介紹了支持向量機(SVM)的理論與實踐。理論部分首先區分了線性可分與不可分問題&#xff0c;闡述了SVM通過尋找最優超平面實現分類的核心思想&#xff0c;包括支持向量、間隔最大化等關鍵概念。詳細講解了硬間隔與軟間隔SVM的數學原理&#xff0c;以及核函數(線性核、多…

DevOps平臺大比拼:Gitee、Jenkins與CircleCI如何選型?

DevOps平臺大比拼&#xff1a;Gitee、Jenkins與CircleCI如何選型&#xff1f; 在數字化轉型浪潮席卷全球的當下&#xff0c;DevOps已成為企業提升研發效能的關鍵引擎。面對市場上紛繁復雜的DevOps工具鏈&#xff0c;如何選擇最適合自身業務需求的平臺成為技術決策者的重要課題。…

開源醫院信息管理系統:基于若依框架的智慧醫療解決方案

引言在數字化浪潮的推動下&#xff0c;醫療行業正加速向信息化、智能化轉型。醫院信息管理系統&#xff08;HIS&#xff09;作為醫療管理的核心工具&#xff0c;直接影響醫院的運營效率和服務質量。近期&#xff0c;一款基于 若依框架 Vue 的開源醫院管理系統&#xff08;hosp…

我的世界進階模組開發教程——附魔(2)

EnchantmentHelper 類詳解 EnchantmentHelper 是 Minecraft 中處理物品附魔邏輯的核心工具類,提供附魔的存儲、查詢、計算和應用等功能。以下是對其字段和方法的逐行詳細解釋: 關鍵字段 private static final String TAG_ENCH_ID = "id"; // NBT標簽鍵:附…

深度學習零基礎入門(4)-卷積神經網絡架構

許久不見~ 本節我們延續上一節的話題來看看卷積神經網絡的架構&#xff0c;看看具體的卷積、池化等操作卷積神經網絡詳解&#xff1a;從基礎操作到整體架構 一、卷積操作&#xff1a;特征提取的核心 卷積是卷積神經網絡&#xff08;CNN&#xff09;的核心操作&#xff0c;靈感來…

C語言的控制語句

C的控制語句 控制語句是C語言中用于控制程序執行流程的結構。通過控制語句,可以根據條件執行不同的代碼塊,或者重復執行某些操作,從而實現復雜的邏輯和功能。掌握控制語句是編寫有效和高效C程序的關鍵。 1 條件控制 條件控制語句用于根據某些條件來決定程序的執行路徑。C語…

Mac電腦基本功能快捷鍵

1. 個性化桌面 將喜愛照片添加為桌面墻紙。前往“系統設置”&#xff0c;然后點按邊欄中的“墻紙”。點按“添加照片”&#xff0c;然后從文件或“照片”App選取一張照片。 2. 截屏 按下鍵盤上的Shift &#xfffc; Command ? 5&#xff0c;然后選取捕捉整個屏幕、App窗口或…

微算法科技(NASDAQ: MLGO)開發量子邊緣檢測算法,為實時圖像處理與邊緣智能設備提供了新的解決方案

圖像邊緣檢測是計算機視覺的核心任務&#xff0c;傳統算法&#xff08;如 Sobel、Canny&#xff09;依賴梯度計算與閾值分割&#xff0c;在處理高分辨率、復雜紋理圖像時面臨計算效率瓶頸。隨著量子計算技術的發展&#xff0c;利用量子態疊加與并行處理特性&#xff0c;微算法科…

斷點續傳Demo實現

基于我們的DownloadManager.swift代碼&#xff0c;讓我詳細解釋斷點續傳需要實現的核心功能&#xff1a; 斷點續傳的核心實現要素 1. 后臺會話配置 private func setupBackgroundSession() {let config URLSessionConfiguration.background(withIdentifier: "com.test.do…

《Leetcode》-面試題-hot100-子串

題目列表 560. 和為K的子數組 中等難度 leetcode鏈接 239 滑動窗口最大值 困難難度 leetcode鏈接 76 最小覆蓋子串 困難難度 leetcode鏈接 題目 &#xff08;1&#xff09;和為K的子數組 給你一個整數數組 nums 和一個整數 k &#xff0c;請你統計并返回 該數組中和為 …

點擊彈框以外的區域關閉彈框

在 Vue 3 中&#xff0c;如果你想判斷點擊的目標是否在彈框內&#xff0c;可以通過以下步驟實現。這里我們將使用 ref 來引用彈框組件&#xff0c;并在點擊事件中進行判斷。 示例代碼 1. 創建彈框子組件 首先&#xff0c;創建一個名為 Modal.vue 的子組件。 <!-- Modal.vue …