Библиотека сайта rus-linux.net
Фреймворк Zotonic
Глава 9 из книги "Производительность приложений с открытым исходным кодом".
Оригинал: Zotonic
Авторы: Arjan Scherpenisse и Marc Worrell
Перевод: Н.Ромоданов
Деп-кэш
Центральный кэширующим механизмом в каждом сайте Zotonic является деп-кэш (depcache), английское название depcache является сокращением от dependency cache - кэш зависимостей. Деп-кэш является хранилищем значений «ключ-значение», которое размещено в памяти и в котором хранится список зависимостей для каждой хранимого ключа.
Для каждого ключа мы храним в деп-кэше следующие данные:
- значение ключа;
- порядковый номер, глобальное целое число, увеличивающееся на единицу при каждом запросе на обновление;
- время окончания действия ключа (указывается в секундах);
- список других ключей, от которых зависит этот ключ (например, идентификатор ресурса, указываемый в кэшированном шаблоне), а также
- в случае, если ключ должен быть еще и вычислен, то и список процессов, ожидающих значения ключа.
Если запрашивается ключ, то кэш проверяет, есть ли этот ключ, не истекло ли его время действия, а также проверяется меньше ли порядковые номера всех ключей его зависимостей, чем порядковый номер кэшированного ключа. Если ключ все еще действует, то возвращается его значение, в противном случае ключ и его значение удаляются из кэша и возвращается значение undefined
(не определено).
Либо, если ключ должен быть вычислен, процесс, который сделал запрос, будет в ключе добавлен в список ожидания.
Реализация использует механизм ETS, Erlang Term Storage, который представляет собой стандартную реализацию хэш-таблиц, являеющуюся частью дистрибутива Erlang OTP. Фреймворком Zotonic для деп-кэша создаются следующие таблицы ETS:
- Мета таблица: Таблица ETS, в которой находятся все сохраняемые ключи, сроки их действия и зависимости ключей. Запись в этой таблице имеет вид
#meta{key, expire, serial, deps}
(ключ, время окончания действия, зависимости). - Таблица зависимостей: Таблица ETS, в которой хранятся порядковые номера для каждого ключа.
- Таблица данных: Таблица ETS, в которой хранятся данные для каждого ключа.
- Словарь идентификаторов PID ожидающих процессов: Таблица ETS, в которой хранятся идентификаторы всех процессов, ожидающих значение ключа.
Таблицы ETS оптимизированы для параллельной выборки и доступ к ним обычно осуществляется непосредственно вызывающим процессом. В результате не требуется никакого взаимодействия между вызывающим процессом и процессом деп-кэша.
Процесс деп-кэша вызывается для выполнения следующих действий:
- чтобы выяснить, какие процессы ожидают, когда значение будет вычислено другим процессом;
- помещения (запоминания) запросов, сериализации увеличения на единицу последовательных номеров и
- удаления запросов, также сериализации доступа к деп-кэшу.
Деп-кэш может быть довольно большим. Чтобы предотвратить чрезмерное увеличение его размера, есть процесс сборщика мусора. Сборщик мусора медленно перебирает все содержимое деп-кэша, удаляя ключи, у которых истек срок действия. Если размер деп-кэша превышает определенный размер (100 Мб, по умолчанию), то работа сборщика мусора ускоряется и он удаляет 10% всех встречающихся элементов. Он продолжает удаление до тех пор, пока размер кэша не станет ниже указанного порога.
Выделение 100 Мб для кэш-памяти может показаться малым для многотерабайтных баз данных. Однако, поскольку в кэше хранятся, в основном, текстовые данные, его размер будет достаточен для того, чтобы хранить горячие данные для большинства веб-сайтов. В противном случае размер кэша можно изменить в конфигурации.
Кэш-память словаря процесса
Другой парадигмой кэширования в памяти, используемой в Zotonic, является кэширование в памяти словаря процесса. Как уже было описано ранее, модели доступа к данным определяются с помощью шаблонов. Чтобы оптимизировать доступ к данным, в системе кэширования применяются простые эвристики.
Важным при такой оптимизации является то, что данные кэшируются в словаре процессов Erlang в том процессе, который обрабатывает запрос. Словарь процесса является простым хранилищем данных вида «ключ-значение», находящимся в той же самой куче, что и процесс. С его помощью в функциональный язык Erlang по существу добавляется механизм работы с состояниями. По этой причине использование словаря процесса, как правило, не одобряется, но он полезен при кешировании данных внутри процесса.
Когда происходит доступ к ресурсу (не забудьте, что ресурс является центральной единицей данных в Zotonic), то ресурс копируется в словарь процесса. То же самое делается для результатов вычислений, например, проверок возможности доступа, а также и для других данных, например, конфигурационных значений.
Для каждого свойства ресурса, например, названия сообщения, краткого описания сообщения или текста, составляющего тело сообщения, требуется, когда это свойство отображается на странице, выполнять проверку, разрешен ли доступ к этому ресурсу, а затем получать от это ресурса запрашиваемое свойство. Кэширование всех свойств ресурса и результатов разрешенич доступа значительно ускоряет использование данных, получаемых из этого ресурса, а также многие трудно предсказываемые недостатки моделей доступа к данным, когда доступ осуществляется с помощью шаблонов.
Поскольку страница или процесс могут использовать огромное количество данных, в этой кэш-памяти есть несколько клапанов, позволяющих сбрасывать нагрузку:
- Когда в словаре накапливается более 10000 ключей, весь словарь процесса сбрасывается из оперативной памяти в долговременную память. Это защищает словарь от хранения в нем большого количества неиспользуемых элементов, что случается в случае, когда в цикле обрабатываются длинные списки ресурсов. Используются специальные переменные Erlang -
$ancestors
. - Кэш-память должна включаться программно. Это делается автоматически для каждого поступающего запроса HTTP или запроса WebSocket, а также при рендеринге шаблона.
- Между запросами HTTP / WebSocket выполняется запись словаря процесса из оперативной памяти в долговременную, т. к. несколько подряд поступающих запросов HTTP/WebSocket могут разделять один и тот же процесс.
- В кэш-памяти не происходит отслеживание зависимостей. При любом удалении деп-кэша весь словарь процесса, который выполняет это удаление, будет также сбрасываться из оперативной памяти в долговременную.
Когда кэш-память отключается, то все поисковые запросы обрабатываются с помощью деп-кэша. Это приводит к вызову процесса деп-кэша и копированию данных между деп-кэшем и запрашивающим процессом.
Продолжение статьи: Виртуальная машина Erlang.