Pular para conteúdo

lrucache: Cache LRU em Lua baseado em LuaJIT FFI

Instalação

Se você ainda não configurou a assinatura do repositório RPM, inscreva-se. Depois, você pode prosseguir com os seguintes passos.

CentOS/RHEL 7 ou 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

Para usar esta biblioteca Lua com NGINX, certifique-se de que o nginx-module-lua esteja instalado.

Este documento descreve lua-resty-lrucache v0.15 lançado em 10 de outubro de 2024.


-- arquivo myapp.lua: exemplo do módulo "myapp"

local _M = {}

-- alternativamente: local lrucache = require "resty.lrucache.pureffi"
local lrucache = require "resty.lrucache"

-- precisamos inicializar o cache no nível do módulo lua para que
-- ele possa ser compartilhado por todas as requisições atendidas por cada processo trabalhador do nginx:
local c, err = lrucache.new(200)  -- permite até 200 itens no cache
if not c then
    error("falha ao criar o cache: " .. (err or "desconhecido"))
end

function _M.go()
    c:set("dog", 32)
    c:set("cat", 56)
    ngx.say("dog: ", c:get("dog"))
    ngx.say("cat: ", c:get("cat"))

    c:set("dog", { age = 10 }, 0.1)  -- expira em 0.1 seg
    c:delete("dog")

    c:flush_all()  -- limpa todos os dados em cache
end

return _M
## nginx.conf

http {
    # apenas se não estiver usando uma versão oficial do OpenResty
    server {
        listen 8080;

        location = /t {
            content_by_lua_block {
                require("myapp").go()
            }
        }
    }
}

Descrição

Esta biblioteca implementa um cache LRU simples para OpenResty e o módulo ngx_lua.

Este cache também suporta tempo de expiração.

O cache LRU reside completamente na VM Lua e está sujeito ao GC do Lua. Como tal, não espere que ele seja compartilhado através da fronteira do processo do SO. A vantagem é que você pode armazenar valores Lua arbitrariamente complexos (como tabelas Lua profundamente aninhadas) sem a sobrecarga de serialização (como com a API de dicionário compartilhado do ngx_lua). A desvantagem é que seu cache está sempre limitado ao processo do SO atual (ou seja, ao processo trabalhador do Nginx atual). Não faz muito sentido usar esta biblioteca no contexto de init_by_lua porque o cache não será compartilhado por nenhum dos processos trabalhadores (a menos que você queira apenas "aquecer" o cache com itens predefinidos que serão herdados pelos trabalhadores via fork()).

Esta biblioteca oferece duas implementações diferentes na forma de duas classes: resty.lrucache e resty.lrucache.pureffi. Ambas implementam a mesma API. A única diferença é que a última é uma implementação pura de FFI que também implementa uma tabela hash baseada em FFI para a busca no cache, enquanto a primeira usa tabelas Lua nativas.

Se a taxa de acerto do cache for relativamente alta, você deve usar a classe resty.lrucache, que é mais rápida que resty.lrucache.pureffi.

No entanto, se a taxa de acerto do cache for relativamente baixa e houver muitas variações de chaves inseridas e removidas do cache, você deve usar a resty.lrucache.pureffi, pois as tabelas Lua não são boas em remover chaves com frequência. Você provavelmente verá a chamada da função resizetab no tempo de execução do LuaJIT sendo muito quente em gráficos de chama em CPU se você usar a classe resty.lrucache em vez de resty.lrucache.pureffi em tal caso de uso.

Métodos

Para carregar esta biblioteca,

  1. use uma versão oficial do OpenResty ou siga as instruções de Instalação.
  2. use require para carregar a biblioteca em uma variável Lua local:
local lrucache = require "resty.lrucache"

ou

local lrucache = require "resty.lrucache.pureffi"

new

syntax: cache, err = lrucache.new(max_items [, load_factor])

Cria uma nova instância de cache. Em caso de falha, retorna nil e uma string descrevendo o erro.

O argumento max_items especifica o número máximo de itens que este cache pode conter.

O argumento load-factor designa o "fator de carga" da tabela hash baseada em FFI usada internamente por resty.lrucache.pureffi; o valor padrão é 0.5 (ou seja, 50%); se o fator de carga for especificado, ele será limitado ao intervalo de [0.1, 1] (ou seja, se o fator de carga for maior que 1, será saturado para 1; da mesma forma, se o fator de carga for menor que 0.1, será limitado a 0.1). Este argumento só é significativo para resty.lrucache.pureffi.

set

syntax: cache:set(key, value, ttl?, flags?)

Define uma chave com um valor e um tempo de expiração.

Quando o cache está cheio, ele automaticamente removerá o item menos recentemente usado.

O argumento opcional ttl especifica o tempo de expiração. O valor do tempo está em segundos, mas você também pode especificar a parte fracionária (por exemplo, 0.25). Um argumento ttl nulo significa que o valor nunca expirará (que é o padrão).

O argumento opcional flags especifica um valor de flags do usuário associado ao item a ser armazenado. Ele pode ser recuperado posteriormente com o item. As flags do usuário são armazenadas como um inteiro sem sinal de 32 bits internamente e, portanto, devem ser especificadas como um número Lua. Se não especificado, as flags terão um valor padrão de 0. Este argumento foi adicionado na versão v0.10.

get

syntax: data, stale_data, flags = cache:get(key)

Busca um valor com a chave. Se a chave não existir no cache ou já tiver expirado, nil será retornado.

A partir da versão v0.03, os dados obsoletos também são retornados como o segundo valor de retorno, se disponíveis.

A partir da versão v0.10, o valor das flags do usuário associado ao item armazenado também é retornado como o terceiro valor de retorno. Se nenhuma flag do usuário foi dada a um item, suas flags padrão serão 0.

delete

syntax: cache:delete(key)

Remove um item especificado pela chave do cache.

count

syntax: count = cache:count()

Retorna o número de itens atualmente armazenados no cache incluindo itens expirados, se houver.

O valor retornado count será sempre maior ou igual a 0 e menor ou igual ao argumento size dado para cache:new.

Este método foi adicionado na versão v0.10.

capacity

syntax: size = cache:capacity()

Retorna o número máximo de itens que o cache pode conter. O valor retornado é o mesmo que o argumento size dado para cache:new quando o cache foi criado.

Este método foi adicionado na versão v0.10.

get_keys

syntax: keys = cache:get_keys(max_count?, res?)

Busca a lista de chaves atualmente dentro do cache até max_count. As chaves serão ordenadas na ordem MRU (chaves mais recentemente usadas primeiro).

Esta função retorna uma tabela Lua (array) (com chaves inteiras) contendo as chaves.

Quando max_count é nil ou 0, todas as chaves (se houver) serão retornadas.

Quando fornecido com um argumento de tabela res, esta função não alocará uma tabela e, em vez disso, inserirá as chaves em res, junto com um valor nil ao final.

Este método foi adicionado na versão v0.10.

flush_all

syntax: cache:flush_all()

Limpa todos os dados existentes (se houver) na instância de cache atual. Esta é uma operação O(1) e deve ser muito mais rápida do que criar uma nova instância de cache.

Note, no entanto, que o método flush_all() de resty.lrucache.pureffi é uma operação O(n).

Pré-requisitos

nginx.conf

http {
    ...
}

e então carregue a biblioteca em Lua:lua local lrucache = require "resty.lrucache" ```

Veja Também

GitHub

Você pode encontrar dicas de configuração adicionais e documentação para este módulo no repositório GitHub para nginx-module-lrucache.