Rails RedisStore Cache 从 Rails 3.2.17 升级到 Rails 4.0.13 后,读取错误的问题

tesla_lee · 2015年07月07日 · 最后由 tesla_lee 回复于 2015年07月08日 · 2303 次阅读

打扰大家了,现在遇到了下面这个问题,不知道如何解决。

概要

在 Rails 3.2.17 中创建的 RedisCache 不能在 Rails 4.0.13 中正确读取

背景

根据 Rails 官方升级指导,将项目从 Rails3.2.17 升级到 Rails 4.0.13,Ruby 版本保持 2.0.0-p247 没有改变。

原来项目使用 RedisStore 做 Cache,在 Blog 代码中使用 Cache 如下

class Blog
  ...
  def self.hidden_ids
    hidden_ids = Rails.cache.fetch(["hidden_ids blog"], expires_in: 1.week) do 
      hidden_ids = Blog.where(hidden:true).pluck(:id)
      hidden_ids << 0 unless hidden_ids.include?(0)
    end
    hidden_ids
  end
  ...
end

以上代码会保存一个数组[1,2,3,4,5,6,7]保存到 Redis 中。 Redis 中的日志显示如下: "setex" "hidden_ids blog" "604800" "\x04\bo: ActiveSupport::Cache::Entry\t:\x10@compressedF:\x10@expires_inf\x0c6.048e5:\x10@created_atf\x161436236658.032523:\x0b@value\"6\x04\b[\x11i\x01\x88i\x02-\x01i\x02\x7f\x01i\x02\xa6\x03i\x02\xb8\x05i\x02\xb6\x06i\x02\xe1\x06i\x02\xe8\x06i\x02\xea\x06i\x02\xfa\x06i\x02\xfb\x06i\x00"

问题

在升级到 Rails 4.0.13 中之后,如果执行Blog.hidden_ids 结果变成了 "\x04\b[\x11i\x01\x88i\x02-\x01i\x02\x7F\x01i\x02\xA6\x03i\x02\xB8\x05i\x02\xB6\x06i\x02\xE1\x06i\x02\xE8\x06i\x02\xEA\x06i\x02\xFA\x06i\x02\xFB\x06i\x00" 而不是 Rails 3.2.17 版本中的 [136, 301, 383, 934, 1464, 1718, 1761, 1768, 1770, 1786, 1787, 0]

调查的结果

  • 在 Rails 3.2.17 版本中,ActiveSupport::Cache::Entry 代码的 line 561@value = Marshal.dump(value)
  • 而在 Rails 4.0.13 版本中,ActiveSupport::Cache::Entry 代码的line 581@value = value
  • 在 Rails 4.0.13 版本中,ActiveSupport::Cache::Entry 的line 666发现方法convert_version_4beta1_entry!,不知道是不是用来处理兼容的。
  • 在查看 3.2 到 4.0 的更新日志中,只是提到了 ActiveSupport::Cache::Entry 的优化,但是具体没有提修改了什么地方

疑问

  1. 是否升级后一定要清除 Cache?
  2. 如果不清楚,这个问题有没有办法解决?

貌似很有趣的问题,先 mark 一下,下班后晚上在看看有没有解。

我们的 Cache 使用了 Yaml 来做序列化,YAML 的序列化模式时比较标准的。而且我们的服务器部署了以后会清空 cache。

Rails.cache.clear

#3 楼 @hooooopo #2 楼 @gene_wu 是的,清除 Cache 以后一切正常。 那是不是每次部署之前,最好都清除 Cache?这么做的原因是?

升级了 redis-store,序列化方式变了,缓存中的数据不兼容,所以要清空缓存。每次部署如果不是有这样不兼容的更新就不用清空。

#4 楼 @tesla_lee 3-4 大版本升级,改实现了有什么奇怪的。

#6 楼 @hooooopo 不奇怪,主要时因为看到了下面这个方法,以为是可以兼容的,但没有找到使用方式。感谢回复 😄

# The internals of this method changed between Rails 3.x and 4.0. This method provides the glue
# to ensure that cache entries created under the old version still work with the new class definition.
def convert_version_4beta1_entry!
  if defined?(@v)
    @value = @v
    remove_instance_variable(:@v)
  end
  if defined?(@c)
    @compressed = @c
    remove_instance_variable(:@c)
  end
  if defined?(@x) && @x
    @created_at ||= Time.now.to_f
    @expires_in = @x - @created_at
    remove_instance_variable(:@x)
  end
end

#5 楼 @rei 😄 好的,谢谢,主要就是想确认是否不兼容,如果真的不兼容。就直接清 Cache。

#4 楼 @tesla_lee 一些 page cache 和局部 cache 会影响最终结果,model 反而一下就看的出来问题。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号