Перейти к содержанию

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 в таком случае.

Методы

Чтобы загрузить эту библиотеку,

  1. используйте официальную версию OpenResty или следуйте инструкциям по Установке.
  2. используйте 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" ```

См. также

GitHub

Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-lrucache.