1. परिदृश्य और सफलता के मानदंड
सेवा प्रत्येक बैच के लिए कई workers शुरू करती है और एक चैनल पर परिणामों को एकत्रित (aggregate) करती है। जब एक worker कोई त्रुटि लौटाता है, तो कॉलर जल्दी वापस लौट जाता है। पीक्स के दौरान, मेमोरी और goroutine संख्या तब तक बढ़ती है जब तक कि किसी इंस्टेंस को पुनरारंभ (restart) करना अस्थायी रूप से मदद नहीं करता। अपग्रेड में ऐसी goroutines ढूंढनी होंगी जो अनब्लॉक नहीं हो सकती हैं, कैंसलेशन सिमेंटिक्स को संरक्षित करना होगा, Go 1.26 GC व्यवहार की तुलना करनी होगी, और एक प्रतिवर्ती (reversible) रोलआउट प्रदान करना होगा।
बेसलाइन से शुरुआत करें: अनुरोध लेटेंसी पर्सेंटाइल, थ्रूपुट, हीप साइज़, GC CPU, सक्रिय goroutines, लीक स्लोप, और त्रुटि दर। अकेले runtime.NumGoroutine यह नहीं बता सकता कि वास्तव में कौन सी goroutines लीक हुई हैं।
2. प्रासंगिक Go 1.26 परिवर्तन
Go 1.26 स्थायी रूप से ब्लॉक और वेक होने में असमर्थ goroutines के एक वर्ग के लिए एक प्रायोगिक goroutineleak pprof प्रोफ़ाइल पेश करता है। इसे GOEXPERIMENT=goroutineleakprofile के साथ सक्षम करें और इसे net/http/pprof के माध्यम से प्रदर्शित करें। यह कचरा बीनने वाले (garbage-collector) की पहुंच (reachability) पर निर्भर करता है और प्रत्येक लीक की पहचान नहीं कर सकता है, इसलिए इसे अनुपस्थिति के प्रमाण के बजाय एक डायग्नोस्टिक सिग्नल के रूप में समझें।
यह रिलीज़ go fix मॉडर्नाइज़र भी प्रदान करती है, new को एक एक्सप्रेशन स्वीकार करने देती है, और डिफ़ॉल्ट रूप से Green Tea GC को सक्षम करती है। भाषा की सुविधाओं, प्रायोगिक डायग्नोस्टिक्स, और रनटाइम परिवर्तनों का अलग-अलग मूल्यांकन करें ताकि एक बेंचमार्क असंबद्ध वेरिएबल्स को मिश्रित न करे।
3. एक न्यूनतम लीक रीप्रोडक्शन का निर्माण करें
यह पैटर्न पहली त्रुटि पर वापस आ जाता है जबकि अन्य workers अभी भी एक अनबफर्ड चैनल पर भेजते हैं और अंततः हमेशा के लिए ब्लॉक हो जाते हैं:
func processWorkItems(ctx context.Context, ws []WorkItem) ([]Result, error) {
ch := make(chan result)
for _, w := range ws {
go func() {
value, err := process(ctx, w)
ch <- result{value: value, err: err}
}()
}
results := make([]Result, 0, len(ws))
for range ws {
r := <-ch
if r.err != nil {
return nil, r.err
}
results = append(results, r.value)
}
return results, nil
}डिटरमिनिस्टिक त्रुटियों को इंजेक्ट करें, रन को दोहराएं, और goroutine संख्या देखते हुए बैच आकार बढ़ाएं। कॉलर कैंसलेशन, टाइमआउट, और सफल पूर्णता पथ शामिल करें ताकि फिक्स केवल हैप्पी पाथ को ही कवर न करे।
4. कैंसलेशन, क्लोजिंग, और बैकप्रेशर को ठीक करें
भेजने वालों (senders) को ctx.Done() का सम्मान करने के लिए कहें और सुनिश्चित करें कि रिसीवर कैंसलेशन सेंडर्स को पीछे नहीं छोड़ सकता है। एक स्पष्ट क्षमता वाला बफ़र्ड चैनल काम कर सकता है, जैसा कि क्लोजिंग और एग्रीगेशन के लिए जिम्मेदार एक समन्वयक (coordinator) goroutine कर सकता है। एकाधिक workers को एक चैनल को बंद करने के लिए रेस नहीं करनी चाहिए।
select {
case ch <- result{value: value, err: err}:
case <-ctx.Done():
}एक पूर्ण फिक्स पहली त्रुटि पर एक व्युत्पन्न (derived) संदर्भ को रद्द करता है, सभी workers के बाहर निकलने की प्रतीक्षा करता है, और फिर त्रुटि लौटाता है। errgroup.WithContext उस जीवनकाल का समन्वय कर सकता है, लेकिन प्रत्येक worker को अभी भी संदर्भ का प्रसार करना होगा और बाहरी I/O पर टाइमआउट लागू करना होगा।
5. goroutineleak प्रोफ़ाइल सक्षम करें और साक्ष्य एकत्र करें
GOEXPERIMENT=goroutineleakprofile के साथ एक पृथक (isolated) बाइनरी बनाएं और एक संरक्षित pprof एंडपॉइंट का नमूना लें। उसी विंडो पर लीक प्रोफ़ाइल, goroutine स्टैक, हीप प्रोफ़ाइल, ट्रेस, और व्यावसायिक मेट्रिक्स की तुलना करें। एक खाली प्रोफ़ाइल यह साबित नहीं करती है कि कोई लीक नहीं है: ग्लोबल्स से पहुंच योग्य ब्लॉकिंग प्रिमिटिव्स को इस तंत्र द्वारा वर्गीकृत नहीं किया जा सकता है।
लोड और फॉल्ट इंजेक्शन के दौरान नमूना लें, Go संस्करण, प्रयोग फ़्लैग, अनुरोध लोड, और नमूनाकरण अंतराल रिकॉर्ड करें। उत्पादन में, एंडपॉइंट एक्सेस, सैंपलिंग आवृत्ति, और अवधारण (retention) को प्रतिबंधित करें ताकि डायग्नोस्टिक्स सूचना-प्रदर्शन (information-exposure) सतह न बनें।
6. Green Tea GC और अपग्रेड अनुकूलता का मूल्यांकन करें
Go 1.26 डिफ़ॉल्ट रूप से Green Tea GC को सक्षम करता है। रिलीज़ नोट्स छोटी वस्तुओं को चिह्नित करने और स्कैन करने के दौरान बेहतर लोकैलिटी और CPU स्केलेबिलिटी के लक्ष्यों का वर्णन करते हैं, लेकिन इसका लाभ वर्कलोड पर निर्भर करता है। बेंचमार्क में GC CPU, पॉज़ समय, पीक हीप, और अनुरोध लेटेंसी को अलग करें और समान हार्डवेयर, कंपाइलर फ़्लैग, और ट्रैफ़िक पर पुराने संस्करण के साथ तुलना करें।
यदि कोई रिग्रेशन दिखाई देता है, तो रिपोर्ट करने का निर्णय लेने से पहले अस्थायी रूप से GOEXPERIMENT=nogreenteagc का डायग्नोस्टिक नियंत्रण के रूप में उपयोग करें। एक प्रायोगिक ऑप्ट-आउट को स्थायी आर्किटेक्चर में न बदलें। ट्रैफ़िक बढ़ाने से पहले कैनरी में रेस व्यवहार, cgo, प्लगइन्स, और निर्भरताओं को मान्य करें।
7. ऑडिट योग्य आधुनिकीकरण के रूप में go fix का उपयोग करें
go fix व्यवहार-संरक्षित मॉडर्नाइज़र लागू करने के लिए go vet के समान विश्लेषण ढांचे का उपयोग करता है; Go 1.26 का new(expr) सिंटैक्स एक प्रतिनिधि लक्ष्य है। इसे एक शाखा पर चलाएं और प्रत्येक डिफ की समीक्षा करें, फिर सिमेंटिक्स की पुष्टि करने के लिए संकलन, यूनिट परीक्षण, रेस का पता लगाने और बेंचमार्क का उपयोग करें।
केवल एक नए संस्करण का पालन करने के लिए पूरे कोडबेस को फिर से न लिखें। स्वचालित सुधारों को लीक मरम्मत और GC अपग्रेड से अलग रखें ताकि दूसरे फिक्स को हटाए बिना एक जोखिम को वापस रोल किया जा सके। जनरेट किए गए कोड और क्रॉस-वर्जन मॉड्यूल के लिए स्पष्ट go निर्देश और बिल्ड बाधाओं का उपयोग करें।
8. रूब्रिक और फॉलो-अप्स
समझाना आवश्यक है
- ब्लॉकिंग के कारण की व्याख्या करें और कैंसलेशन, क्लोजिंग, और बैकप्रेशर के साथ worker के जीवनकाल की मरम्मत करें।
- जानें कि
goroutineleakएक प्रायोगिक, पहुंच-आधारित प्रोफ़ाइल है जो हर लीक को कवर नहीं कर सकती है। - Green Tea GC, go fix, और संस्करण अपग्रेड को स्वतंत्र बेसलाइन, कैनरी जांच, और रोलबैक चरणों में अलग करें।
फॉलो-अप प्रश्न
- यदि कोई लीक हुआ चैनल वैश्विक रजिस्ट्री द्वारा धारित है, तो प्रोफ़ाइल इसे क्यों छोड़ सकती है, और आप क्या सबूत जोड़ेंगे?
- पहली त्रुटि के बाद, आप यह कैसे सुनिश्चित करते हैं कि एक अवरुद्ध (blocked) नेटवर्क कॉल भी बाहर निकल जाए?
- आप
GOEXPERIMENT=nogreenteagcका उपयोग कब करेंगे, और आप वास्तविक समस्या को छिपाने से कैसे बचेंगे?
स्कोरिंग गाइड
एक उत्कृष्ट उत्तर रीप्रोडक्शन, लाइफसाइकिल रिपेयर, डायग्नोस्टिक साक्ष्य, और अपग्रेड प्रशासन को जोड़ता है: प्रत्येक worker को रद्द करने योग्य बनाएं, प्रोफाइल और स्टैक के साथ पुष्टि करें, फिर पृथक बेंचमार्क और कैनरी के साथ रनटाइम सुरक्षा साबित करें।