Кэш на стороне сервера

Так же смотри главу про кластеризацию.

Xitrum предоставляет широкие возможности для кэширования на стороне клиента и сервера. На уровне веб сервера, маленькие файлы кэшируются в памяти, большие отправляются по технологии zero copy. Скорость отдачи статических файлов сравнима с Nginx. На уровне фреймворка вы можете использовать кэш страницы, кэш контроллера или объектный кэш в стиле Rails. Xitrum придерживается рекомендации Google.

Для динамического контента, если контент не меняется после создания (как в случае статического файла), вы можете установить необходимые заголовки для агрессивного кэширования. В этом случае используйте метод setClientCacheAggressively() в контроллере.

Иногда требуется запретить кэширование на стороне клиента. В этом случае используйте setNoClientCache() в контроллере.

Кэширование на стороне сервера более подробно рассматривается ниже.

Кэширование страницы или контроллера

import xitrum.Action
import xitrum.annotation.{GET, CacheActionMinute, CachePageMinute}

@GET("articles")
@CachePageMinute(1)
class ArticlesIndex extends Action {
  def execute() {
    ...
  }
}

@GET("articles/:id")
@CacheActionMinute(1)
class ArticlesShow extends Action {
  def execute() {
    ...
  }
}

Термин “кэш страницы” и “кэш контроллера” позаимствован из Ruby on Rails.

Последовательность обработки запроса следующая: (1) запрос -> (2) пре-фильтры -> (3) метод execute контроллера -> (4) ответ

После первого запроса, Xitrum закеширует ответ на указанный период времени. @CachePageMinute(1) или @CacheActionMinute(1) задают время кэша равное одной минуте. Xitrum кэширует страницы только в случае если ответ имеет статус “200 OK”. Например, ответ со статусом “500 Internal Server Error” или “302 Found” (redirect) не будет помещен в кэш.

В случае запросов к тому же контроллеру, если кэш еще не устарел, Xitrum в качестве ответа будет использовать значение из кэша:

  • Для кэша страницы, последовательность обработки (1) -> (4).
  • Для кэша контроллера, последовательность обработки (1) -> (2) -> (4), или просто (1) -> (2) если пре-фильтр вернет значение “false”.

Единственное различие: для кэша страницы пре-фильтры не запускаются.

Обычно, кэш страницы используется когда один и тот же ответ подходит для всех пользователей. Кэш контроллера используется когда вам нужно использовать пре-фильтр как защиту, например для проверки авторизации пользователя:

  • Если пользователь прошел авторизацию, он может получать кэшированный ответ.
  • Если нет, отправить пользователя на страницу авторизации.

Кэш объект

Кэширующие методы предоставляются объектом xitrum.Config.xitrum.cache, наследником xitrum.Cache.

Без указания TTL (времени жизни):

  • put(key, value)

С указанием TTL:

  • putSecond(key, value, seconds)
  • putMinute(key, value, minutes)
  • putHour(key, value, hours)
  • putDay(key, value, days)

Обновление кэша только в случае отсутствия значения:

  • putIfAbsent(key, value)
  • putIfAbsentSecond(key, value, seconds)
  • putIfAbsentMinute(key, value, minutes)
  • putIfAbsentHour(key, value, hours)
  • putIfAbsentDay(key, value, days)

Удаление кэша

Удаление кэша страницы или контроллера:

removeAction[MyAction]

Удаление объектного кэша:

remove(key)

Удаление всех ключей начинающихся с префикса:

removePrefix(keyPrefix)

При использовании removePrefix, вы можете организовать иерархический кэш. Например, вы можете создавать кэш связанной со статьей, а когда статья изменится просто удалите весь кэш статьи.

import xitrum.Config.xitrum.cache

// Кэш с префиксом
val prefix = "articles/" + article.id
cache.put(prefix + "/likes", likes)
cache.put(prefix + "/comments", comments)

// Позднее, очистка кэша
cache.remove(prefix)

Конфигурация

Вы можете использовать свою реализацию кэша.

В файле config/xitrum.conf, вы можете настроить кэш двумя способами:

cache = my.cache.EngineClassName

Или:

cache {
  "my.cache.EngineClassName" {
    option1 = value1
    option2 = value2
  }
}

Xitrum предоставляет реализацию по умолчанию:

cache {
  # Simple in-memory cache
  "xitrum.local.LruCache" {
    maxElems = 10000
  }
}

Если вы используете кластер, вы можете использовать Hazelcast.

Для создания своей реализации кэша, реализуйте интерфейс interface xitrum.Cache.

Как работает кэш

Вход:

               ответ контроллера
               должен быть в кэше
запрос         и кэш существует?
-------------------------+---------------НЕТ-------------->
                         |
<---------ДА-------------+
  ответ из кэша

Выход:

               ответ контроллера
               должен быть помещен в кэш
               кэш не существует?                     ответ
<---------НЕТ------------+---------------------------------
                         |
<---------ДА-------------+
  сохранить ответ в кэше

xitrum.util.LocalLruCache

Этот кэш переиспользуется всеми компонентами Xitrum. Если вам нужен отдельный небольшой кэш, вы можете использовать xitrum.util.LocalLruCache.

import xitrum.util.LocalLruCache

// LRU (Least Recently Used) кэш содержит до 1000 элементов.
// Ключи и значения имеет тип String.
val cache = LocalLruCache[String, String](1000)

Переменная cache имеет тип java.util.LinkedHashMap. Вы можете использовать методы из LinkedHashMap.