raftexample, आदि द्वारा प्रदान किया गया एक उदाहरण है जो आदि राफ्ट सर्वसम्मति एल्गोरिदम लाइब्रेरी के उपयोग को प्रदर्शित करता है। राफ़्टेक्सैम्पल अंततः एक वितरित कुंजी-मूल्य भंडारण सेवा लागू करता है जो एक REST API प्रदान करता है।
यह आलेख राफ्टएक्सैम्पल के कोड को पढ़ेगा और उसका विश्लेषण करेगा, जिससे पाठकों को बेहतर ढंग से समझने में मदद मिलेगी कि आदि राफ्ट लाइब्रेरी और राफ्ट लाइब्रेरी के कार्यान्वयन तर्क का उपयोग कैसे किया जाए।
Raftexample का आर्किटेक्चर बहुत सरल है, मुख्य फ़ाइलें इस प्रकार हैं:
HTTP PUT अनुरोध के माध्यम से httpapi मॉड्यूल की ServeHTTP विधि में एक लेखन अनुरोध आता है।
curl -L http://127.0.0.1:12380/key -XPUT -d value
स्विच के माध्यम से HTTP अनुरोध विधि से मिलान करने के बाद, यह PUT विधि प्रसंस्करण प्रवाह में प्रवेश करता है:
प्रस्ताव राफ्ट एल्गोरिथम लाइब्रेरी द्वारा प्रदान की गई प्रस्ताव विधि के माध्यम से राफ्ट एल्गोरिथम लाइब्रेरी को प्रस्तुत किया गया है।
प्रस्ताव की सामग्री में एक नई कुंजी-मूल्य जोड़ी जोड़ना, मौजूदा कुंजी-मूल्य जोड़ी को अपडेट करना आदि शामिल हो सकता है।
// httpapi.go v, err := io.ReadAll(r.Body) if err != nil { log.Printf("Failed to read on PUT (%v)\n", err) http.Error(w, "Failed on PUT", http.StatusBadRequest) return } h.store.Propose(key, string(v)) w.WriteHeader(http.StatusNoContent)
इसके बाद, आइए kvstore मॉड्यूल की प्रपोज विधि पर नजर डालें कि प्रस्ताव कैसे बनाया और संसाधित किया जाता है।
प्रोपोज़ विधि में, हम पहले गोब का उपयोग करके लिखे जाने वाले कुंजी-मूल्य जोड़े को एन्कोड करते हैं, और फिर एन्कोडेड सामग्री को प्रपोज़सी में पास करते हैं, एक चैनल जो केवीस्टोर मॉड्यूल द्वारा निर्मित प्रस्तावों को राफ्ट मॉड्यूल में प्रसारित करने के लिए जिम्मेदार है।
// kvstore.go func (s *kvstore) Propose(k string, v string) { var buf strings.Builder if err := gob.NewEncoder(&buf).Encode(kv{k, v}); err != nil { log.Fatal(err) } s.proposeCकेवीस्टोर द्वारा निर्मित और प्रपोजसी को पारित प्रस्ताव राफ्ट मॉड्यूल में सर्वचैनल्स विधि द्वारा प्राप्त और संसाधित किया जाता है।
यह पुष्टि करने के बाद कि प्रपोजसी को बंद नहीं किया गया है, राफ्ट मॉड्यूल राफ्ट एल्गोरिदम लाइब्रेरी द्वारा प्रदान की गई प्रपोज विधि का उपयोग करके प्रसंस्करण के लिए प्रस्ताव को राफ्ट एल्गोरिदम लाइब्रेरी में जमा करता है।
// raft.go select { case prop, ok :=एक प्रस्ताव प्रस्तुत होने के बाद, यह राफ्ट एल्गोरिदम प्रक्रिया का पालन करता है। प्रस्ताव अंततः लीडर नोड को भेज दिया जाएगा (यदि वर्तमान नोड लीडर नहीं है और आप अनुयायियों को DisableProposalForwarding कॉन्फ़िगरेशन द्वारा नियंत्रित प्रस्तावों को अग्रेषित करने की अनुमति देते हैं)। नेता प्रस्ताव को अपने राफ्ट लॉग में लॉग प्रविष्टि के रूप में जोड़ देगा और इसे अन्य अनुयायी नोड्स के साथ सिंक्रनाइज़ करेगा। प्रतिबद्ध समझे जाने के बाद, इसे राज्य मशीन पर लागू किया जाएगा और परिणाम उपयोगकर्ता को वापस कर दिया जाएगा।
हालाँकि, चूंकि आदि राफ्ट लाइब्रेरी स्वयं नोड्स के बीच संचार, राफ्ट लॉग को जोड़ना, राज्य मशीन पर लागू करना आदि को संभाल नहीं पाती है, इसलिए राफ्ट लाइब्रेरी केवल इन परिचालनों के लिए आवश्यक डेटा तैयार करती है। वास्तविक संचालन हमारे द्वारा किया जाना चाहिए।
इसलिए, हमें इस डेटा को राफ्ट लाइब्रेरी से प्राप्त करने और इसके प्रकार के आधार पर इसे संसाधित करने की आवश्यकता है। रेडी विधि एक रीड-ओनली चैनल लौटाती है जिसके माध्यम से हम वह डेटा प्राप्त कर सकते हैं जिसे संसाधित करने की आवश्यकता है।
यह ध्यान दिया जाना चाहिए कि प्राप्त डेटा में कई फ़ील्ड शामिल हैं, जैसे लागू किए जाने वाले स्नैपशॉट, राफ्ट लॉग में जोड़े जाने वाली लॉग प्रविष्टियां, नेटवर्क पर प्रसारित होने वाले संदेश, आदि।
हमारे लेखन अनुरोध उदाहरण (लीडर नोड) को जारी रखते हुए, संबंधित डेटा प्राप्त करने के बाद, हमें सर्वर क्रैश (उदाहरण के लिए, एक अनुयायी द्वारा कई उम्मीदवारों के लिए मतदान) के कारण होने वाली समस्याओं को संभालने के लिए स्नैपशॉट, हार्डस्टेट और प्रविष्टियों को लगातार सहेजने की आवश्यकता होती है। जैसा कि पेपर में बताया गया है, हार्डस्टेट और एंट्रीज़ मिलकर सभी सर्वरों पर पर्सिस्टेंट स्थिति बनाते हैं। उन्हें लगातार सहेजने के बाद, हम स्नैपशॉट लागू कर सकते हैं और राफ्ट लॉग में जोड़ सकते हैं।
चूंकि हम वर्तमान में लीडर नोड हैं, राफ्ट लाइब्रेरी हमें MsgApp प्रकार के संदेश लौटाएगी (पेपर में AppendEntries RPC के अनुरूप)। हमें इन संदेशों को अनुयायी नोड्स को भेजने की आवश्यकता है। यहां, हम नोड संचार के लिए आदि द्वारा प्रदान किए गए राफ्टhttp का उपयोग करते हैं और सेंड विधि का उपयोग करके अनुयायियों को संदेश भेजते हैं।
// raft.go case rd :=इसके बाद, हम राज्य मशीन पर प्रतिबद्ध राफ्ट लॉग प्रविष्टियों को लागू करने के लिए पब्लिशएंट्रीज़ विधि का उपयोग करते हैं। जैसा कि पहले उल्लेख किया गया है, राफ्टएक्सैम्पल में, केवीस्टोर मॉड्यूल राज्य मशीन के रूप में कार्य करता है। पब्लिशएंट्रीज़ विधि में, हम उन लॉग प्रविष्टियों को पास करते हैं जिन्हें कमिटसी के लिए राज्य मशीन पर लागू करने की आवश्यकता होती है। पहले के प्रस्तावसी के समान, कमिटसी उन लॉग प्रविष्टियों को प्रसारित करने के लिए जिम्मेदार है जिन्हें राफ्ट मॉड्यूल ने राज्य मशीन पर आवेदन के लिए केवीस्टोर मॉड्यूल के लिए प्रतिबद्ध माना है।
// raft.go rc.commitCकेवीस्टोर मॉड्यूल की रीडकमिट्स विधि में, कमिटसी से पढ़े गए संदेशों को मूल कुंजी-मूल्य जोड़े को पुनः प्राप्त करने के लिए गोब-डिकोड किया जाता है, जिन्हें फिर केवीस्टोर मॉड्यूल के भीतर एक मानचित्र संरचना में संग्रहीत किया जाता है।
// kvstore.go for commit := range commitC { ... for _, data := range commit.data { var dataKv kv dec := gob.NewDecoder(bytes.NewBufferString(data)) if err := dec.Decode(&dataKv); err != nil { log.Fatalf("raftexample: could not decode message (%v)", err) } s.mu.Lock() s.kvStore[dataKv.Key] = dataKv.Val s.mu.Unlock() } close(commit.applyDoneC) }राफ्ट मॉड्यूल पर लौटते हुए, हम राफ्ट लाइब्रेरी को सूचित करने के लिए एडवांस विधि का उपयोग करते हैं कि हमने रेडी चैनल से पढ़े गए डेटा को संसाधित करना समाप्त कर लिया है और डेटा के अगले बैच को संसाधित करने के लिए तैयार हैं।
इससे पहले, लीडर नोड पर, हमने सेंड विधि का उपयोग करके फॉलोअर नोड्स को MsgApp प्रकार के संदेश भेजे थे। फॉलोअर नोड का राफ्टhttp अनुरोध प्राप्त करने और प्रतिक्रियाएँ वापस करने के लिए संबंधित पोर्ट पर सुनता है। चाहे यह अनुयायी नोड द्वारा प्राप्त अनुरोध हो या लीडर नोड द्वारा प्राप्त प्रतिक्रिया हो, इसे चरण विधि के माध्यम से प्रसंस्करण के लिए राफ्ट लाइब्रेरी में प्रस्तुत किया जाएगा।
raftNode, Rafthttp में Raft इंटरफ़ेस को कार्यान्वित करता है, और Raft इंटरफ़ेस की प्रक्रिया विधि को प्राप्त अनुरोध सामग्री (जैसे MsgApp संदेश) को संभालने के लिए कहा जाता है।
// raft.go func (rc *raftNode) Process(ctx context.Context, m raftpb.Message) error { return rc.node.Step(ctx, m) }उपरोक्त राफ्ट उदाहरण में एक लेखन अनुरोध के संपूर्ण प्रसंस्करण प्रवाह का वर्णन करता है।
सारांश
यह इस लेख की सामग्री को समाप्त करता है। राफ्टएक्सैम्पल की संरचना की रूपरेखा और एक लेखन अनुरोध के प्रसंस्करण प्रवाह का विवरण देकर, मुझे आशा है कि मैं आपको बेहतर ढंग से समझने में मदद करूंगा कि अपनी स्वयं की वितरित केवी भंडारण सेवा बनाने के लिए आदि राफ्ट लाइब्रेरी का उपयोग कैसे करें।
यदि कोई गलती या समस्या है, तो कृपया बेझिझक टिप्पणी करें या मुझे सीधे संदेश भेजें। धन्यवाद।
संदर्भ
https://github.com/etcd-io/etcd/tree/main/contrib/raftexample
https://github.com/etcd-io/raft
https://raft.github.io/raft.pdf
अस्वीकरण: उपलब्ध कराए गए सभी संसाधन आंशिक रूप से इंटरनेट से हैं। यदि आपके कॉपीराइट या अन्य अधिकारों और हितों का कोई उल्लंघन होता है, तो कृपया विस्तृत कारण बताएं और कॉपीराइट या अधिकारों और हितों का प्रमाण प्रदान करें और फिर इसे ईमेल पर भेजें: [email protected] हम इसे आपके लिए यथाशीघ्र संभालेंगे।
Copyright© 2022 湘ICP备2022001581号-3