radixtree: Адаптивные Radix-деревья, реализованные на Lua / LuaJIT
Установка
Если вы еще не настроили подписку на RPM-репозиторий, зарегистрируйтесь. Затем вы можете продолжить с следующими шагами.
CentOS/RHEL 7 или 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
Чтобы использовать эту библиотеку Lua с NGINX, убедитесь, что nginx-module-lua установлен.
Этот документ описывает lua-resty-radixtree v2.9.2, выпущенную 28 ноября 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 = {}
}
-- соответствует первому маршруту
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 = {}
}
-- соответствует второму маршруту
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 = {}
}
-- соответствует третьему маршруту
ngx.say(rx:match("/admin/jane", opts)) -- metadata /admin/name
ngx.say("admin name: ", opts.matched.name) -- admin name: jane
}
}
Методы
new
Создает новое radix-дерево для хранения маршрутов.
Использование
rx, err = radix.new(routes, opts)
Атрибуты
routes — это массив ({ {...}, {...}, {...} }), где каждый элемент является маршрутом.
Каждый маршрут может иметь следующие атрибуты:
| Имя | Обязательно? | Описание | Пример |
|---|---|---|---|
| paths | Обязательно | Список путей запросов для сопоставления маршрута. По умолчанию выполняется полное сопоставление. Добавление * в конце приведет к сопоставлению по префиксу. Например, /foo* может соответствовать запросам с путями /foo/bar и /foo/car/far. |
{"/", "/foo", "/bar/*"} |
| hosts | Необязательно | Список адресов хостов для сопоставления маршрута. Поддерживает подстановочные знаки. Например, *.bar.com может соответствовать foo.bar.com и car.bar.com. |
{"foo.com", "*.bar.com"} |
| remote_addrs | Необязательно | Список удаленных адресов (IPv4 или IPv6) для сопоставления маршрута. Поддерживает формат CIDR. | {"127.0.0.1", "192.0.0.0/8", "::1", "fe80::/32"} |
| methods | Необязательно | Список HTTP-методов для сопоставления маршрута. Допустимые значения: "GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "CONNECT" и "TRACE". | {"GET", "POST"} |
| vars | Необязательно | DSL для оценки с предоставленными opts.vars или ngx.var. См.: lua-resty-expr. |
{{"arg_name", "==", "json"}, {"arg_age", ">", 18}} |
| filter_fun | Необязательно | Пользовательская функция фильтра для сопоставления маршрута. Может использоваться для пользовательских сценариев сопоставления. vars и opts будут переданы функции при сопоставлении маршрута. |
function(vars) return vars["arg_name"] == "json" end |
| priority | Необязательно | Приоритет маршрута. По умолчанию 0. | priority = 100 |
| metadata | Необязательно | metadata будет возвращен, когда маршрут соответствует при использовании rx:match. |
|
| handler | Необязательно | Функция handler будет вызвана, когда маршрут соответствует при использовании rx:dispatch. |
opts — это необязательная конфигурация, которая контролирует поведение сопоставления. Она может иметь следующий атрибут:
| Имя | Описание | По умолчанию |
|---|---|---|
| no_param_match | Отключает Параметры в пути. | false |
match
Сопоставляет запрос клиента с маршрутами и возвращает metadata, если успешно.
Использование
metadata = rx:match(path, opts)
Атрибуты
path — это путь запроса клиента. Например, "/foo/bar", /user/john/send.
opts — это необязательный атрибут и таблица. Она может иметь следующие атрибуты:
| Имя | Обязательно? | Описание |
|---|---|---|
| method | Необязательно | HTTP-метод запроса клиента. |
| host | Необязательно | Адрес хоста запроса клиента. |
| remote_addr | Необязательно | Удаленный адрес (IPv4 или IPv6) клиента. Поддерживает формат CIDR. |
| paths | Необязательно | Список путей запросов клиента. |
| vars | Необязательно | Таблица для получения переменных. По умолчанию ngx.var для получения встроенных переменных Nginx. |
dispatch
Сопоставляет запросы клиента с маршрутами и вызывает функцию handler, если успешно.
Использование
ok = rx:dispatch(path, opts, ...)
Атрибуты
path — это путь запроса клиента. Например, "/api/metrics", /admin/john/login.
opts — это необязательный атрибут и таблица. Она может иметь следующие атрибуты:
| Имя | Обязательно? | Описание |
|---|---|---|
| method | Необязательно | HTTP-метод запроса клиента. |
| host | Необязательно | Адрес хоста запроса клиента. |
| remote_addr | Необязательно | Удаленный адрес (IPv4 или IPv6) клиента. Поддерживает формат CIDR. |
| paths | Необязательно | Список путей запросов клиента. |
| vars | Необязательно | Таблица для получения переменных. По умолчанию ngx.var для получения встроенных переменных Nginx. |
Примеры
Полное сопоставление пути
Сопоставление полных путей с несколькими указанными путями:
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",
},
})
Сопоставление по префиксу
Сопоставление на основе префикса с несколькими указанными путями:
local rx = radix.new({
{
paths = {"/foo/*", "/bar/car/*"}, -- соответствует `/foo/boo`, `/bar/car/sar/far` и т.д.
metadata = "metadata /foo",
},
{
paths = {"/example/*"}, -- соответствует `/example/boo`, `/example/car/sar/far` и т.д.
metadata = "metadata /example",
},
})
Параметры в пути
Вы можете указать параметры в пути. Эти параметры затем можно динамически получить из opts.matched.parameter-name:
local rx = radix.new({
{
-- соответствует `/user/john`, но не `/user/` или `/user`
paths = {"/user/:user"}, -- для `/user/john`, `opts.matched.user` будет `john`
metadata = "metadata /user",
},
{
-- Но это будет соответствовать `/user/john/` и также `/user/john/send`
paths = {"/user/:user/*action"}, -- для `/user/john/send`, `opts.matched.user` будет `john`, а `opts.matched.action` будет `send`
metadata = "metadata action",
},
})
Разработка
Чтобы установить зависимости, выполните:
make deps
Бенчмарки
Это простые бенчмарки.
Среда: MacBook Pro (16 дюймов, 2019), CPU 2.3 GHz Intel Core i9.
Чтобы начать бенчмаркинг, выполните:
make
make bench
Результаты:
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
Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-radixtree.