Jbuilder Rails 缓存较慢

Jbuilder Rails caching is slower

我尝试过对集合使用缓存(有多种解决方案),问题是每当我尝试缓存时,响应都会变慢 考虑以下集合示例,它为其中的每个项目(大约 25 个项目)呈现 2 个部分

json.data do
  json.array! @organizations do |organization|
    json.partial! 'api/v1/organizations/organization', organization: organization
    json.partial! 'api/v1/organizations/links', organization: organization
  end
end

没有缓存的平均响应时间约为 38 毫秒(平均)

现在有缓存

json.data do
  json.array! @organizations do |organization|
    json.cache! organization do
      json.partial! 'api/v1/organizations/organization', organization: organization
      json.partial! 'api/v1/organizations/links', organization: organization
    end
  end
end

正确安装和配置了 jbuilder 默认缓存和 dalli 存储(我可以验证没有缓存未命中)

平均响应约为 59 毫秒(平均)

使用 Cache Digest

中的语法
json.data do
  json.cache! @organizations do
    json.partial! 'api/v1/organizations/organization', collection: @organizations, as: :organization
    json.partial! 'api/v1/organizations/links', collection: @organizations, as: :organization
  end
end

平均响应时间约为 41 毫秒(平均),并且响应与其他响应不同

# Instead of getting
[{ data:{}, links:{} }, {{ data:{}, links:{} }]
# I get
[{ data:{}, data:{}, links:{}, links:{} }]

但是文件的缓存摘要是一个非常大的字符串,很容易超过 unix 最大文件名长度。 例如,这是文件名。

Cache write: jbuilder/organizations/5509f9284162643526000000-20150322012449497000000/organizations/5509e5924162643056020000-20150320223230684000000/organizations/550b54d8416264add2040000-20150321004501311000000/organizations/550e35704162640a98030000-20150322032224768000000/organizations/550e357b4162640a98050000-20150322032235260000000/organizations/550e35834162640a98080000-20150322032243162000000/organizations/550e35894162640a980a0000-20150322032249767000000/organizations/550e35904162640a980c0000-20150322032256464000000/organizations/550e35944162640a980e0000-20150322032300519000000/organizations/550e35984162640a98100000-20150322032304428000000/organizations/550e359c4162640a98120000-20150322032308542000000/organizations/550e35a04162640a98140000-20150322032312514000000/organizations/550e35a54162640a98160000-20150322032317066000000/organizations/550e35a84162640a98180000-20150322032320850000000/organizations/550e35ac4162640a981a0000-20150322032324716000000/organizations/550e35b04162640a981c0000-20150322032328643000000/organizations/550e35b54162640a981e0000-20150322032333651000000/organizations/550e35ba4162640a98200000-20150322032338114000000/organizations/550e35bd4162640a98220000-20150322032341889000000/organizations/550e35c14162640a98240000-20150322032345602000000/organizations/550e35c54162640a98260000-20150322032349739000000/3fcda1f9c320ab4284da56b4b2337cf5`

我也累了Jbuilder Cache Multi

json.data do
  json.cache_collection! @organizations do |organization|
    json.partial! 'api/v1/organizations/organization', organization: organization
    json.partial! 'api/v1/organizations/links', organization: organization
  end
end

响应时间约为 57 毫秒(平均)

加上 jbuilder 缓存和 multi,我在日志中得到了很多这样的东西

  Cache digest for app/views/api/v1/organizations/index.json.jbuilder: 3a51096b9c8da6a2cdb5b5a33ee58ea4
  Cache digest for app/views/api/v1/organizations/_organization.json.jbuilder: 4a1f1d49c90fdd867d88701f8a3fd6e1
  Cache digest for app/views/api/v1/organizations/_links.json.jbuilder: f2a881e125f95421d566edd571fdec73
  Cache digest for app/views/api/v1/organizations/index.json.jbuilder: 3a51096b9c8da6a2cdb5b5a33ee58ea4
  Cache digest for app/views/api/v1/organizations/_organization.json.jbuilder: 4a1f1d49c90fdd867d88701f8a3fd6e1
  Cache digest for app/views/api/v1/organizations/_links.json.jbuilder: f2a881e125f95421d566edd571fdec73
  Cache digest for app/views/api/v1/organizations/index.json.jbuilder: 3a51096b9c8da6a2cdb5b5a33ee58ea4
  Cache digest for app/views/api/v1/organizations/_organization.json.jbuilder: 4a1f1d49c90fdd867d88701f8a3fd6e1

所以我的实现或机器或本地环境有问题吗? Rails 4.2.0 和 Jbuilder 2.2.11

I also posted this issue to jbuilder #259

作为这个答案的时间......这就是 jbuilder 的工作方式......正如我可以引用 github issue

@vincentwoo

The issue is that jbuilder caching is fairly naive - it basically dumps a serialized version of a giant activerecord blob into the cache store, then pulls it out, deserializes it, and then EVENTUALLY serializes THAT to JSON.

In the future, jbuilder will hopefully act directly on strings, but until then, I think jbuilder caching is best not used russian-doll style.

和@rwz(合作者之一)

Currently caching provides benefits only when it allows to skip some of AR queries or you're using really computionally heavy view helpers.

When you already have the records fetched and only perform basic extractions, caching only slows things down.

为了详细说明我的报价,截至目前(JBuilder 的 v2.2.12),只有在以下一项或两项为真时,在 JBuilder 中缓存部分才真正值得:

  • 您可以跳过平均 比访问缓存

    更昂贵的 AR 查询(或计算)

    访问缓存通常是在通常的 Rails 堆栈中进行的网络调用,虽然数据库查询 可能 很昂贵,但通过网络访问的成本获取序列化的 ActiveSupport blob,然后反序列化为 Ruby 中的散列非常昂贵,必须在 Ruby VM 中完成。这对性能不利。

  • 生成的 JSON blob 的大小很小

    作为必然结果,如果您有一个小查询,但产生大量 JSON,您将很快遇到性能下降,因为该 blob 从 ActiveSupport blob 反序列化,然后再次退出原始 JSON。请记住,缓存不存储原始JSON,而是序列化的中间格式。这意味着,对于 JSON 存储在缓存中的每个额外字节,您将通过线路(来自序列化的 AS 表示)增加大约 4 个字节,并且可能花费与反序列化所花费的时间一样长的时间无论如何只计算部分。

如果您有一个生成巨大 JSON blob 的端点,我的建议是手动有条件地在控制器中渲染 blob 并将其作为原始字符串缓存在 Rails.cache 中。时不时地重新计算所有 JSON 的成本可能比每次调用都通过 JBuilder 的缓存机制要少。