2010-08-18 23 views
8

मैं कुछ पृष्ठभूमि विश्लेषण चलाने के लिए देरी वाली नौकरी का उपयोग करने की योजना बना रहा हूं। मेरे प्रारंभिक परीक्षण में मैंने मेमोरी उपयोग की जबरदस्त मात्रा देखी, इसलिए मैंने मूल रूप से एक बहुत ही सरल कार्य बनाया जो हर 2 मिनट में चलता है यह देखने के लिए कि कितनी मेमोरी का उपयोग किया जा रहा है।रेल मेमोरी उच्च मेमोरी उपयोग

कार्य बहुत आसान है और analytics_eligbile? विधि हमेशा झूठी वापसी करती है, जहां डेटा अब है, इसलिए मूल रूप से भारी मारने वाले कोड में से कोई भी नहीं कहा जा रहा है। मेरे विकास में मेरे नमूना डेटा में लगभग 200 पद हैं। पोस्ट has_one analytics_facet है।

यहां तक ​​कि आंतरिक तर्क/व्यवसाय के बावजूद, यह कार्य केवल एक ही चीज है जो analytics_exiable को कॉल कर रहा है? विधि हर 2 मिनट 200 बार। 4 घंटों के मामले में मेरा भौतिक स्मृति उपयोग 110 एमबी और वर्चुअल मेमोरी 200 एमबी पर है। बस कुछ आसान करने के लिए! मैं यह भी कल्पना नहीं कर सकता कि यह वास्तविक उत्पादन डेटा के साथ 10,000 पदों पर वास्तविक विश्लेषण करने पर कितनी मेमोरी खाएगी !! यह माना जाता है कि यह हर 2 मिनट की तरह नहीं चल सकता है, फिर भी मुझे नहीं लगता कि यह उड़ जाएगा।

यह रूबी 1.9.7 चल रहा है, उबंटू 10.x 64 बिट पर रेल 2.3.5। मेरे लैपटॉप में 4 जीबी मेमोरी, डुअल कोर सीपीयू है।

क्या रेल वास्तव में यह बुरा है या क्या मैं कुछ गलत कर रहा हूं?

Delayed::Worker.logger.info('RAM USAGE Job Start: ' + `pmap #{Process.pid} | tail -1`[10,40].strip) 
Post.not_expired.each do |p| 
    if p.analytics_eligible? 
     #this method is never called 
     Post.find_for_analytics_update(p.id).update_analytics 
    end 
end 
Delayed::Worker.logger.info('RAM USAGE Job End: ' + `pmap #{Process.pid} | tail -1`[10,40].strip) 

Delayed::Job.enqueue PeriodicAnalyticsJob.new(), 0, 2.minutes.from_now 

पोस्ट मॉडल

def analytics_eligible? 
     vf = self.analytics_facet 
     if self.total_ratings > 0 && vf.nil? 
      return true 
     elsif !vf.nil? && vf.last_update_tv > 0 
      ratio = self.total_ratings/vf.last_update_tv 
      if (ratio - 1) >= Constants::FACET_UPDATE_ELIGIBILITY_DELTA 
       return true 
      end 
     end 
     return false 
    end 

उत्तर

18

ActiveRecord काफी स्मृति-भूख लगी है - चयन करते समय बहुत सावधान रहें, और ध्यान रखें कि रुबी स्वचालित रूप से ब्लॉक में अंतिम विवरण को रिटर्न वैल्यू के रूप में लौटाता है, संभावित रूप से इसका अर्थ है कि आप रिकॉर्ड्स की एक सरणी वापस ले रहे हैं परिणामस्वरूप कहीं से बचाया गया और इस प्रकार जीसी के लिए योग्य नहीं है।

इसके अतिरिक्त, जब आप "Post.not_expired.each" को कॉल करते हैं, तो आप सभी लोड नहीं कर रहे हैं। एक बेहतर समाधान find_in_batches है, जो विशेष रूप से केवल एक ही समय में एक्स रिकॉर्ड को रैम में लोड करता है।

फिक्सिंग के रूप में यह रूप में सरल कुछ हो सकता है:

def do_analytics 
    Post.not_expired.find_in_batches(:batch_size => 100) do |batch| 
    batch.each do |post| 
     if post.analytics_eligible? 
     #this method is never called 
     Post.find_for_analytics_update(post.id).update_analytics 
     end 
    end 
    end 
    GC.start 
end 

do_analytics 

कुछ बातें यहाँ हो रही हैं। सबसे पहले, पूरी चीज को फ़ंक्शन में स्कॉप्ड किया जाता है ताकि वेरिएबल टकराव को ब्लॉक इटरेटर्स से संदर्भों पर रोक दिया जा सके। इसके बाद, find_in_batches एक समय में डीबी से batch_size ऑब्जेक्ट्स पुनर्प्राप्त करता है, और जब तक आप उनके संदर्भ नहीं बना रहे हैं, प्रत्येक पुनरावृत्ति चलाने के बाद कचरा संग्रहण के लिए योग्य बनें, जो कुल मेमोरी उपयोग को कम रखेगा। अंत में, हम विधि के अंत में GC.start पर कॉल करते हैं; यह जीसी को एक स्वीप शुरू करने के लिए मजबूर करता है (जिसे आप रीयलटाइम ऐप में नहीं करना चाहते हैं, लेकिन चूंकि यह पृष्ठभूमि की नौकरी है, तो यह ठीक है अगर इसे चलाने के लिए अतिरिक्त 300ms लगते हैं)। nil लौटने पर इसका बहुत ही विशिष्ट लाभ होता है, जिसका अर्थ है कि विधि का परिणाम nil है, जिसका अर्थ है कि हम खोजकर्ता से लौटाए गए एआर उदाहरणों पर गलती से लटका नहीं सकते हैं।

इस तरह कुछ उपयोग करने से यह सुनिश्चित करना चाहिए कि आप लीक एआर ऑब्जेक्ट्स के साथ समाप्त न हों, और प्रदर्शन और स्मृति उपयोग दोनों में काफी सुधार करना चाहिए। आप यह सुनिश्चित करना चाहते हैं कि आप अपने ऐप में कहीं और नहीं लीक कर रहे हैं (कक्षा चर, ग्लोबल्स, और कक्षा संदर्भ सबसे खराब अपराधी हैं), लेकिन मुझे संदेह है कि इससे आपकी समस्या हल हो जाएगी।

सभी ने कहा, यह मेरी राय में डीजे समस्या के बजाय एक क्रॉन समस्या (आवधिक आवर्ती कार्य) है। आपके पास एक-शॉट एनालिटिक्स पार्सर हो सकता है जो प्रत्येक एक्स मिनट को script/runner के साथ चलाता है, जो क्रॉन द्वारा आक्रमण किया जाता है, जो कि किसी भी संभावित मेमोरी लीक या प्रति-दुरुपयोग को अच्छी तरह से साफ करता है (क्योंकि पूरी प्रक्रिया अंत में समाप्त हो जाती है)

+0

एकमात्र चीज जो मैं इस उत्कृष्ट उत्तर में जोड़ूंगा वह एक नोट है कि किसी भी रेल प्रक्रिया में काफी मेमोरी का उपभोग होगा - आपका 110 एमबी असामान्य नहीं है। यह आपके कोड में मेमोरी लीक का संकेत नहीं है, या आपने कितनी प्रोसेसिंग की है। प्रसंस्करण 1000 रिकॉर्ड या 10 एम रिकॉर्ड मेमोरी की एक ही मात्रा का उपयोग करेंगे यदि आपने चीजें ठीक से की हैं (जिस तरह क्रिस ने समझाया है)। – wuputah

0

यह एक तथ्य यह है कि रूबी की खपत (और लीक) स्मृति है। मुझे नहीं पता कि आप इसके बारे में बहुत कुछ कर सकते हैं, लेकिन कम से कम मैं अनुशंसा करता हूं कि आप Ruby Enterprise Edition पर एक नज़र डालें।

आरईई एक ओपन सोर्स पोर्ट है जो अन्य सभी अच्छी चीजों के बीच "33% कम स्मृति" का वादा करता है। मैंने लगभग दो वर्षों से यात्री में उत्पादन के साथ आरईई का उपयोग किया है और मैं बहुत खुश हूं।

+0

ठीक है, मुझे अब तक आरओआर के बारे में कुछ चीजें हैं, लेकिन यदि यह बुरा है, तो यह वास्तव में गायब हो जाता है। मैं अब आरईई की कोशिश कर रहा हूं, धन्यवाद! – badnaam

+0

आरईई का "33% कम स्मृति उपयोग" का वादा रेल फ्रेम ढांचे को लोड होने के बाद प्रक्रिया के कारण है। एक प्रक्रिया में, इसका कोई महत्वपूर्ण प्रभाव नहीं पड़ेगा। –

1

यदि आप स्मृति समस्याओं का सामना कर रहे हैं, तो एक समाधान अन्य पृष्ठभूमि प्रसंस्करण तकनीक का उपयोग करना है, जैसे resque। यह बीजी प्रसंस्करण github द्वारा उपयोग किया जाता है।

Resque के माता पिता/बच्चे वास्तुकला के लिए धन्यवाद, नौकरियों कि पूरा होने पर बहुत ज्यादा स्मृति रिलीज कि स्मृति का उपयोग करें। कोई अवांछित वृद्धि

कैसे?

कुछ प्लेटफार्मों पर, जब एक Resque कर्मी ने कार्य इसे तुरंत कांटे एक बच्चे की प्रक्रिया सुरक्षित रखता है। बच्चा नौकरी को संसाधित करता है तो बाहर निकलता है। जब बच्चा सफलतापूर्वक बाहर निकल गया है, कर्मचारी एक और नौकरी सुरक्षित रखता है और प्रक्रिया को दोहराता है।

आप रीडमे में अधिक तकनीकी विवरण प्राप्त कर सकते हैं।

+0

धन्यवाद। यह माता-पिता/बाल वास्तुकला किस प्लेटफॉर्म पर काम करता है? – badnaam

+0

मुझे पता है कि यह लिनक्स और ओएस एक्स पर काम करता है। संभवतः यह विंडोज पर काम नहीं करता है? – wuputah

6

बैच में डेटा लोड करना और कचरा कलेक्टर का आक्रामक रूप से उपयोग करना क्योंकि क्रिस हेल्ड ने आपको कुछ वास्तव में बड़े लाभ देने जा रहे हैं, लेकिन एक और क्षेत्र लोग अक्सर अनदेखा करते हैं कि वे किस ढांचे में लोड हो रहे हैं।

डिफ़ॉल्ट रेल स्टैक लोड करना आपको एक्शनकंट्रोलर, एक्शनमेलर, एक्टिव रिकार्ड और एक्टिव रिसोर्स को एक साथ मिल जाएगा। यदि आप एक वेब एप्लिकेशन बना रहे हैं तो आप इन सभी का उपयोग नहीं कर रहे हैं, लेकिन आप शायद अधिकतर उपयोग कर रहे हैं।

आप एक पृष्ठभूमि काम का निर्माण कर रहे हैं, तो आप लोड हो रहा है बातें आपको लगता है कि के लिए एक कस्टम वातावरण बनाने के द्वारा की जरूरत नहीं है बच सकते हैं:

# config/environments/production_bg.rb 

config.frameworks -= [ :action_controller, :active_resource, :action_mailer ] 

# (Also include config directives from production.rb that apply) 

इन चौखटे से प्रत्येक सिर्फ एक के लिए इंतज़ार कर चारों ओर बैठे हो जाएगा ईमेल जो कभी नहीं भेजा जाएगा, या एक नियंत्रक जिसे कभी नहीं कहा जाएगा। उन्हें लोड करने में बस कोई बात नहीं है। database.yml फ़ाइल को समायोजित करें, production_bg वातावरण में चलाने के लिए अपनी पृष्ठभूमि नौकरी सेट करें, और आपके पास शुरुआत करने के लिए एक बहुत क्लीनर स्लेट होगा।

एक और चीज जो आप कर सकते हैं वह सीधे रेल लोड किए बिना ActiveRecord का उपयोग करती है। यह सब कुछ हो सकता है जो आपको इस विशेष ऑपरेशन के लिए चाहिए। मैंने Sequel जैसे हल्के वजन वाले ओआरएम का उपयोग भी पाया है, यदि आप अधिकतर एसक्यूएल कॉल रिकॉर्ड को पुनर्गठित करने या पुराने डेटा को हटाने के लिए करते हैं तो आपकी पृष्ठभूमि नौकरी बहुत हल्की होती है। यदि आपको अपने मॉडल और उनके तरीकों तक पहुंच की आवश्यकता है, तो आपको ActiveRecord का उपयोग करने की आवश्यकता होगी। कभी-कभी प्रदर्शन और दक्षता के कारणों के लिए शुद्ध एसक्यूएल में सरल तर्क को फिर से कार्यान्वित करने लायक है।

स्मृति उपयोग को मापते समय, "असली" स्मृति से संबंधित होने वाली एकमात्र संख्या है।आभासी राशि में साझा पुस्तकालय शामिल हैं और इनकी लागत प्रत्येक प्रक्रिया के बीच फैली हुई है, भले ही इसे प्रत्येक के लिए पूर्ण रूप से गिना जाता है।

अंत में, यदि कुछ महत्वपूर्ण चलाना 100 एमबी मेमोरी लेता है लेकिन आप इसे तीन सप्ताह के काम के साथ 10 एमबी तक ले जा सकते हैं, तो मुझे नहीं लगता कि आप परेशान क्यों होंगे। 9 0 एमबी मेमोरी लागत एक प्रबंधित प्रदाता पर लगभग $ 60/वर्ष पर होती है जो आमतौर पर आपके समय की तुलना में बहुत कम महंगी होती है।

रेल पर रूबी आपकी उत्पादकता और स्मृति के उपयोग के मुकाबले आपके समय से अधिक चिंतित होने के दर्शन को गले लगाती है। यदि आप इसे वापस ट्रिम करना चाहते हैं, तो इसे आहार पर रखें, आप इसे कर सकते हैं लेकिन इसमें थोड़ा सा प्रयास होगा।

+0

अच्छे अंक! आपका बहुत बहुत धन्यवाद! – badnaam

संबंधित मुद्दे