如何缓存 rails api 控制器

How to cache a rails api controller

我在我的应用程序中发现了一些性能问题,想知道我的缓存是否正常工作,或者我是否误解/错误配置了任何东西。我正在使用 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

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

但是,实际上我看到我的数据库在启用或不启用缓存的情况下都以相同的方式命中,并且响应时间非常慢。此外,在检查我的缓存时,它似乎只缓存了每一本书,而不是整个序列化的哈希。

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

我知道我可以使用多个 ways/layers 缓存。我只是不确定要合并哪些以及是否要防止这些层之间发生任何冲突。

我看得出来你想缓存这个 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 个条目,您应该考虑分页。