lrucache: Lua-земля LRU Кэш на основе LuaJIT FFI
Установка
Если вы еще не настроили подписку на репозиторий RPM, зарегистрируйтесь. После этого вы можете продолжить с следующими шагами.
CentOS/RHEL 7 или Amazon Linux 2
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-lrucache
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-lrucache
Чтобы использовать эту Lua библиотеку с NGINX, убедитесь, что nginx-module-lua установлен.
Этот документ описывает lua-resty-lrucache v0.15, выпущенный 10 октября 2024 года.
-- файл myapp.lua: пример модуля "myapp"
local _M = {}
-- альтернативно: local lrucache = require "resty.lrucache.pureffi"
local lrucache = require "resty.lrucache"
-- нам нужно инициализировать кэш на уровне lua модуля, чтобы
-- он мог быть общим для всех запросов, обслуживаемых каждым рабочим процессом nginx:
local c, err = lrucache.new(200) -- разрешить до 200 элементов в кэше
if not c then
error("не удалось создать кэш: " .. (err or "неизвестно"))
end
function _M.go()
c:set("dog", 32)
c:set("cat", 56)
ngx.say("собака: ", c:get("dog"))
ngx.say("кот: ", c:get("cat"))
c:set("dog", { age = 10 }, 0.1) -- истекает через 0.1 сек
c:delete("dog")
c:flush_all() -- очистить все закэшированные данные
end
return _M
## nginx.conf
http {
# только если не используется официальная версия OpenResty
server {
listen 8080;
location = /t {
content_by_lua_block {
require("myapp").go()
}
}
}
}
Описание
Эта библиотека реализует простой LRU кэш для OpenResty и модуля ngx_lua.
Этот кэш также поддерживает время истечения.
LRU кэш полностью находится в Lua VM и подвержен сборке мусора Lua. Поэтому
не ожидайте, что он будет общим за пределами процесса ОС. Плюс в том,
что вы можете кэшировать произвольно сложные значения Lua (такие как глубоко вложенные таблицы Lua) без накладных расходов на сериализацию (как в API shared dictionary ngx_lua).
Недостаток в том, что ваш кэш всегда ограничен текущим процессом ОС
(т.е. текущим рабочим процессом Nginx). Не имеет большого смысла
использовать эту библиотеку в контексте
init_by_lua
потому что кэш не будет разделяться между рабочими процессами (если
вы не хотите просто "разогреть" кэш с предопределенными элементами, которые будут
унаследованы рабочими процессами через fork()).
Эта библиотека предлагает две разные реализации в виде двух классов:
resty.lrucache и resty.lrucache.pureffi. Оба реализуют один и тот же API.
Единственное различие в том, что последний является чистой реализацией FFI, которая также
реализует хэш-таблицу на основе FFI для поиска в кэше, в то время как первый использует
нативные таблицы Lua.
Если коэффициент попадания в кэш относительно высок, вам следует использовать класс resty.lrucache,
который быстрее, чем resty.lrucache.pureffi.
Однако, если коэффициент попадания в кэш относительно низок и может быть много
вариаций ключей, вставляемых в кэш и удаляемых из него, то вам следует использовать
resty.lrucache.pureffi, потому что таблицы Lua не хороши в частом удалении ключей. Вы, вероятно, увидите, что вызов функции resizetab в
время выполнения LuaJIT будет очень горячим в графиках пламени на CPU, если вы используете
класс resty.lrucache вместо resty.lrucache.pureffi в таком случае.
Методы
Чтобы загрузить эту библиотеку,
- используйте официальную версию OpenResty или следуйте инструкциям по Установке.
- используйте
require, чтобы загрузить библиотеку в локальную переменную Lua:
local lrucache = require "resty.lrucache"
или
local lrucache = require "resty.lrucache.pureffi"
new
синтаксис: cache, err = lrucache.new(max_items [, load_factor])
Создает новый экземпляр кэша. В случае неудачи возвращает nil и строку,
описывающую ошибку.
Аргумент max_items указывает максимальное количество элементов, которые этот кэш может
содержать.
Аргумент load-factor обозначает "коэффициент загрузки" хэш-таблицы на основе FFI, используемой внутренне в resty.lrucache.pureffi; значение по умолчанию — 0.5 (т.е. 50%); если коэффициент загрузки указан, он будет ограничен диапазоном [0.1, 1] (т.е. если коэффициент загрузки больше 1, он будет насыщен до 1; аналогично, если коэффициент загрузки меньше 0.1, он будет ограничен до 0.1). Этот аргумент имеет смысл только для
resty.lrucache.pureffi.
set
синтаксис: cache:set(key, value, ttl?, flags?)
Устанавливает ключ с заданным значением и временем истечения.
Когда кэш полон, кэш автоматически удалит наименее недавно использованный элемент.
Необязательный аргумент ttl указывает время истечения. Значение времени указывается в
секундах, но вы также можете указать дробную часть (например, 0.25). Аргумент ttl, равный nil,
означает, что значение никогда не истечет (что является значением по умолчанию).
Необязательный аргумент flags указывает значение пользовательских флагов, связанных с
элементом, который будет храниться. Его можно извлечь позже с элементом. Пользовательские флаги
хранятся как беззнаковое 32-битное целое число, и поэтому должны быть указаны как
число Lua. Если не указано, флаги будут иметь значение по умолчанию 0. Этот
аргумент был добавлен в релизе v0.10.
get
синтаксис: data, stale_data, flags = cache:get(key)
Извлекает значение по ключу. Если ключ не существует в кэше или уже истек, будет возвращен nil.
Начиная с v0.03, устаревшие данные также возвращаются как второе возвращаемое
значение, если они доступны.
Начиная с v0.10, значение пользовательских флагов, связанных с хранимым элементом, также
возвращается как третье возвращаемое значение. Если для элемента не были указаны пользовательские флаги, его
значение по умолчанию будет 0.
delete
синтаксис: cache:delete(key)
Удаляет элемент, указанный ключом, из кэша.
count
синтаксис: count = cache:count()
Возвращает количество элементов, в настоящее время хранящихся в кэше включая истекшие элементы, если таковые имеются.
Возвращаемое значение count всегда будет больше или равно 0 и меньше
или равно аргументу size, переданному в cache:new.
Этот метод был добавлен в релизе v0.10.
capacity
синтаксис: size = cache:capacity()
Возвращает максимальное количество элементов, которые кэш может содержать. Возвращаемое значение
такое же, как аргумент size, переданный в cache:new при создании кэша.
Этот метод был добавлен в релизе v0.10.
get_keys
синтаксис: keys = cache:get_keys(max_count?, res?)
Извлекает список ключей, в настоящее время находящихся в кэше, до max_count. Ключи
будут упорядочены в порядке MRU (наиболее недавно использованные ключи первыми).
Эта функция возвращает таблицу Lua (массив) (с целыми ключами), содержащую ключи.
Когда max_count равен nil или 0, будут возвращены все ключи (если таковые имеются).
Когда предоставляется аргумент таблицы res, эта функция не будет выделять
таблицу и вместо этого вставит ключи в res, вместе с завершающим значением nil.
Этот метод был добавлен в релизе v0.10.
flush_all
синтаксис: cache:flush_all()
Очищает все существующие данные (если таковые имеются) в текущем экземпляре кэша. Это
операция O(1) и должна быть значительно быстрее, чем создание совершенно нового экземпляра кэша.
Однако обратите внимание, что метод flush_all() resty.lrucache.pureffi является
операцией O(n).
Предварительные требования
nginx.conf
http {
...
}
и затем загрузите библиотеку в Lua:lua
local lrucache = require "resty.lrucache"
```
См. также
- OpenResty: https://openresty.org
- модуль ngx_http_lua: https://github.com/openresty/lua-nginx-module
- модуль ngx_stream_lua: https://github.com/openresty/stream-lua-nginx-module
- библиотека lua-resty-core: https://github.com/openresty/lua-resty-core
GitHub
Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-lrucache.