2013-05-25 19 views
7

Kısa bir süre önce varsayılan Basit I18n arka ucundan I18n için bir Redis arka ucuna geçiyorum. Bunu yaptığım için çevirileri halletmemizi kolaylaştırdım, ancak her sayfada önemli bir performans artışı olduğunu gördüm.Rails üretimi I18n için Redis çok yavaş mı?

Göstermek için MBP'mde bazı Yükseltmeler 3.2 ve Redis 2.6.4 yüklü bazı Karşılaştırmalar çalıştırıyorum. Müşterim olarak hiredis-rb kullanıyorum.

İki farklı arka uçu kullanırken oldukça net bir fark var. Basit arka uç ile ilk görüşme kısa bir gecikme var - Ben çeviriler belleğe yüklenirken varsayalım - bundan sonra ve daha sonra büyük bir performans:

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 arka uç sürekli yavaş:

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 

Bu, I18n için neden yavaş olduğunu anlamamıza neden oluyor ... Kod tabanım boyunca düzinelerce I18n çağrılarını sıraya alıyorum. Onları bir araya ön Ben iyi durumda olurdu ben toplu Yapabilseydim:

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

Ama gerçekten varolan I18n backends herhangi biriyle bunun için temiz bir yol görmüyorum. Bu problemi çözen var mı?

DÜZENLEME Chris Heald önerisini aldı ve memoization bir arka uç basit önbellek büst yarattı. özü işte burada:

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

Birkaç gündür bu denersiniz ve daha sonra bir mücevher çevirmek.

GÜNCELLEME

Çözümümün artık mücevher olarak mevcuttur:

https://github.com/wheeyls/cached_key_value_store

Ve ayrıca bu sorun hakkında blogged:

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

+0

Redis sunucunuz bu karşılaştırıcıları çalıştıran kutuyla ilişkili olarak nerede? – deefour

+0

Bunlar çalıştırıldı yerel makinemde. Sorunu açıklığa kavuşturmak için düzenleyeceğim. – Wheeyls

cevap

3

Ağ trafiği her zaman daha yavaş olacaktır yerel işlerden daha Bir bellek içi önbellek düşünebilirsiniz ve sonra önbelleği geçersiz kılıp kılmadığını belirlemek için her yerel istek (yalnızca kısa bir zamanlayıcıda) geçerli yerelleştirme sürümünü çekebilirsiniz. Sadece bir I18n arabirimine karıştırabileceğiniz bir Notlandırma modülü (the source here'a göre) var gibi görünüyor. Ardından, #lookup yöntemini, her 5 dakikada bir, güncellenen bir yerel sürüm sürümü için Redis'i denetler ve yeni çeviriler kaydedildiğinde yerel sürümün artırılmasını sağlar.

Bu, tüm çevirilerinizin bellek içi bir önbelleğini verir, böylece çok hızlı bir arama yapar ve çeviri sırasında anında değişiklik yapma olanağı verir; çevirilerinizin güncellenmesi 5 dakika kadar sürebilir, ancak Herhangi bir açık önbellek temizleme yapmak zorunda değilsiniz.

İsterseniz, sadece 5 dakikalık son kullanma süresinin kısaltılması yerine before_filter numaralı telefonu kullanarak her isteği kontrol edebilirsiniz.

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 

Sadece I18n kaynağını okumaktan bu kadar saldırıya uğramış ve bazı işler gerekebilir yüzden, hiç denenmedi, ama yeterince iyi bir fikir iletişim kurar düşünüyorum.

+0

Nifty. Bu temelde aklımda olan çözüm, sadece daha iyi. Merak ediyorum neden başka kimse bununla ilgilenmedi? – Wheeyls

+0

Gist burada: https://gist.github.com/wheeyls/5650947 – Wheeyls

+0

Güzel. Bunu daha sonra kullanacağım ve daha sonra kullanacağım kazıma yapıştıracağım. :) –