apisix源码分析-初始化过程(3)

apisix源码分析-初始化过程(3)

init

init 对应到 openresty 的 init_by_lua_blockinit_worker_by_lua_block 的阶段

init_by_lua_block 所做的不多,执行 apisix.http_init(args),args 里面传入了 dns_resolver 配置的参数,比如使用docker-compose 启动传入的127.0.0.11 。

1
2
3
4
5
local dns_resolver = { "127.0.0.11", }
local args = {
dns_resolver = dns_resolver,
}
apisix.http_init(args)

在init 过程中:

1
2
3
4
5
6
7
8
9
10
11
12
-- dns 发现设置: args["dns_resolver"]
core.resolver.init_resolver(args)
-- 生成 apisix uuid /conf/apisix.uid
core.id.init()
--https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/process.md#enable_privileged_agent
-- 开启特权进程,可以使用 master 进程权限执行一些功能
local process = require("ngx.process")
local ok, err = process.enable_privileged_agent()

-- 读初始化配置, core/config_etcd.lua 执行 init 判断 etcd 是否可访问。
local ok, err = core.config.init()

init_worker

apisix/init/http_init_worker()

init_worker 阶段执行了所有组件的初始化,也就是对应组件的 init_worker 方法。

比如 admin timers plugin plugin_config route service consumer config upstream ssl。、

这个阶段主要的作用是初始化各个组件。每个组件自身都实现了一个 init_worker 方法,除了自身相关的内容,主要是同步组件自身对应的 etcd 信息。

etcd watch 实现

1
obj, err = core.config.new("/etcd_path", cfg)

比如在 router 的 http_init_worker 阶段,watch 了 /global_rules

1
2
3
4
5
local global_rules, err = core.config.new("/global_rules", {
automatic = true,
item_schema = core.schema.global_rule,
checker = plugin_checker,
})

core.config.new(key,ops)

函数对应的执行在文件 core/config_etcd.lua 中。

> 在 apisix/core.lua 中 local config = require("apisix.core.config_" .. config_center), config_center 来自配置文件,默认为 etcd。 

key 为 etcd 监控的节点,ops 为需要的参数。

当 automatic == true 时 ,会创建 ngx.timer_at , 否则只会初始化 etcd_cli

load_full_data 函数,将 etcd 取回的数据填充到 key 对应的 obj 中(将etcd 数据转换为 lua 对象)

- self.item_scheme 检验数据
- self.checker 对象检查
- 将数据写入 self.value  , self.values_hash[key] 记录对应key的index
- 执行 self.filter

_automatic_fetch 函数,启动 ngx_timer_at 调用函数 _automatic_fetch ,通过自调用形成迭代。

在_automatic_fetch函数中真正执行同步的是 sync_data 函数

sync_data 函数,读取 etcd,并 watch etcd ,将数据写到对象中 。

   self.values :  array 用来存储 etcd 写回的数据


   self.values_hash: hash 用来存储 etcd key 对应的 values 的下标, 在 etcd 中 {/routes/aaa:<data>} 同步到 apisix 的存储 


假设 etcd 有如下 key


`etcd: /routes/aaaa : <data>` 


在self 中存储: 
`self.values = [<data>,...]
self.values_hash= {"/routes/aaa":1}` 

出现修改数据

1
2
insert_tab(self.values, res)
self.values_hash[key] = #self.values

当出现删除数据时

1
2
3
self.sync_times = self.sync_times + 1
self.values[pre_index] = false
self.values_hash[key] = nil

这里出现的 sync_times 是一个计数器,用来记录删除values 数量,当超过 100 的时候,会对 values 里的数据进行重建。

self.conf_version 记录版本变化次数

服务发现

服务发现的 init_worker 会循环调用配置的服务发现。 discovery_type 为配置文件中配置的服务发现。

1
2
3
4
local discovery_type = local_conf.discovery
for discovery_name, _ in pairs(discovery_type) do
discovery[discovery_name].init_worker()
end

我们可以在 discovery 目录找到对应的服务发现的实现。服务发现需要实现两个接口。

1
2
3
4
local _M = {}
function _M.nodes(service_name)
function _M.init_worker()
return _M

为了看分析比较简单,可以查看 discovery/dns.lua 的实现。

init_woker 函数初始化了 dns_client 。

nodes 函数通过 dns 服务发现来获取 service_name 对应的服务。并将返回的内容转换成 apisix 的的格式。

1
2
3
4
5
nodes[i] = {host = r.address, weight = r.weight or 1, port = r.port or port}
if r.priority then
-- for SRV record, nodes with lower priority are chosen first
nodes[i].priority = -r.priority
end

目前 apisix 支持了 consul_kv dns eureka nacos 四种服务发现,如果想要其他的可以自行实现这两个函数来支持业务。

在将upstream 和 route 绑定时会 set_by_route 会触发服务发现的 nodes 函数。

access

apisix 匹配路由是在 access 阶段完成的,功能由 router_http.match(api_ctx) 提供

header_filter

会设置一些 apisix 自定义的 header ,调用 common_phase

body_filter

调用 common_phase

log

调用 common_phase

被动健康检查

释放前面阶段里通过 tablepool 申请的对象 (api_ctx plugins uri_parse_param matched_route_record )

balancer

在access 阶段就计算出了要均衡到的后端,设置并执行 balancer.lua 的 run 函数

apisix源码分析-初始化过程(3)

https://beixiu.net/apisix-source-3/

作者

张巍

发布于

2023-08-18

更新于

2023-08-18

许可协议

评论