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,
- usa una versión oficial de OpenResty o sigue las instrucciones de Instalación.
- usa
requirepara 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
- OpenResty: https://openresty.org
- el módulo ngx_http_lua: https://github.com/openresty/lua-nginx-module
- el módulo ngx_stream_lua: https://github.com/openresty/stream-lua-nginx-module
- la biblioteca lua-resty-core: https://github.com/openresty/lua-resty-core
GitHub
Puedes encontrar consejos de configuración adicionales y documentación para este módulo en el repositorio de GitHub para nginx-module-lrucache.