1 पॉइंट द्वारा GN⁺ 2024-05-12 | 1 टिप्पणियां | WhatsApp पर शेयर करें

ActiveSupport::Notifications से जुड़ी Memory Leak को हल करने की प्रक्रिया का सार

  • वह स्थिति जिसमें Memory Leak हुआ

    • एक निश्चित समय के बाद web Dyno की memory usage असामान्य रूप से बढ़ने लगी
    • Pager बजने लगा, और स्थिति memory leak जैसी दिखी
  • तत्काल प्रतिक्रिया

    • Heroku में यदि memory leak का संदेह हो, तो Dyno को restart करके अस्थायी समाधान किया जा सकता है
    • सामान्य deploy cycle के अनुसार restart करना, या memory limit के करीब पहुँचे Dyno को मैन्युअली restart करना
  • कारण पता लगाने के लिए संदिग्ध कोड की समीक्षा

    • memory spike से ठीक पहले deploy किए गए code changes की समीक्षा
    • कारण माने जा रहे कुछ कोड को एक-एक करके deploy कर यह जाँचना कि memory leak होता है या नहीं
    • ऐसा कोई code नहीं मिला जो कारण लगता हो, इसलिए tooling changes भी rollback करके जाँचे गए। फिर भी memory leak जारी रहा
  • memory बढ़ने के pattern का विश्लेषण

    • leak सिर्फ web Dyno में हुआ। Sidekiq, Delayed::Job Dyno सामान्य थे
    • सभी web Dyno हमेशा leak नहीं कर रहे थे। कुछ घंटे सामान्य उपयोग के बाद एक-दो या सभी Dyno में leak शुरू हो जाता था
    • ट्रैफ़िक की मात्रा की बजाय किसी विशेष ट्रैफ़िक के कारण यह हो रहा है, ऐसा संदेह हुआ
    • Dyno के भीतर सभी Puma worker में leak नहीं हो रहा था; कुछ ही worker कुल memory का अधिकांश हिस्सा उपयोग कर रहे थे
  • Heap dump का संग्रह और विश्लेषण

    • rbtrace का उपयोग करके leak हो रहे Ruby process का heap dump इकट्ठा किया गया
      • heroku ps:exec से leak वाले dyno में ssh के जरिए प्रवेश किया गया
      • ps कमांड से सबसे अधिक memory उपयोग कर रहे Ruby worker process का चयन किया गया
      • rbtrace से उस pid पर attach करके memory allocation tracing शुरू की गई (ObjectSpace.trace_object_allocations_start)
      • ObjectSpace.dump_all से heap dump इकट्ठा किया गया। आकार बड़ा होने पर gzip compression किया गया
      • heroku ps:copy से dump file को लोकल मशीन पर लाया गया
    • reap का उपयोग कर heap dump को flamegraph के रूप में visualize किया गया
      • एक Thread मिला जो 1.9GB memory को reference कर रहा था, और उसके नीचे 32,067 objects को reference करने वाला एक Array मिला
    • sheap का उपयोग कर संदिग्ध objects की जाँच की गई
      • वह Thread, Puma का worker thread निकला
      • ActiveSupport::SubscriberQueueRegistry object एक Hash को reference कर रहा था, और उसके नीचे String तथा Array objects थे
      • समस्या वाले Array में 32,000 से अधिक ActiveSupport::Notifications::Event objects जमा थे
  • कारण के बारे में अनुमान

    • अनुमान लगाया गया कि ActiveSupport::Notifications के Event objects गलत तरीके से #children array में जमा हो रहे हैं
    • यदि ActiveSupport::Notifications.instrument block के भीतर error हो, तो संबंधित Event #children से हटे बिना वहीं रह जाता है, और इससे memory leak होता है
  • लोकल में पुनरुत्पादन

    • production में मिले संदिग्ध request path और parameter के साथ लोकल में request भेजी गई
    • 500 Internal Server Error के साथ URI::InvalidURIError होने की पुष्टि हुई
    • यह भी पुष्टि हुई कि वही request भेजने पर production dyno की memory usage तेज़ी से बढ़ जाती है
  • ठोस कारण का विश्लेषण

    • Rails 7.1 में ठीक किया गया ActiveSupport::Notifications का Event#children से जुड़ा एक bug मौजूद था
    • इसके साथ Bugsnag gem में request url को clean करने की प्रक्रिया के दौरान URI.parse पर URI::InvalidURIError raise होने वाला bug भी जुड़ गया, और memory leak हुआ
    • ActiveSupport::Notifications.subscribe block के भीतर raise हुई error पकड़ी नहीं गई, इसलिए संबंधित Event #children array से हटाया नहीं गया और जमा होता गया, जिससे memory leak हुआ
  • समाधान

    • अल्पकालिक: Bugsnag gem को ऐसे version में upgrade करना जहाँ URI::InvalidURIError होने पर भी error raise न हो
    • दीर्घकालिक: उस Rails 7.x में upgrade करना जिसमें ActiveSupport::Notifications का bug ठीक किया गया है

GN⁺ की राय

  • समस्या को पहचानकर व्यवस्थित तरीके से उसके कारण तक पहुँचने की प्रक्रिया प्रभावशाली है। memory leak का संदेह होने पर आज़माए जा सकने वाले बुनियादी analysis steps अच्छी तरह संकलित किए गए हैं
  • Ruby में heap dump इकट्ठा करने, visualize करने और analyze करने के लिए कई open source tools (rbtrace, reap, sheap आदि) सक्रिय रूप से विकसित होते दिखते हैं। सिर्फ Ruby ही नहीं, किसी भी भाषा में उपयोगी memory analysis tools को जानना और समस्या पर लागू करना महत्वपूर्ण लगता है
  • वास्तव में memory leak का कारण अक्सर किसी विशेष library या framework का bug होता है, लेकिन ऐसे bug को सीधे analyze कर patch बनाकर deploy करना हमेशा संभव नहीं होता। इसलिए जितनी जल्दी हो सके workaround लागू करना महत्वपूर्ण है। bug report के साथ व्यावहारिक विकल्प देना भी अच्छा तरीका है
  • केवल memory leak ठीक करने पर रुकने के बजाय, समस्या के root cause तक गहराई से जाने का पहलू भी अच्छा लगा। framework के आंतरिक code को ध्यान से देखकर मूल कारण तक पहुँचने वाली विश्लेषणात्मक दृष्टि डेवलपर के लिए आवश्यक लगती है
  • अंततः memory leak का कारण एक मामूली library version upgrade निकला, जो शुरुआत में पूरी तरह असंबंधित लगता था। यह dependency management और changes tracking के महत्व को दिखाने वाला उदाहरण है। छोटे बदलावों के प्रभाव का भी सावधानी से विश्लेषण करना और deploy के बाद monitoring करना ज़रूरी है

1 टिप्पणियां

 
GN⁺ 2024-05-12
Hacker News राय

मैनुअल मेमोरी मैनेजमेंट के डर के बिना, इसे इंजीनियरिंग ट्रेनिंग से हल किया जा सकता है

  • अगर सिर्फ RAII और स्पष्ट ownership नियम हों, तो मेमोरी मैनेजमेंट एक आसान इंजीनियरिंग काम है
  • उलटे, reference counting और shared pointers पर अड़े रहने वाले framework ownership को धुंधला बनाते हैं, जिससे यह और कठिन हो जाता है
  • बनाओ तो मुक्त करो, और transfer कर दो तो फिर उसकी चिंता मत करो — यह इंजीनियरिंग अनुशासन का हिस्सा है
  • मेमोरी bugs, logic bugs से अलग नहीं हैं, इसलिए उन्हें ठीक करना स्वाभाविक है
  • OS resources (handles, sockets आदि) भी automatic resource manager के बिना मैनुअली manage किए जाते हैं, इसलिए मेमोरी को भी उसी तरह संभाला जा सकता है

मेमोरी लीक की वजह से 50 लाख डॉलर के नुकसान का मामला

  • 90 के दशक के Solaris printer driver में मेमोरी लीक bug से जुड़ा एक किस्सा पेश किया गया
  • उस समय बैंक fax से trades की पुष्टि करते थे, फिर उन्हें printer से निकालकर दूसरी पार्टी को फोन पर पढ़कर सुनाते थे और रिकॉर्डिंग के जरिए कानूनी पुष्टि लेते थे
  • मेमोरी लीक की वजह से printer driver crash हो गया, पुष्टि-पत्र print नहीं हुआ, और trade cancel होने से 50 लाख डॉलर का नुकसान हुआ
  • आखिरकार Sun के CEO की शिकायत के बाद developers ने bug ठीक किया

मेमोरी लीक debugging tools और समाधान

  • Valgrind का उपयोग करने पर C में leaks आसानी से ढूंढे जा सकते हैं
  • अगर design सही हो, तो आमतौर पर allocation और deallocation एक ही function में होते हैं, इसलिए इसे ठीक करना आसान होता है
  • Yahoo ad server में मेमोरी लीक के एक मामले और एक अस्थायी workaround का परिचय दिया गया
  • PHP के designer के एक मजाकिया उद्धरण के जरिए यह दिखाया गया कि पूर्णतावाद से ज़्यादा व्यावहारिकता को चुना गया
  • Rails में productivity के लिए hardware से समस्या हल करना आम माना जाता है

लेखन शैली की प्रशंसा

  • एक टिप्पणी में कहा गया कि लेखक की लिखने की शैली, शायद emoticons या formatting की वजह से, पढ़ने में आनंददायक है