请问大家做数据库层的缓存,都用什么 Gem? 有什么好建议吗,谢谢。
搜索了一些资料,不知道大家常用的,以及使用的过程中有没有遇到什么比较坑的事情。
1) dalli https://www.digitalocean.com/community/articles/how-to-use-memcached-with-ruby-on-rails-on-ubuntu-12-04-lts https://github.com/mperham/dalli/
2) cache method https://github.com/seamusabshere/cache_method
3) find cache https://github.com/mustafaturan/find_cache
4) second_level_cache (csdn) https://github.com/csdn-dev/second_level_cache https://github.com/hooopo/second_level_cache (支持 Rails 4)
要给出场景才知道要用什么缓存机制啊。
如果是缓存一个查询
def something_need_to_cache
Rails.cache.fetch('some_key') do
where(CONDITIONS).to_a
end
end
#3 楼 @ihlayy 没场景讨论不了。应该先把这里看一次 http://guides.rubyonrails.org/caching_with_rails.html
#4 楼 @Rei #6 楼 @zhangjinzhu 想问一下,如果我是两种语言混用的项目,前台用 Rails 后台用 Java, 如何共享缓存,或者怎么使用 memcached.
假设有 Customer 对象在 Rails,Java 中都被缓存了,如果是从 Rails 程序更新了 Customer 对象和缓存,怎么使 Java 缓存失效?
没看到有现成的库两边的 Key 和保存的 Json 都能通用的呢?
一般几个思路?
用 identity_cache + Rails.cache 应该够了,对于基本的查询(如使用主键,或者使用固定字段等)直接使用 identity_cache,如
User.fetch(1)
Chart.fetch_file_name_by_uuid(uuid)
对于 identity_cache 不能处理的,或者想单独缓存的,可以使用 Rails.cache 包下,如 @Rei 上面说得。
@ihlayy 不要尝试写回调让缓存失效,只要改变缓存的 key 即可。逻辑挺简单的,也就是几十行代码的事情。 https://github.com/qor/qor_cache/blob/master/lib/qor_cache/active_record.rb
#9 楼 @zhangjinzhu 我有很多是类方法,比如 Customer.find_by_email , 这个时候缓存的 Key 是 customer_{#email} => 对应 customer id
比如登录这个场景,这个时候不是一个对象的实例方法,没有 model 的 updatedAt 这个时间戳的
参考这 18 行代码: https://github.com/qor/qor_cache/blob/master/lib/qor_cache/active_record.rb#L15-L33
以及这两行 https://github.com/qor/qor_cache/blob/master/lib/qor_cache/active_record.rb#L7-L8
你的类会维护一个类级别的 cache key,如果这个类有更新的话,就会改变这个类的 cache key,你所要做的就是在你的类方法上用这些类级别的 cache key 就好了...
#12 楼 @zhangjinzhu 你这个是类名 + 方法名 + 随机数,如果我只有 rails 的 app 还行,但是我要在 Java 那边和这个 Key 对起来更麻烦了。我想的是 Java 和 Rails 生成的缓存的 Key 的规则是一致的,就是我 Java 的 lib 可以使用 Rails 程序保存的 memcached 的对象,这样的好处是,内存节约了,更新在一个端更新另外一端使用就行了。
不然的话我就需要处理如果 Rails 这边更新了数据库,Java 那边的缓存怎么办的问题。
@ihlayy 你就压根不需要管 cache key 是什么组成的,你只要知道他是一个随机数就好了!java 那边难道不能做成一个随机数存到 memcache 里?。。。
#14 楼 @zhangjinzhu 如果同一个数据库里的同一个 customer(Id;1),你有 rails 程序和 Java 程序,你在 memcached 里面保存几份 customer 对象?
我怀疑多个 Rails 程序集群的时候也可能会有问题。
如果 customer 对象在数据库里被更新了,你怎么保证 Rails 程序和 Java 程序读到的是最新的 Customer 数据?
因为可能是通过 Rails 程序更新的数据库而 Java 程序根本就不知道这个 Customer 被更新了
@ihlayy 给你举个例子,对于 customer 这个类来说 rails, java 要有一个同享的 cache key(例如名字叫:customer_cache_key, 这个 key 是用来存到 memcache 中的),这个 cache key 的值是一个随机值。
如果 rails 中 customer 变了的话,就更新 customer_cache_key 的值变成另一个随机值,如果 java 中 customer 变了的话,就更新 customer_cache_key 的值为另一个随机值。
这样子你取的时候,只需要根据 customer_cache_key 的值来读缓存,如果不存在缓存就写数据库就可以了
问题是你怎么处理这个同享的 cache key?
假设 login_by_email 方法,你两边怎么产生这个一致的 Key?
rails cache_key(123456) -> customer1 java cache_key(123456) -> customer1
rails 中 customer 变了 (你的思路是变 key 这个没错,不清除缓存) rails cache_key(56789) -> customer1_change java cache_key(123456) -> customer1
这个时候 java 得使用 cache_key(56789)?我怎么知道这个新的 key(56789)?
@ihlayy 我的描述能力有这么差么?。。。。
再以你的例子举个例子:
getCacheKeyFromMemcache() -> 123456
rails cache_key(getCacheKeyFromMemcache()) -> customer1
java cache_key(getCacheKeyFromMemcache()) -> customer1
如果 rails 中 customer 变了:
getCacheKeyFromMemcache() -> 56789
rails cache_key(getCacheKeyFromMemcache()) -> customer1_change
java cache_key(getCacheKeyFromMemcache()) -> customer1_change
浅显易懂了么?
#18 楼 @zhangjinzhu 我知道你这个意思。我怀疑是我表述的太不清楚了?
我刚问的意思就是 getCacheKeyFromMemcache() 你这个方法你准备怎么写。
你想想具体实现会很容易么?
你是想告诉我 cacheKey 对应类名,方法名存在 memcache 里面?这得查询多少次,感觉不太划算吧。。。?
@ihlayy 其实挺简单的,只是读两次 memcache 而已,第一次读 cache key,第二次读真正的缓存值。
这个带来的好处就是,你不需要维护缓存的数据 (不用清缓存) (这个的复杂度通常来说是很高的。。。特别在还有关联表的情况下)。。。。你看看和你上面的解决方案来比较,这个解决方案轻量级多了。。。
一般几个思路?
1. Rails,Java通用的类库
2. 各自独立,更新的时候通过队列,或者Rest api通知另一端更新
3. 数据统一从一个地方取,一个数据层?(这种效率就不清楚了)
#21 楼 @zhangjinzhu 我刚装了下 qor_cache,看了下源码,确实是读了两次 memcache 换来了不用清除缓存。
我想下吧。没在真实的产品环境实验过,读两次代价也挺高的,毕竟不是单机进程内读数据。 调用 memcache 是有网络开销的。你要一个方法内有 4 次调用数据库,无形中就可能多了 4 次的 memcache 调用。
谢谢啊。这么有耐心的回答。。
我想下吧。没在真实的产品环境实验过,读两次代价也挺高的,毕竟不是单机进程内读数据。 调用 memcache 是有网络开销的。你要一个方法内有 4 次调用数据库,无形中就可能多了 4 次的 memcache 调用
https://github.com/mperham/dalli 这种库一般都是维持一个长连接的,所以可以忽略网络开销。。。