Saltar a contenido

lrucache: Caché LRU en Lua basado en LuaJIT FFI

Instalación

Si no has configurado la suscripción al repositorio RPM, regístrate. Luego puedes proceder con los siguientes pasos.

CentOS/RHEL 7 o 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 con NGINX, asegúrate de que nginx-module-lua esté instalado.

Este documento describe lua-resty-lrucache v0.15 lanzado el 10 de octubre de 2024.


-- archivo myapp.lua: módulo de ejemplo "myapp"

local _M = {}

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

-- necesitamos inicializar la caché a nivel del módulo lua para que
-- pueda ser compartida por todas las solicitudes atendidas por cada proceso trabajador de nginx:
local c, err = lrucache.new(200)  -- permitir hasta 200 elementos en la caché
if not c then
    error("falló al crear la caché: " .. (err or "desconocido"))
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 en 0.1 seg
    c:delete("dog")

    c:flush_all()  -- vaciar todos los datos en caché
end

return _M
## nginx.conf

http {
    # solo si no se usa una versión oficial de OpenResty
    server {
        listen 8080;

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

Descripción

Esta biblioteca implementa una caché LRU simple para OpenResty y el módulo ngx_lua.

Esta caché también soporta tiempo de expiración.

La caché LRU reside completamente en la VM de Lua y está sujeta a la GC de Lua. Como tal, no esperes que se comparta a través del límite del proceso del SO. La ventaja es que puedes almacenar valores complejos de Lua arbitrarios (como tablas de Lua profundamente anidadas) sin el costo de la serialización (como con la API del diccionario compartido de ngx_lua). La desventaja es que tu caché siempre está limitada al proceso del SO actual (es decir, el proceso trabajador actual de Nginx). No tiene mucho sentido usar esta biblioteca en el contexto de init_by_lua porque la caché no será compartida por ninguno de los procesos trabajadores (a menos que solo quieras "calentar" la caché con elementos predefinidos que serán heredados por los trabajadores a través de fork()).

Esta biblioteca ofrece dos implementaciones diferentes en forma de dos clases: resty.lrucache y resty.lrucache.pureffi. Ambas implementan la misma API. La única diferencia es que la última es una implementación pura de FFI que también implementa una tabla hash basada en FFI para la búsqueda en caché, mientras que la primera usa tablas nativas de Lua.

Si la tasa de aciertos de la caché es relativamente alta, deberías usar la clase resty.lrucache que es más rápida que resty.lrucache.pureffi.

Sin embargo, si la tasa de aciertos de la caché es relativamente baja y puede haber muchas variaciones de claves insertadas y eliminadas de la caché, entonces deberías usar resty.lrucache.pureffi, porque las tablas de Lua no son buenas para eliminar claves con frecuencia. Probablemente verías que la llamada a la función resizetab en el tiempo de ejecución de LuaJIT es muy activa en los gráficos de llama en CPU si usas la clase resty.lrucache en lugar de resty.lrucache.pureffi en tal caso de uso.

Métodos

Para cargar esta biblioteca,

  1. usa una versión oficial de OpenResty o sigue las instrucciones de Instalación.
  2. usa require para cargar la biblioteca en una variable local de Lua:
local lrucache = require "resty.lrucache"

o

local lrucache = require "resty.lrucache.pureffi"

new

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

Crea una nueva instancia de caché. En caso de fallo, devuelve nil y una cadena describiendo el error.

El argumento max_items especifica el número máximo de elementos que esta caché puede almacenar.

El argumento load-factor designa el "factor de carga" de la tabla hash basada en FFI utilizada internamente por resty.lrucache.pureffi; el valor predeterminado es 0.5 (es decir, 50%); si se especifica el factor de carga, se limitará al rango de [0.1, 1] (es decir, si el factor de carga es mayor que 1, se saturará a 1; de igual manera, si el factor de carga es menor que 0.1, se limitará a 0.1). Este argumento solo es significativo para resty.lrucache.pureffi.

set

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

Establece una clave con un valor y un tiempo de expiración.

Cuando la caché está llena, la caché automáticamente expulsará el elemento menos recientemente utilizado.

El argumento opcional ttl especifica el tiempo de expiración. El valor de tiempo está en segundos, pero también puedes especificar la parte fraccionaria (por ejemplo, 0.25). Un argumento ttl nulo significa que el valor nunca expira (que es el predeterminado).

El argumento opcional flags especifica un valor de bandera de usuario asociado con el elemento a almacenar. Se puede recuperar más tarde con el elemento. Las banderas de usuario se almacenan como un entero sin signo de 32 bits internamente, y por lo tanto deben ser especificadas como un número de Lua. Si no se especifica, las banderas tendrán un valor predeterminado de 0. Este argumento se agregó en la versión v0.10.

get

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

Recupera un valor con la clave. Si la clave no existe en la caché o ya ha expirado, se devolverá nil.

A partir de v0.03, los datos obsoletos también se devuelven como el segundo valor de retorno si están disponibles.

A partir de v0.10, el valor de las banderas de usuario asociado con el elemento almacenado también se devuelve como el tercer valor de retorno. Si no se dieron banderas de usuario a un elemento, sus banderas predeterminadas serán 0.

delete

syntax: cache:delete(key)

Elimina un elemento especificado por la clave de la caché.

count

syntax: count = cache:count()

Devuelve el número de elementos actualmente almacenados en la caché incluyendo elementos expirados si los hay.

El valor de count devuelto siempre será mayor o igual a 0 y menor o igual al argumento size dado a cache:new.

Este método se agregó en la versión v0.10.

capacity

syntax: size = cache:capacity()

Devuelve el número máximo de elementos que la caché puede almacenar. El valor devuelto es el mismo que el argumento size dado a cache:new cuando se creó la caché.

Este método se agregó en la versión v0.10.

get_keys

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

Recupera la lista de claves actualmente dentro de la caché hasta max_count. Las claves se ordenarán en orden de MRU (claves más recientemente utilizadas primero).

Esta función devuelve una tabla de Lua (array) (con claves enteras) que contiene las claves.

Cuando max_count es nil o 0, se devolverán todas las claves (si las hay).

Cuando se proporciona un argumento de tabla res, esta función no asignará una tabla y en su lugar insertará las claves en res, junto con un valor nil al final.

Este método se agregó en la versión v0.10.

flush_all

syntax: cache:flush_all()

Vacía todos los datos existentes (si los hay) en la instancia de caché actual. Esta es una operación O(1) y debería ser mucho más rápida que crear una nueva instancia de caché.

Sin embargo, ten en cuenta que el método flush_all() de resty.lrucache.pureffi es una operación O(n).

Requisitos previos

nginx.conf

http {
    ...
}

y luego carga la biblioteca en Lua:lua local lrucache = require "resty.lrucache" ```

Ver También

GitHub

Puedes encontrar consejos de configuración adicionales y documentación para este módulo en el repositorio de GitHub para nginx-module-lrucache.