热更新-动态reload机制
转载自 https://www.sohu.com/a/516320573_121126896
为什么新配置不 reload 就可以生效?
apisix可以通过内部的 的/apisix/admin/接口修改配置,请求执行完 Nginx Worker 进程可以立刻生效
开源版 Nginx 的请求匹配是基于 3 种不同的容器进行的:
-
将静态哈希表中的 server_name 配置与请求的 Host 域名匹配;
-
其次将静态 Trie 前缀树中的 location 配置与请求的 URI 匹配;
-
在上述 2 个过程中,如果含有正则表达式,则基于数组顺序(在 nginx.conf 中出现的次序)依次匹配。
上述过程虽然执行效率极高,却是写死在 find_config 阶段及 Nginx HTTP 框架中的,**一旦变更必须在 nginx -s reload 后才能生效!**因此,APISIX 索性完全抛弃了上述流程!
从 nginx.conf 中可以看到,访问任意域名、URI 的请求都会匹配到 http_access_phase 这个 lua 函数:
server {
server_name _;
location / {
access_by_lua_block {
apisix.http_access_phase()
}
proxy_pass $upstream_scheme://apisix_backend$upstream_uri;
}
}
而在 http_access_phase 函数中,将会基于 1 个用 C 语言实现的基数前缀树匹配 Method、域名和 URI(仅支持通配符,不支持正则表达式),这个库就是lua-resty-radixtree。每当路由规则发生变化,Lua 代码就会重建这棵基数树:
备注:第一次建立基数前缀树 在http_init_work函数阶段
function _M.match(api_ctx)
if not cached_version or cached_version ~= user_routes.conf_version then
uri_router = base_router.create_radixtree_uri_router(user_routes.values,
uri_routes, false)
cached_version = user_routes.conf_version
end
end
这样,路由变化后就可以不 reload 而使其生效。Plugin 启用、参数及顺序调整的规则与此类似。
小结
动态修改 Nginx 配置的关键在于 2 点:Lua 语言的灵活度远高于 nginx.conf 语法,而且 Lua 代码可以通过 loadstring 从外部数据中导入!当然,为了保障路由匹配的执行效率,APISIX 通过 C 语言实现了前缀基数树,基于 Host、Method、URI 进行请求匹配,在保障动态性的基础上提升了性能。