新手问题 关于将 ActiveRecord 结果集缓存到 Redis 的 HASH 中

wfwdex · October 25, 2017 · Last by hooopo replied at October 27, 2017 · 2755 hits

在优化项目响应时,想将 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 的思路自己弄一个

redis 也是远程调用,细粒度的缓存是否有用还要实测。

Reply to mizuhashi

谢谢,slc 似乎不能只指定某一个关联启用缓存,而是给 Model 的所有二级关联启用缓存了。

Reply to Rei

谢谢,目前 mysql 和 redis 是在同一台单独的服务器上,我测一下看看效果。

查阅 Rails.cache

Reply to wfwdex

所以说参考 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

Reply to breeze

谢谢回复,这个的只是在 redis 里存一个 key/value 键值,而不是在 Redis 的 HASH 里存键值。 我的问题是怎样方便地在 redis 的 hash 里存键值,并且取出来的时候能正常还原成 activerecord 对象。

Reply to dsh0416

多谢,这个似乎就是解决这个问题的切入点,我研究下。

建议用 PG 的 trigger 和扩展比如 https://github.com/pg-redis-fdw/redis_fdw 来管理缓存

Reply to nouse

这个看起来真不错,可惜我现在用的是 mysql,下次用试试,多谢。

Reply to wfwdex

为什么一定要用 hash? 如果只是想缓存的话,Rails.cache.fetch 应该没有问题 (现在的项目用的这个来缓存一些 master table)

https://redis.io/topics/memory-optimization hash 好像更节省内存,可以先比较下 hash 和 Rails.cache.fetch 的内存使用量在决定使用哪个

Reply to dsh0416

second_level_cache 那个 record_marshal.rb 也是每次 Rails 大版本升级最难搞的部分

需要深入分析新版本里面 Active Record 是如何实现的,还得回想之前版本的是如何实现的,所以这个文件写了很多注释

还有直接用 redis 做存储的, https://github.com/soveran/ohm

Reply to huacnlee

之前 Rails 有个 issue 说是给缓存插件提供一些 hook 接口,后来也没有下文了

You need to Sign in before reply, if you don't have an account, please Sign up first.