前端开发之动态管理Nginx集群的方法( 五 )
upstreams = require("apisix.admin.upstreams"),
consumers = require("apisix.admin.consumers"),
schema = require("apisix.admin.schema"),
ssl = require("apisix.admin.ssl"),
plugins = require("apisix.admin.plugins"),
proto = require("apisix.admin.proto"),
global_rules = require("apisix.admin.global_rules"),
stream_routes = require("apisix.admin.stream_routes"),
plugin_metadata = https://www.isolves.com/it/cxkf/qd/2022-01-14/require("apisix.admin.plugin_metadata"),
plugin_configs = require("apisix.admin.plugin_config"),
}
因此,上面的 curl 请求将被/apisix/admin/upstreams.lua 文件的 put 函数处理,看下 put 函数的实现:
-- /apisix/admin/upstreams.lua文件
function _M.put(id, conf)
-- 校验请求数据的合法性
local id, err = check_conf(id, conf, true)
local key = "/upstreams/" .. id
core.log.info("key: ", key)
-- 生成etcd中的配置数据
local ok, err = utils.inject_conf_with_prev_conf("upstream", key, conf)
-- 写入etcd
local res, err = core.etcd.set(key, conf)
end
-- /apisix/core/etcd.lua
local function set(key, value, ttl)
local res, err = etcd_cli:set(prefix .. key, value, {prev_kv = true, lease = data.body.ID})
end
最终新配置被写入 etcd 中 。可见,Nginx 会校验数据再写入 etcd,这样其他 Worker 进程、Nginx 节点都将通过 watch 机制接收到正确的配置 。上述流程你可以通过 error.log 中的日志验证:
2021/08/03 17:15:28 [info] 16437#16437: *23572 [lua] upstreams.lua:72: key: /upstreams/1, client: 127.0.0.1, server: _, request: "PUT /apisix/admin/upstreams/1 HTTP/1.1", host: "127.0.0.1:9080"
为什么新配置不 reload 就可以生效?我们再来看 admin 请求执行完 Nginx Worker 进程可以立刻生效的原理 。
开源版 Nginx 的请求匹配是基于 3 种不同的容器进行的:
- 将静态哈希表中的 server_name 配置与请求的 Host 域名匹配;
- 其次将静态 Trie 前缀树中的 location 配置与请求的 URI 匹配;

文章插图
3.在上述 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 代码就会重建这棵基数树:
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 启用、参数及顺序调整的规则与此类似 。
最后再提下 Script,它与 Plugin 是互斥的 。之前的动态调整改的只是配置,事实上 Lua JIT 的及时编译还提供了另外一个杀手锏 loadstring,它可以将字符串转换为 Lua 代码 。因此,在 etcd 中存储 Lua 代码并设置为 Script 后,就可以将其传送到 Nginx 上处理请求了 。
小结Nginx 集群的管理必须依赖中心化配置组件,而高可靠又具备 watch 推送机制的 etcd 无疑是最合适的选择!虽然当下 Resty 生态没有 gRPC 客户端,但每个 Worker 进程直接通过 HTTP/1.1 协议同步 etcd 配置仍不失为一个好的方案 。
动态修改 Nginx 配置的关键在于 2 点:Lua 语言的灵活度远高于 nginx.conf 语法,而且 Lua 代码可以通过 loadstring 从外部数据中导入!当然,为了保障路由匹配的执行效率,APISIX 通过 C 语言实现了前缀基数树,基于 Host、Method、URI 进行请求匹配,在保障动态性的基础上提升了性能 。
文章来源:云原生实验室
推荐阅读:
前端开发之Nginx单页加载优化
web开发基础篇之Nginx的安装与启动
linux下Nginx的安装方法与介绍
前端开发框架Vue之findIndex() 的使用
推荐阅读
- win7开机后无法进入系统的处理
- 如何更改电脑的开机密码
- 孩子多大分房睡比较好
- 怎么查询被开通手机号?
- 电脑系统win10忘记开机密码强制重置教程
- 电脑没声音怎么办?电脑没声音了怎么恢复?
- 5 个网站将您的前端技能提升 100 倍
- 红茶中的生物碱,历史上最早的红茶
- 西安全运会开始和结束时间是多久?
- 客服|南宁一公司全是美女,都开奔驰奥迪,警方一查真相不堪入目