2013-05-25 5 views
7

मैंने हाल ही में डिफ़ॉल्ट I18n बैकएंड से अपने I18n के लिए रेडिस बैकएंड में स्विच किया है। मैंने ऐसा किया है ताकि अनुवादों को संभालने में हमारे लिए आसान हो, लेकिन मुझे पता चला है कि प्रत्येक पृष्ठ पर काफी प्रदर्शन हुआ था।रेल उत्पादन I18n के लिए रेडिस बहुत धीमी है?

मैंने अपने एमबीपी पर प्रदर्शित करने के लिए रेल 3.2 और रेडिस 2.6.4 के साथ कुछ बेंचमार्क चलाए हैं। मैं अपने क्लाइंट के रूप में hiredis-rb का उपयोग कर रहा हूं।

दो अलग-अलग बैकएंड का उपयोग करते समय यह एक बहुत स्पष्ट अंतर है। सरल बैकएंड के साथ वहाँ पहली कॉल पर एक संक्षिप्त देरी है - मुझे लगता है अनुवाद मेमोरी में लोड किया जा रहा है - उसके बाद और फिर शानदार प्रदर्शन:

pry(main)> Benchmark.realtime { 500.times { I18n.t 'shared.slogan' } } 
=> 0.143246 
pry(main)> Benchmark.realtime { 500.times { I18n.t 'shared.slogan' } } 
=> 0.00415 
pry(main)> Benchmark.realtime { 500.times { I18n.t 'shared.slogan' } } 
=> 0.004153 
pry(main)> Benchmark.realtime { 500.times { I18n.t 'shared.slogan' } } 
=> 0.004056 

Redis बैकएंड लगातार धीमी है:

pry(main)> Benchmark.realtime { 500.times { I18n.t 'shared.slogan' } } 
=> 0.122448 
pry(main)> Benchmark.realtime { 500.times { I18n.t 'shared.slogan' } } 
=> 0.263564 
pry(main)> Benchmark.realtime { 500.times { I18n.t 'shared.slogan' } } 
=> 0.232637 
pry(main)> Benchmark.realtime { 500.times { I18n.t 'shared.slogan' } } 
=> 0.122304 

यह मुझे पूर्ण समझ में आता है कि यह I18n के लिए धीमा क्यों है ... मैं अपने कोड बेस में दर्जनों I18n कॉलों को कतारबद्ध कर रहा हूं। अगर मैं बैच सकता है उन्हें एक साथ सामने मैं अच्छी हालत में हो जाएगा:

pry(main)> keys = $redis.keys[0..500] 
pry(main)> Benchmark.realtime { $redis.mget keys } 
=> 0.04264 

लेकिन मैं वास्तव में मौजूदा I18n बैकेंड से किसी के साथ ऐसा करने के लिए एक साफ रास्ता नहीं दिख रहा। क्या किसी ने इस समस्या का सामना किया है?

संपादित

मैं क्रिस Heald के सुझाव लिया और Memoization के साथ एक बैकेंड एक सरल कैश बस्ट बनाया। सार यहाँ है:

https://gist.github.com/wheeyls/5650947

मैं कुछ दिनों के लिए इस बाहर की कोशिश और फिर इसे एक मणि में बदल जाएगा।

अद्यतन

मेरे समाधान अब एक रत्न के रूप में उपलब्ध है:

https://github.com/wheeyls/cached_key_value_store

और मैं भी इस समस्या के बारे में ब्लॉग:

http://about.g2crowd.com/faster-i18nredis-on-rails/

+0

इन बेंचमार्क को चलाने वाले बॉक्स के संबंध में आपका रेडिस सर्वर कहां है? – deefour

+0

ये दौड़ मेरी स्थानीय मशीन पर हैं। मैं स्पष्ट करने के लिए अपना प्रश्न संपादित करूंगा। – Wheeyls

उत्तर

3

नेटवर्क ट्रैफ़िक हमेशा धीमी हो जाएगा स्थानीय काम से। आप इन-मेमोरी कैश पर विचार कर सकते हैं, और उसके बाद कैश को अमान्य करना है या नहीं, यह निर्धारित करने के लिए बस प्रत्येक अनुरोध (या यहां तक ​​कि केवल एक छोटे टाइमर पर) वर्तमान स्थानीयकरण संस्करण को खींचें। ऐसा लगता है कि एक ज्ञापन मॉड्यूल (प्रति the source here) है कि आप केवल I18n इंटरफ़ेस में मिश्रण कर सकते हैं। फिर, हम सिर्फ #lookup विधि को ट्वीक करते हैं ताकि प्रत्येक 5 मिनट में, यह एक अद्यतन लोकेल संस्करण के लिए रेडिस की जांच करता है, और यह सुनिश्चित करता है कि नए अनुवाद सहेजे जाने पर यह लोकेल संस्करण में वृद्धि करे।

यह आपको अपने सभी अनुवादों में एक मेमोरी कैश देता है, इसलिए यह एक बहुत तेज़ लुकअप है, जबकि आपको ऑन-द-फ्लाई में अनुवाद करने की क्षमता प्रदान करने के दौरान - आपके अनुवादों को अपडेट करने में 5 मिनट तक लग सकते हैं, लेकिन आपको कोई स्पष्ट कैश शुद्ध करने की ज़रूरत नहीं है।

यदि आप चाहते थे, तो आप आलसी 5-मिनट की समाप्ति का उपयोग करने के बजाय before_filter के साथ प्रत्येक अनुरोध पर चेक कर सकते हैं, जिसका अर्थ है लालसा के लिए अधिक अनुरोध, लेकिन आपको कोई पुराना अनुवाद नहीं दिखाई देगा।

module I18n 
    module Backend 
    class CachedKeyValueStore < KeyValue 
     include Memoize 

     def store_translations(locale, data, options = {}) 
     @store.incr "locale_version:#{locale}" 
     reset_memoizations!(locale) 
     super 
     end 

     def lookup(locale, key, scope = nil, options = {}) 
     ensure_freshness(locale) 
     flat_key = I18n::Backend::Flatten.normalize_flat_keys(locale, 
      key, scope, options[:separator]).to_sym 
     flat_hash = memoized_lookup[locale.to_sym] 
     flat_hash.key?(flat_key) ? flat_hash[flat_key] : (flat_hash[flat_key] = super) 
     end 

     def ensure_freshness(locale) 
     @last_check ||= 0 

     if @last_check < 5.minutes.ago 
      @last_check = Time.now 
      current_version = @store.get "locale_version:#{locale}" 
      if @last_version != current_version 
      reset_memoizations! locale 
      @last_version = current_version 
      end 
     end 
     end 
    end 
    end 
end 

मैं सिर्फ इस I18n स्रोत पढ़ने से हैक की गई है, और मैं तो यह कुछ काम की आवश्यकता है, सब पर यह परीक्षण नहीं किया, लेकिन मैं इसे विचार काफी अच्छी तरह से संचार में सोचते हैं।

+0

निफ्टी। यह मूल रूप से मेरे मन में समाधान था, केवल बेहतर है। मुझे आश्चर्य है कि ऐसा कोई और क्यों नहीं रहा है? – Wheeyls

+0

गिस्ट यहां है: https://gist.github.com/wheeyls/5650947 – Wheeyls

+0

अच्छा। मैं इसे यॉइंक करने जा रहा हूं और इसे अपने उपयोग में बाद के ढेर में चिपका रहा हूं। :) –

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