如何缓存rails api控制器

Posted

技术标签:

【中文标题】如何缓存rails api控制器【英文标题】:How to cache a rails api controller 【发布时间】:2020-09-10 05:44:16 【问题描述】:

我在我的应用程序中发现了一些性能问题,我想知道我的缓存是否工作正常,或者我是否误解/错误配置了任何内容。我使用fast-jsonapi 进行序列化,它带有内置缓存选项。

假设:

class BooksController < ApplicationController
...
  def index
    @books = Books.includes(:author, :publisher).with_attached_cover.all
    BookSerializer.new(@book,  include: [:author, :publisher]).serializable_hash.to_json
  end
...
end

class BookSerializer
  include FastJsonapi::ObjectSerializer
  cache_options store: Rails.cache, namespace: 'fast-jsonapi', expires_in: 24.hours

  belongs_to :author
  belongs_to :publisher

  attributes :all_the_book_attributes_im_too_lazy_to_list
end

还假设我有大约 5000 本书,有 2000 位作者和 100 位出版商,所以我希望缓存会对性能产生很大影响。

但是,事实上,无论是否启用缓存,我都看到我的数据库以相同的方式命中,而且响应时间确实很慢。此外,在检查我的缓存时,它似乎只缓存了每一本书,而不是整个序列化的哈希。

现在我想知道我是否完全错过了在序列化程序中缓存的目的,或者我是否需要在控制器中添加一些额外的层?如果是,是否有解决方案以 DRY 方式执行此操作?会不会和序列化器的缓存冲突?那么,序列化程序中缓存的目的是什么?

我知道我可以使用多种方式/缓存层。我只是不确定要合并哪些以及是否要防止这些层之间的任何冲突。

【问题讨论】:

你是在开发模式还是生产模式下尝试这个? 【参考方案1】:

我可以看到你想要缓存这个 JSON 响应。

为此查询添加缓存键。当书籍随时间发生变化时,您需要使用它来使响应无效。

# model book.rb
class Book < ApplicationRecord
...
  def self.cache_key
    
      serializer: 'books',
      stat_record: Book.maximum(:updated_at)
    
  end
...
end

在您的控制器中使用该键从缓存中获取数据或进行新查询:

class BooksController < ApplicationController
...
  def index
    @books = Rails.cache.fetch(Book.cache_key) do
      BookSerializer.new(
        Books.includes(:author, :publisher).with_attached_cover.all, 
         
          include: [:author, :publisher]
        
      ).serializable_hash.to_json
    end

    render json: @books 
  end
...
end

您还可以查看页面缓存。

顺便说一句,如果你有 5000 个条目,你应该考虑分页。

【讨论】:

以上是关于如何缓存rails api控制器的主要内容,如果未能解决你的问题,请参考以下文章

如何将查询参数传递给 Rails API 控制器?

如何让 Devise 和 JWT 与我的版本化 API Rails 控制器一起工作?

带有查询字符串参数的 Rails 动作缓存

Rails的不同缓存策略

验收测试 Rails 使用“测试 API”进行客户端状态控制

Rails 如何在使用外部 API 创建时保存数据?