Aller au contenu

radixtree: Arbres Radix Adaptatifs implémentés en Lua / LuaJIT

Installation

Si vous n'avez pas encore 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-radixtree

CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023

dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-radixtree

Pour utiliser cette bibliothèque Lua avec NGINX, assurez-vous que nginx-module-lua est installé.

Ce document décrit lua-resty-radixtree v2.9.2 publié le 28 novembre 2024.


location / {
  set $arg_access 'admin';
  content_by_lua_block {
    local radix = require("resty.radixtree")
    local rx = radix.new({
        {
            paths = { "/login/*action" },
            metadata = { "metadata /login/action" },
            methods = { "GET", "POST", "PUT" },
            remote_addrs = { "127.0.0.1", "192.168.0.0/16", "::1", "fe80::/32" }
        },
        {
            paths = { "/user/:name" },
            metadata = { "metadata /user/name" },
            methods = { "GET" },
        },
        {
            paths = { "/admin/:name", "/superuser/:name" },
            metadata = { "metadata /admin/name" },
            methods = { "GET", "POST", "PUT" },
            filter_fun = function(vars, opts)
                return vars["arg_access"] == "admin"
            end
        }
    })

    local opts = {
        method = "POST",
        remote_addr = "127.0.0.1",
        matched = {}
    }

    -- correspond à la première route
    ngx.say(rx:match("/login/update", opts))   -- metadata /login/action
    ngx.say("action: ", opts.matched.action)   -- action: update

    ngx.say(rx:match("/login/register", opts)) -- metadata /login/action
    ngx.say("action: ", opts.matched.action)   -- action: register

    local opts = {
        method = "GET",
        matched = {}
    }

    -- correspond à la deuxième route
    ngx.say(rx:match("/user/john", opts)) -- metadata /user/name
    ngx.say("name: ", opts.matched.name)  -- name: john

    local opts = {
        method = "POST",
        vars = ngx.var,
        matched = {}
    }

    -- correspond à la troisième route
    ngx.say(rx:match("/admin/jane", opts))     -- metadata /admin/name
    ngx.say("admin name: ", opts.matched.name) -- admin name: jane
    }
}

Méthodes

new

Crée un nouvel arbre radix pour stocker les routes.

Utilisation

rx, err = radix.new(routes, opts)

Attributs

routes est un tableau ({ {...}, {...}, {...} }) où chaque élément est une route.

Chaque route peut avoir les attributs suivants :

Nom Requis ? Description Exemple
paths Requis Liste des chemins de requête à faire correspondre à la route. Par défaut, cela fait une correspondance complète. Ajouter * à la fin entraînera une correspondance par préfixe. Par exemple, /foo* peut correspondre aux requêtes avec les chemins /foo/bar et /foo/car/far. {"/", "/foo", "/bar/*"}
hosts Optionnel Liste des adresses hôtes à faire correspondre à la route. Prend en charge les caractères génériques. Par exemple, *.bar.com peut correspondre à foo.bar.com et car.bar.com. {"foo.com", "*.bar.com"}
remote_addrs Optionnel Liste des adresses distantes (IPv4 ou IPv6) à faire correspondre à la route. Prend en charge le format CIDR. {"127.0.0.1", "192.0.0.0/8", "::1", "fe80::/32"}
methods Optionnel Liste des méthodes HTTP à faire correspondre à la route. Valeurs valides : "GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "CONNECT" et "TRACE". {"GET", "POST"}
vars Optionnel DSL à évaluer avec les opts.vars ou ngx.var fournis. Voir : lua-resty-expr. {{"arg_name", "==", "json"}, {"arg_age", ">", 18}}
filter_fun Optionnel Fonction de filtre définie par l'utilisateur pour faire correspondre la route. Peut être utilisée pour des scénarios de correspondance personnalisés. vars et opts seront passés à la fonction lors de la correspondance d'une route. function(vars) return vars["arg_name"] == "json" end
priority Optionnel Priorité de la route. Par défaut, 0. priority = 100
metadata Optionnel metadata sera retourné lorsqu'une route correspond tout en utilisant rx:match.
handler Optionnel La fonction handler sera appelée lorsqu'une route correspond tout en utilisant rx:dispatch.

opts est une configuration optionnelle qui contrôle le comportement d'une correspondance. Elle peut avoir l'attribut suivant :

Nom Description Par défaut
no_param_match Désactive Paramètres dans le chemin. false

match

Fait correspondre la requête client avec les routes et retourne metadata si réussi.

Utilisation

metadata = rx:match(path, opts)

Attributs

path est le chemin de la requête client. Par exemple, "/foo/bar", /user/john/send.

opts est un attribut optionnel et un tableau. Il peut avoir les attributs suivants :

Nom Requis ? Description
method Optionnel Méthode HTTP de la requête client.
host Optionnel Adresse hôte de la requête client.
remote_addr Optionnel Adresse distante (IPv4 ou IPv6) du client. Prend en charge le format CIDR.
paths Optionnel Une liste de chemins de requête client.
vars Optionnel Un tableau pour récupérer des variables. Par défaut, ngx.var pour récupérer les variables intégrées de Nginx.

dispatch

Fait correspondre les requêtes client avec les routes et appelle la fonction handler si réussi.

Utilisation

ok = rx:dispatch(path, opts, ...)

Attributs

path est le chemin de la requête client. Par exemple, "/api/metrics", /admin/john/login.

opts est un attribut optionnel et un tableau. Il peut avoir les attributs suivants :

Nom Requis ? Description
method Optionnel Méthode HTTP de la requête client.
host Optionnel Adresse hôte de la requête client.
remote_addr Optionnel Adresse distante (IPv4 ou IPv6) du client. Prend en charge le format CIDR.
paths Optionnel Une liste de chemins de requête client.
vars Optionnel Un tableau pour récupérer des variables. Par défaut, ngx.var pour récupérer les variables intégrées de Nginx.

Exemples

Correspondance de Chemin Complet

Correspondance de chemins complets avec plusieurs chemins spécifiés :

local rx = radix.new({
    {
        paths = {"/foo", "/bar/car", "/doo/soo/index.html"},
        metadata = "metadata /foo",
    },
    {
        paths = {"/example"},
        metadata = "metadata /example",
    },
    {
        paths = {"/index.html"},
        metadata = "metadata /index.html",
    },
})

Correspondance par Préfixe

Correspondance basée sur le préfixe avec plusieurs chemins spécifiés :

local rx = radix.new({
    {
        paths = {"/foo/*", "/bar/car/*"}, -- correspond avec `/foo/boo`, `/bar/car/sar/far`, etc.
        metadata = "metadata /foo",
    },
    {
        paths = {"/example/*"}, -- correspond avec `/example/boo`, `/example/car/sar/far`, etc.
        metadata = "metadata /example",
    },
})

Paramètres dans le Chemin

Vous pouvez spécifier des paramètres sur un chemin. Ceux-ci peuvent ensuite être obtenus dynamiquement à partir de opts.matched.parameter-name :

local rx = radix.new({
    {
        -- correspond avec `/user/john` mais pas `/user/` ou `/user`
        paths = {"/user/:user"}, -- pour `/user/john`, `opts.matched.user` sera `john`
        metadata = "metadata /user",
    },
    {
        -- Mais cela correspondra à `/user/john/` et aussi `/user/john/send`
        paths = {"/user/:user/*action"}, -- pour `/user/john/send`, `opts.matched.user` sera `john` et `opts.matched.action` sera `send`
        metadata = "metadata action",
    },
})

Développement

Pour installer les dépendances, exécutez :

make deps

Benchmarks

Ce sont des benchmarks simples.

Environnement : MacBook Pro (16 pouces, 2019), CPU 2.3 GHz Intel Core i9.

Pour commencer les benchmarks, exécutez :

make
make bench

Résultats :

resty -I=./lib -I=./deps/share/lua/5.1 benchmark/match-parameter.lua
matched res: 1
route count: 100000
match times: 10000000
time used  : 3.1400001049042 sec
QPS        : 3184713
each time  : 0.31400001049042 ns

resty -I=./lib -I=./deps/share/lua/5.1 benchmark/match-prefix.lua
matched res: 500
route count: 100000
match times: 1000000
time used  : 0.42700004577637 sec
QPS        : 2341920

resty -I=./lib -I=./deps/share/lua/5.1 benchmark/match-static.lua
matched res: 500
route count: 100000
match times: 10000000
time used  : 0.95000004768372 sec
QPS        : 10526315

resty -I=./lib -I=./deps/share/lua/5.1 benchmark/match-hosts.lua
matched res: 500
route count: 1000
match times: 100000
time used  : 0.60199999809265 sec
QPS        : 166112

resty -I=./lib -I=./deps/share/lua/5.1 benchmark/match-wildcard-hosts.lua
matched res: 500
route count: 1000
match times: 50000
time used  : 0.47900009155273 sec
QPS        : 104384

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-radixtree.