Whe*_*yls 11 ruby-on-rails internationalization redis
我最近从默认的Simple I18n后端切换到我的I18n的Redis后端.我这样做是为了让我们更容易处理翻译,但我发现每个页面都有很大的性能影响.
我在我的MBP上安装了Rails 3.2和Redis 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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
对我来说绝对有意义,为什么I18n的速度很慢...我在整个代码库中排队了几十个I18n.如果我可以在前面将它们一起批量处理,我会保持良好状态:
pry(main)> keys = $redis.keys[0..500]
pry(main)> Benchmark.realtime { $redis.mget keys }
=> 0.04264
Run Code Online (Sandbox Code Playgroud)
但我真的没有看到任何现有I18n后端的干净方法.有没有人解决这个问题?
我采用了Chris Heald的建议并创建了一个后备文件,其中包含一个简单的缓存区域.要点在这里:
https://gist.github.com/wheeyls/5650947
我会试试这几天,然后把它变成一颗宝石.
我的解决方案现在可用作宝石:
https://github.com/wheeyls/cached_key_value_store
我还在博客上写了这个问题:
网络流量总是比本地工作慢.您可以考虑使用内存缓存,然后在每个请求(或者甚至只是在短计时器上)上拉当前的本地化版本,以确定是否使缓存无效.它看起来像是一个Memoization模块(根据这里的来源),你可以混合到一个I18n接口.然后,我们只调整#lookup方法,以便每5分钟检查一次Redis以获取更新的语言环境版本,并确保在保存新翻译时增加语言环境版本.
这为您提供了所有翻译的内存缓存,因此它是一个非常快速的查找,同时使您能够即时更改翻译 - 您的翻译可能需要5分钟才能更新,但您不需要必须进行任何显式的缓存清除.
如果你愿意,你可以让它before_filter使用一个懒惰的5分钟到期来检查每个请求,这意味着更多的redis请求,但你不会看到任何陈旧的翻译.
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
Run Code Online (Sandbox Code Playgroud)
我刚从阅读I18n源代码中解决了这个问题,而我根本没有测试它,所以它可能需要一些工作,但我认为它足够好地传达了这个想法.
| 归档时间: |
|
| 查看次数: |
2509 次 |
| 最近记录: |