在优化项目响应时,想将 ActiveRecord 的结果集存在 Redis 的 HASH 中,主要是为了好管理。
比如用关联的 user_id 当做 HASH 的 key:
books = Book.where(user_id: user_id)
$redis.hset("books", user_id, books.to_json)
取出:
books = JSON.parse($redis.hset("books", user_id))
这样做的问题是取出时并不会还原成 ActiveRecord 结果集对象,而且数据量大的时候不知道会不会有性能问题。
但是使用Rails.cache.write
又不支持存进 Redis 的 HASH 中,请教一下有没有更好的方法解决这个问题?
有干这个的 gem https://github.com/hooopo/second_level_cache
不过带 where 条件的关联,用 slc 可能会导致关联没法正确过期,要留意一下或者你参照 slc 的思路自己弄一个
books = Rails.cache.fetch('cache_key', expires_in: 1.days) do
Book.where(user_id: user_id).to_a
end
你想要的是这个吗?
但是以上做法有弊端,当 book 更新时,缓存中的 books 的无法得到更新
本质就是要把 ActiveRecord 的结果集 marshalize 一下,如果要还原出来还是 ActiveRecord 的类的话。可以把 attributes 自己提出来,塞到 ActiveRecord 里,出来的时候还原一下。理论上,也可以调标准库里那个 marshalize,这个有可能杀鸡用牛刀了,看具体需要了。
slc 里核心需要用的就是 record_marshal 的代码,照着实现一个类似的就行。 https://github.com/hooopo/second_level_cache/blob/master/lib/second_level_cache/record_marshal.rb
谢谢回复,这个的只是在 redis 里存一个 key/value 键值,而不是在 Redis 的 HASH 里存键值。 我的问题是怎样方便地在 redis 的 hash 里存键值,并且取出来的时候能正常还原成 activerecord 对象。
为什么一定要用 hash? 如果只是想缓存的话,Rails.cache.fetch 应该没有问题 (现在的项目用的这个来缓存一些 master table)
https://redis.io/topics/memory-optimization hash 好像更节省内存,可以先比较下 hash 和 Rails.cache.fetch 的内存使用量在决定使用哪个
second_level_cache 那个 record_marshal.rb 也是每次 Rails 大版本升级最难搞的部分
需要深入分析新版本里面 Active Record 是如何实现的,还得回想之前版本的是如何实现的,所以这个文件写了很多注释