lua-resty-radixtree

opm 包 => 基于 FFI 的 rax Lua 实现库。

$ opm get xiangnanscu/lua-resty-radixtree

用于 openresty 默认安装

    make && INST_PREFIX=/usr/local/openresty/luajit make install

名称

这是一个基于 FFI 的 rax Lua 实现库。

[!构建状态](https://travis-ci.org/iresty/lua-resty-radixtree) [!许可证](https://github.com/iresty/lua-resty-radixtree/blob/master/LICENSE)

此项目依赖于 lua-resty-ipmatcherlua-resty-expr

此项目已在微服务 API 网关 Apache APISIX 中使用。

该项目由 深圳市智柳科技有限公司 开源。

除了这个开源版本外,我们公司还提供更强大和高效的商业版本,并提供技术支持。如果您对我们的商业版本感兴趣,请联系 我们

概要

     location / {
         content_by_lua_block {
            local radix = require("resty.radixtree")
            local rx = radix.new({
                {
                    paths = {"/aa", "/bb*", "/name/:name/*other"},
                    hosts = {"*.bar.com", "foo.com"},
                    methods = {"GET", "POST", "PUT"},
                    remote_addrs = {"127.0.0.1","192.168.0.0/16",
                                    "::1", "fe80::/32"},
                    vars = {
                        {"arg_name", "==", "json"},
                        {"arg_weight", ">", 10},
                    },
                    filter_fun = function(vars, opts)
                        return vars["arg_name"] == "json"
                    end,
    
                    metadata = "metadata /bb",
                }
            })
    
            -- try to match
            local opts = {
                host = "foo.com",
                method = "GET",
                remote_addr = "127.0.0.1",
                vars = ngx.var,
            }
            ngx.say(rx:match("/aa", opts))
    
            -- try to match and store the cached value
            local opts = {
                host = "foo.com",
                method = "GET",
                remote_addr = "127.0.0.1",
                vars = ngx.var,
                matched = {}
            }
            ngx.say(rx:match("/name/json/foo/bar/gloo", opts))
            ngx.say("name: ", opts.matched.name, " other: ", opts.matched.other)
         }
     }

方法

new

语法: rx, err = radix.new(routes, opts)

routes 是一个数组表,例如 { {...}, {...}, {...} },数组中的每个元素都是一条路由,是一个哈希表。

每个元素的属性可能包含以下内容:

|名称 |选项 |描述|示例| |:-------- |:--------|:-----------|:-----| |paths |必需|客户端请求路径列表。默认情况下是完全匹配,但如果路径的末尾是 *,则表示这是一个前缀路径。例如 /foo*,它将匹配 /foo/bar/foo/glo/grey 等|{"/", "/aa", "/bb"}| |hosts |选项 |客户端请求主机列表,不仅支持普通域名,还支持通配符名称。|{"foo.com", "*.bar.com"}| |remote_addrs|选项 |客户端远程地址(IPv4 和 IPv6) 列表,可以使用 CIDR 格式,例如 192.168.1.0/24。|{"127.0.0.1", "192.0.0.0/8", "::1", "fe80::/32"}| |methods |选项 |方法名称列表。以下是完整有效的 方法列表:"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "CONNECT" 和 "TRACE"。|{"GET", "POST"}| |vars |选项 |使用给定的 opts.varsngx.var 来评估的 DSL。请参阅 https://github.com/api7/lua-resty-expr#new |{{"arg_name", "==", "json"}, {"arg_age", ">", 18}}| |filter_fun |选项 |用户定义的过滤器函数,可以用来实现特殊场景的匹配逻辑。radixtree 在匹配路由时会传递 vars 和其他参数。|function(vars) return vars["arg_name"] == "json" end| |priority |选项 |路由优先级,默认为 0。|priority = 100| |metadata |选项 |如果使用 rx:match 来匹配路由,则将返回此字段。|| |handler |选项 |使用 rx:dispatch 来匹配路由时将调用此函数。||

opts 是一个可选的配置,用于控制匹配的行为。支持以下字段:

|名称 |描述|默认值| |:-------- |:-----------|:-----| |no_param_match|禁用 "路径中的参数"|false|

路径

    local rx = radix.new({
        {
            paths = {"/aa", "/bb/cc", "/dd/ee/index.html"},
            metadata = "metadata /aa",
        },
        {
            paths = {"/gg"},
            metadata = "metadata /gg",
        },
        {
            paths = {"/index.html"},
            metadata = "metadata /index.html",
        },
    })

完全路径匹配

完全路径匹配,允许同时指定多个路径。

    local rx = radix.new({
        {
            paths = {"/aa/*", "/bb/cc/*"},
            metadata = "metadata /aa",
        },
        {
            paths = {"/gg/*"},
            metadata = "metadata /gg",
        },
    })

前缀匹配

路径前缀匹配,允许同时指定多个路径。

    local rx = radix.new({
        {
            -- This handler will match /user/john but will not match /user/ or /user
            paths = {"/user/:user"},
            metadata = "metadata /user",
        },
        {
            -- However, this one will match /user/john/ and also /user/john/send/data
            paths = {"/user/:user/*action"},
            metadata = "metadata action",
        },
    })

路径中的参数

match

  • 语法: metadata = rx:match(path, opts)

  • path: 客户端请求路径。

    • opts: 一个 Lua 表 (可选)。

    • method: 可选,客户端请求的方法名称。

    • host: 可选,客户端请求主机。

    • remote_addr: 可选,客户端远程地址,例如 192.168.1.100

    • paths: 可选,客户端请求路径列表。

vars: 可选,一个用于获取变量的 Lua 表,默认值为 ngx.var,用于获取 Nginx 内置变量。

    local metadata = rx:match(ngx.var.uri, {...})

根据 methodpathhost 等匹配路由,如果成功则返回 metadata

dispatch

  • 语法: metadata = rx:match(path, opts)

  • path: 客户端请求路径。

    • opts: 一个 Lua 表 (可选)。

    • method: 可选,客户端请求的方法名称。

    • host: 可选,客户端请求主机。

    • paths: 可选,客户端请求路径列表。

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

    local ok = rx:dispatch(ngx.var.uri, {...})

根据 methodpathhost 等匹配路由,如果成功则调用 handler 函数。

安装

    make install

编译并安装

开发环境

    make deps

安装依赖项

基准测试

    $ make
    cc -O2 -g -Wall -fpic -std=c99 -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -DBUILDING_SO -c src/rax.c -o src/rax.o
    cc -O2 -g -Wall -fpic -std=c99 -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -DBUILDING_SO -c src/easy_rax.c -o src/easy_rax.o
    cc -shared -fvisibility=hidden src/rax.o src/easy_rax.o -o librestyradixtree.so
    
    $ 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

我们编写了一些简单的基准测试脚本。机器环境:MacBook Pro (16 英寸,2019),CPU 2.3 GHz Intel Core i9。

作者

Nan Xiang(@xiangnanscu)

许可证

apache2

依赖项

xiangnanscu/lua-resty-expr, xiangnanscu/lua-resty-ipmatcher