lrucache: Cache LRU en Lua basé sur LuaJIT FFI
Installation
Si vous n'avez pas configuré l'abonnement au dépôt RPM, inscrivez-vous. Ensuite, vous pouvez procéder avec les étapes suivantes.
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
Pour utiliser cette bibliothèque Lua avec NGINX, assurez-vous que le nginx-module-lua est installé.
Ce document décrit lua-resty-lrucache v0.15 publié le 10 octobre 2024.
-- fichier myapp.lua : exemple de module "myapp"
local _M = {}
-- alternativement : local lrucache = require "resty.lrucache.pureffi"
local lrucache = require "resty.lrucache"
-- nous devons initialiser le cache au niveau du module lua afin qu'il
-- puisse être partagé par toutes les requêtes servies par chaque processus de travail nginx :
local c, err = lrucache.new(200) -- autoriser jusqu'à 200 éléments dans le cache
if not c then
error("échec de la création du cache : " .. (err or "inconnu"))
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) -- expirer dans 0.1 sec
c:delete("dog")
c:flush_all() -- vider toutes les données mises en cache
end
return _M
## nginx.conf
http {
# seulement si vous n'utilisez pas une version officielle d'OpenResty
server {
listen 8080;
location = /t {
content_by_lua_block {
require("myapp").go()
}
}
}
}
Description
Cette bibliothèque implémente un cache LRU simple pour OpenResty et le ngx_lua module.
Ce cache prend également en charge le temps d'expiration.
Le cache LRU réside complètement dans la VM Lua et est soumis à la GC Lua. En
tant que tel, ne vous attendez pas à ce qu'il soit partagé au-delà de la limite du processus OS. L'avantage
est que vous pouvez mettre en cache des valeurs Lua arbitrairement complexes (telles que des tables Lua profondément imbriquées) sans le surcoût de la sérialisation (comme avec l'API de dictionnaire partagé de ngx_lua).
L'inconvénient est que votre cache est toujours limité au processus OS actuel
(c'est-à-dire le processus de travail Nginx actuel). Il n'est pas vraiment logique d'utiliser cette bibliothèque dans le contexte de
init_by_lua
car le cache ne sera pas partagé par aucun des processus de travail (à moins que
vous ne souhaitiez simplement "réchauffer" le cache avec des éléments prédéfinis qui seront hérités par les travailleurs via fork()).
Cette bibliothèque offre deux implémentations différentes sous la forme de deux classes :
resty.lrucache et resty.lrucache.pureffi. Les deux implémentent la même API.
La seule différence est que la dernière est une implémentation FFI pure qui implémente également une table de hachage basée sur FFI pour la recherche dans le cache, tandis que la première utilise
des tables Lua natives.
Si le taux de réussite du cache est relativement élevé, vous devriez utiliser la classe resty.lrucache
qui est plus rapide que resty.lrucache.pureffi.
Cependant, si le taux de réussite du cache est relativement bas et qu'il peut y avoir beaucoup de variations de clés insérées et supprimées du cache, alors vous devriez
utiliser resty.lrucache.pureffi, car les tables Lua ne sont pas bonnes pour
supprimer fréquemment des clés. Vous pourriez probablement voir l'appel de fonction resizetab dans
l'exécution de LuaJIT être très fréquent dans les graphes de flammes sur CPU si vous utilisez la
classe resty.lrucache au lieu de resty.lrucache.pureffi dans un tel cas d'utilisation.
Méthodes
Pour charger cette bibliothèque,
- utilisez une version officielle d'OpenResty ou suivez les instructions d'Installation.
- utilisez
requirepour charger la bibliothèque dans une variable Lua locale :
local lrucache = require "resty.lrucache"
ou
local lrucache = require "resty.lrucache.pureffi"
new
syntax: cache, err = lrucache.new(max_items [, load_factor])
Crée une nouvelle instance de cache. En cas d'échec, retourne nil et une chaîne
décrivant l'erreur.
L'argument max_items spécifie le nombre maximal d'éléments que ce cache peut
contenir.
L'argument load-factor désigne le "facteur de charge" de la table de hachage basée sur FFI utilisée en interne par resty.lrucache.pureffi ; la valeur par défaut est
0.5 (c'est-à-dire 50 %) ; si le facteur de charge est spécifié, il sera limité à la
plage de [0.1, 1] (c'est-à-dire si le facteur de charge est supérieur à 1, il sera
saturé à 1 ; de même, si le facteur de charge est inférieur à 0.1, il sera
limité à 0.1). Cet argument n'est significatif que pour
resty.lrucache.pureffi.
set
syntax: cache:set(key, value, ttl?, flags?)
Définit une clé avec une valeur et un temps d'expiration.
Lorsque le cache est plein, le cache évacuera automatiquement l'élément le moins récemment utilisé.
L'argument optionnel ttl spécifie le temps d'expiration. La valeur temporelle est en
secondes, mais vous pouvez également spécifier la partie fractionnaire (par exemple 0.25). Un argument ttl nil signifie que la valeur ne
fera jamais expirer (ce qui est la valeur par défaut).
L'argument optionnel flags spécifie une valeur de drapeaux utilisateur associée à l'élément à stocker. Elle peut être récupérée plus tard avec l'élément. Les drapeaux utilisateur sont
stockés en tant qu'entier non signé de 32 bits en interne, et doivent donc être spécifiés comme
un nombre Lua. Si non spécifié, les drapeaux auront une valeur par défaut de 0. Cet
argument a été ajouté dans la version v0.10.
get
syntax: data, stale_data, flags = cache:get(key)
Récupère une valeur avec la clé. Si la clé n'existe pas dans le cache ou a
déjà expiré, nil sera retourné.
À partir de v0.03, les données périmées sont également retournées comme deuxième valeur de retour si disponibles.
À partir de v0.10, la valeur des drapeaux utilisateur associée à l'élément stocké est
également retournée comme troisième valeur de retour. Si aucun drapeau utilisateur n'a été donné à un
élément, ses drapeaux par défaut seront 0.
delete
syntax: cache:delete(key)
Supprime un élément spécifié par la clé du cache.
count
syntax: count = cache:count()
Retourne le nombre d'éléments actuellement stockés dans le cache y compris les éléments expirés, le cas échéant.
La valeur de count retournée sera toujours supérieure ou égale à 0 et inférieure
ou égale à l'argument size donné à cache:new.
Cette méthode a été ajoutée dans la version v0.10.
capacity
syntax: size = cache:capacity()
Retourne le nombre maximal d'éléments que le cache peut contenir. La valeur de retour est la
même que l'argument size donné à cache:new lors de la création du cache.
Cette méthode a été ajoutée dans la version v0.10.
get_keys
syntax: keys = cache:get_keys(max_count?, res?)
Récupère la liste des clés actuellement dans le cache jusqu'à max_count. Les clés
seront ordonnées de manière MRU (clés les plus récemment utilisées en premier).
Cette fonction retourne une table Lua (tableau) (avec des clés entières) contenant les clés.
Lorsque max_count est nil ou 0, toutes les clés (le cas échéant) seront retournées.
Lorsqu'un argument de table res est fourni, cette fonction n'allouera pas de
table et insérera plutôt les clés dans res, avec une valeur nil à la fin.
Cette méthode a été ajoutée dans la version v0.10.
flush_all
syntax: cache:flush_all()
Vide toutes les données existantes (le cas échéant) dans l'instance de cache actuelle. C'est
une opération O(1) et devrait être beaucoup plus rapide que de créer une toute nouvelle instance de cache.
Notez cependant que la méthode flush_all() de resty.lrucache.pureffi est une
opération O(n).
Prérequis
nginx.conf
http {
...
}
et ensuite chargez la bibliothèque en Lua :lua
local lrucache = require "resty.lrucache"
```
Voir Aussi
- OpenResty : https://openresty.org
- le module ngx_http_lua : https://github.com/openresty/lua-nginx-module
- le module ngx_stream_lua : https://github.com/openresty/stream-lua-nginx-module
- la bibliothèque lua-resty-core : https://github.com/openresty/lua-resty-core
GitHub
Vous pouvez trouver des conseils de configuration supplémentaires et de la documentation pour ce module dans le dépôt GitHub pour nginx-module-lrucache.