2016-03-04 3 views
2

У моего игрушечного приложения есть пара моделей, rent_units и пользователей. Вы можете найти репо hereКэширование активной модели Serializer 10. Кажется, он не работает. Зачем?

Я бегу 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) 
... 

У меня есть RentalUnitSerializer, который выглядит следующим образом:

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

    belongs_to :user 
end 

Это мой 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 

Это часть моего 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" 

И это мой конфиг/среда/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 

Вот странное поведение

Когда я посещаю 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) 

Когда я навещаю 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) 

Что происходит? Похоже, что в последних журналах пользователи кэшируются? Я считаю, что, поскольку 3 единицы аренды принадлежат Пользователю 1, AMS имеет некоторое кэширование по умолчанию, когда идентичные SQL-запросы просто попадают в кеш какого-то типа. Таким образом, первый запрос для User1 попадает в базу данных сервера, но в последующих запросах для User1 нет. Где этот кеш? Это на сервере? Или какой-нибудь веб-сервер?

Но я думаю, что моя стратегия кэширования в моем Serializer не работает вообще. Зачем?

ответ

3

Чтобы помочь с отладкой, попробуйте установить logger для вашего кеша. Кэш Rails поддерживает установку регистратора, но MemoryStore не устанавливает его по умолчанию.

В инициализаторе, попробуйте следующее:

# config/initializers/cache.rb 
Rails.cache.logger = Logger.new(STDOUT) 
# or Rails.cache.logger = Rails.logger 

Перезапустите сервер Rails, и вы должны увидеть протоколирование кэша хитов/промахов. Я подозреваю, что он работает, но, возможно, не так, как вы ожидали.


Поскольку вы спросили, есть на самом деле пару слоев кэшировать ваш вопрос касается: фрагмент (или представления) кэширования и кэширования запросов.

Вы включили кеш :memory_store, который создаст экземпляр ActiveSupport::Cache::MemoryStore, доступный в вашем приложении, и в консоли Rails, как Rails.cache.

Вы также установили cache для вашего сериализатора. С ActiveModelSerializer guides для вашей версии, похоже, что вы правильно настроили это. Все идет нормально.

Как правило, в контроллере Rails кеш Rails не запускается, пока вы не сделаете рендер. В вашем случае вы просматриваете json-представление (через AMS); он будет работать с шаблоном HTML.

В первый раз, когда этот запрос сделан, кеш холодный, выполняется запрос БД, Rails запрашивает кеш для представления строк (ов) JSON с помощью ключа кеша (или ключей). Поскольку кеш пуст для этого набора ресурсов, должна быть сгенерирована строка JSON, затем она кэшируется в Rails.cache, после чего возвращается ответ.

В следующий раз, когда этот запрос сделан (в окне срока действия), выполняется запрос БД - Rails должен знать, для каких ресурсов можно запросить кеш правильно? - и на этот раз кеш попадает, и строка возвращается из кеша. Никакой новый JSON не требуется. Обратите внимание, что это все еще приводит к удалению БД, чтобы запросить исходный ресурс (ы). Эти запросы необходимы AMS для поиска ключей кеши для вашего JSON.

Вы также видите CACHE select ... запросов в своих журналах. Как уже упоминалось в другом ответе, это может указывать на то, что вы делаете один и тот же запрос БД снова и снова (часто это показатель N+1 query), поэтому предлагается «нетерпеливо загружать» эти отношения. Ваш RentalUnit принадлежит к :user, поэтому для каждой единицы аренды отдельный запрос делается для каждого пользователя - вы можете получить всех этих пользователей в одном запросе с активной загрузкой.

Rails обеспечивает некоторую способность cache the results of SQL queries. Это отдельно от кэширования представления, которое мы обсуждали, которое вы включили для AMS.