Active Model Serializer 10缓存。它似乎不起作用。为什么?

Jwa*_*622 5 api ruby-on-rails active-model-serializers

我的玩具应用程序有几个模型,rental_unit和用户。你可以在这里找到回购

我正在运行Rails 5和AMS 10。

active_model_serializers (0.10.0.rc4)
...
rails (5.0.0.beta3)
      actioncable (= 5.0.0.beta3)
      actionmailer (= 5.0.0.beta3)
      actionpack (= 5.0.0.beta3)
...
Run Code Online (Sandbox Code Playgroud)

我有一个RentalUnitSerializer看起来像这样:

class RentalUnitSerializer < ActiveModel::Serializer
  cache key: 'rental_unit', expires_in: 3.hours
  attributes :id, :rooms, :bathrooms, :price, :price_cents

  belongs_to :user
end
Run Code Online (Sandbox Code Playgroud)

这是我的UserSerializer:

class UserSerializer < ActiveModel::Serializer
  cache key: 'user'
  attributes :id, :name, :email
  has_many :rental_units

  def name
    names = object.name.split(" ")
    "#{names[0].first}. #{names[1]}"
  end
end
Run Code Online (Sandbox Code Playgroud)

这是我的Gemfile的一部分:

    source 'https://rubygems.org'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '>= 5.0.0.beta3', '< 5.1'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Use Puma as the app server
gem 'puma'
gem 'active_model_serializers', '~> 0.10.0.rc1'
gem "dalli"
gem "memcachier"
Run Code Online (Sandbox Code Playgroud)

这是我的config / environments / development.rb文件:

Rails.application.configure do
  # Settings specified here will take precedence over those in config/application.rb.

  # In the development environment your application's code is reloaded on
  # every request. This slows down response time but is perfect for development
  # since you don't have to restart the web server when you make code changes.
  config.cache_classes = false

  # Do not eager load code on boot.
  config.eager_load = false

  # Show full error reports.
  config.consider_all_requests_local = true

  # Enable/disable caching. By default caching is disabled.
  if Rails.root.join('tmp/caching-dev.txt').exist?
    config.action_controller.perform_caching = true

    config.action_mailer.perform_caching = false

    config.cache_store = :memory_store
    config.public_file_server.headers = {
      'Cache-Control' => 'public, max-age=172800'
    }
  else
    config.action_controller.perform_caching = true

    config.action_mailer.perform_caching = false

    config.cache_store = :memory_store
  end

  # Don't care if the mailer can't send.
  config.action_mailer.raise_delivery_errors = false

  # Print deprecation notices to the Rails logger.
  config.active_support.deprecation = :log

  # Raise an error on page load if there are pending migrations.
  config.active_record.migration_error = :page_load


  # Raises error for missing translations
  # config.action_view.raise_on_missing_translations = true

  # Use an evented file watcher to asynchronously detect changes in source code,
  # routes, locales, etc. This feature depends on the listen gem.
  config.file_watcher = ActiveSupport::EventedFileUpdateChecker
end
Run Code Online (Sandbox Code Playgroud)

这是奇怪的行为

当我访问http:// localhost:3000 / users时,这是我的日志,没有缓存的迹象:

Started GET "/users" for ::1 at 2016-03-04 15:18:12 -0500
Processing by UsersController#index as HTML
  User Load (0.1ms)  SELECT "users".* FROM "users"
[active_model_serializers]   RentalUnit Load (0.2ms)  SELECT "rental_units".* FROM "rental_units" WHERE "rental_units"."user_id" = ?  [["user_id", 1]]
[active_model_serializers]   RentalUnit Load (0.1ms)  SELECT "rental_units".* FROM "rental_units" WHERE "rental_units"."user_id" = ?  [["user_id", 2]]
[active_model_serializers]   RentalUnit Load (0.1ms)  SELECT "rental_units".* FROM "rental_units" WHERE "rental_units"."user_id" = ?  [["user_id", 3]]
[active_model_serializers] Rendered ActiveModel::Serializer::CollectionSerializer with ActiveModel::Serializer::Adapter::JsonApi (11.0ms)
Completed 200 OK in 13ms (Views: 12.5ms | ActiveRecord: 0.5ms)
Run Code Online (Sandbox Code Playgroud)

当我访问http:// localhost:3000 / rental_units时,有一些缓存吗?

Started GET "/rental_units" for ::1 at 2016-03-04 15:18:37 -0500
Processing by RentalUnitsController#index as HTML
  RentalUnit Load (0.4ms)  SELECT "rental_units".* FROM "rental_units"
[active_model_serializers]   User Load (0.9ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
[active_model_serializers]   CACHE (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
[active_model_serializers]   CACHE (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
[active_model_serializers]   User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
[active_model_serializers] Rendered ActiveModel::Serializer::CollectionSerializer with ActiveModel::Serializer::Adapter::JsonApi (16.1ms)
Completed 200 OK in 21ms (Views: 19.1ms | ActiveRecord: 1.4ms)
Run Code Online (Sandbox Code Playgroud)

到底是怎么回事?看起来在后面的日志中,正在缓存用户?我相信,由于3个不同的租赁单元属于用户1,因此AMS会进行一些默认的缓存,在这些缓存中,相同的SQL查询只会命中某种类型的缓存。因此,对User1的第一个查询会命中服务器的数据库,而对User1的后续查询则不会。此缓存在哪里?在服务器上吗?还是一些网络服务器?

但是我认为我的Serializer中的缓存策略根本无法正常工作。为什么?

ros*_*sta 5

为了帮助调试,请尝试logger为您的缓存设置a 。Rails缓存支持设置记录器,但MemoryStore默认情况下不设置。

在初始化程序中,尝试以下操作:

# config/initializers/cache.rb
Rails.cache.logger = Logger.new(STDOUT)
# or Rails.cache.logger = Rails.logger
Run Code Online (Sandbox Code Playgroud)

重新启动Rails服务器,您应该看到缓存命中/未命中的日志记录。我怀疑它正在工作,但可能不是您期望的那样。


正如您所提出的,实际上您的问题涉及到几层缓存:片段(或视图)缓存和查询缓存。

您已启用缓存,:memory_store因为它将ActiveSupport::Cache::MemoryStore在您的应用程序和Rails控制台中创建一个可访问实例,实例为Rails.cache

您还cache为序列化程序设置了选项。在您所用版本的ActiveModelSerializer指南中,您似乎已正确设置了它。到目前为止,一切都很好。

通常,在Rails控制器中,直到您去渲染视图时才调用Rails缓存。就您而言,您正在渲染json视图(通过AMS);与HTML模板相同。

第一次发出此请求时,高速缓存很冷,进行了数据库查询,Rails使用一个或多个高速缓存键向高速缓存请求JSON字符串的表示形式。由于这组资源的缓存为空,因此必须生成JSON字符串,然后将其缓存在中Rails.cache,然后返回响应。

下次发出此请求时(在到期窗口内),将进行数据库查询 -Rails需要知道哪些资源可以请求高速缓存?-这次,缓存命中了,并且从缓存中返回了字符串。无需生成新的JSON。请注意,这仍然会导致数据库命中以请求原始资源。这些请求对于AMS查找JSON的缓存键是必需的。

您还会CACHE select ...在日志中看到查询。正如另一个答案中提到的那样,这可能表明您一遍又一遍地进行相同的数据库查询(通常是N + 1查询的指示),因此建议“急于加载”这些关系。您的RentalUnit属于:user,因此对于每个租赁单元,将为每个用户提出一个单独的请求-您可以通过急切的加载在一个查询中抓住所有这些用户。

Rails提供了一些缓存SQL查询结果的功能。这与我们一直在讨论的为AMS启用的视图缓存是分开的。