Aller au contenu

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,

  1. utilisez une version officielle d'OpenResty ou suivez les instructions d'Installation.
  2. utilisez require pour 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

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.