APISIX 工作原理
本文介绍 APISIX 的主要组件如何协同处理请求,包括配置存储、路由器、插件引擎、请求生命周期和热更新模型。
文末的相关资源可帮助你进一步了解各主题。
概览
APISIX 是一个运行在 OpenResty 中的 Lua 应用。OpenResty 通过 lua-nginx-module 扩展 NGINX。NGINX 负责连接处理、工作进程模型和请求阶段机制;APISIX 通过挂载到各个阶段的 Lua 程序完成路由、插件执行和上游选择。
本页从请求流角度说明 APISIX。所有由 APISIX 处理的请求都会经过三个运行时组件:
- 提供路由和插件定义的配置存储。
- 将请求匹配到路由的路由器。
- 在对应 NGINX 阶段运行匹配路由插件的插件引擎。
以下各节先介绍这些组件,再跟踪一个请求如何依次经过它们。负载均衡、服务发现和 Admin API 等其他组件会在请求流中的相关位置提及,并在各自页面中详细介绍。
下图展示默认传统部署模式中的请求流和配置流,其中 etcd 是配置来源。路由器、插件引擎、负载均衡器和内存配置均位于 APISIX 工作进程内:
独立部署模式保留相同的请求路径,但配置来源不同:磁盘上的 apisix.yaml(或 apisix.json)是配置来源,文件更改时各工作进程会重新加载配置:
配置存储
在默认部署模式中,APISIX 使用 etcd 作为路由、上游、服务、消费者、SSL 证书、插件配置和全局规则的事实来源。每个 NGINX 工作进程通过长轮询订阅 etcd, 并在内存中保存一份配置副本。
通过 Admin API 创建或更新资源时,更改会写入 etcd。工作进程通过 watch 机制观察更改,并独立重建内存中的路由结构,不需要重新加载、重启或跨工作进程协调。配置更改会应用到运行中的工作进程,不会中断现有连接。
APISIX 支持两种采用不同配置来源的部署模式:
- 传统模式(默认):etcd 是配置的事实来源,每个工作进程都会 watch etcd,即上图所示模式。
- 独立部署模式:每个工作进程完全在内存中保存配置。配置从磁盘上的
apisix.yaml(或apisix.json)加载,并在文件更改时重新加载,不使用 etcd。
本页其余部分介绍的请求处理行为在所有模式中相同,区别仅在于配置来源。有关支持的完整模式列表和配置方式,请参阅部署模式。
路由器
路由器将传入请求匹配到路由。APISIX 使用 Radix Tree(压缩前缀树)作为匹配引擎。
配置路由时,路由会被插入树中。处理请求时,URI 的匹配时间与 URI 长度相关,而不是与已配置的路由数量相关。因此,即使路由数量增加,匹配开销也大致保持不变。
APISIX 内置三种 HTTP 路由器,它们使用不同的字段作为树的主索引:
radixtree_host_uri(默认):使用host + uri作为主索引,同时匹配请求 Host 和 URI。radixtree_uri:仅使用uri作为主索引,Host 不属于索引。radixtree_uri_with_parameter:与radixtree_uri相同,同时支持/user/:id之类的路径参数。
当前使用的 HTTP 路由器通过 config.yaml 中的 apisix.router.http 配置选择。TLS 握手期间的 SSL 证书选择使用独立的 radixtree_sni 路由器,将客户端 SNI 与已配置的证书匹配。有关 HTTP 路由器的配置和功能对比,请参阅路由选项。
插件引擎
路由器确定匹配路由后,插件引擎会运行适用于该请求的插件。待运行的插件集合来自:
- 匹配的路由。
- 路由关联的服务(如果有)。
- 匹配的消费者和消费者组(如果有)。
- 任何全局规则。
在每个 NGINX 阶段,引擎按照插件的 priority 字段排序(值越大越先执行),并依次调用各插件对应的阶段函数。插件可以修改请求或响应,也可以提前终止请求。例如,身份认证插件可以在请求到达上游前返回 401。
插件会定义一个或多个阶段函数。HTTP 流量会经过 rewrite、access、before_proxy、header_filter、body_filter 和 log 阶段。
大多数插件以 Lua 模块形式提供。APISIX 还支持通过外部插件运行器执行 Go、Java 和 Python 插件,并通过 WASM 运行器支持 WebAssembly 模块。有关阶段模型,以及如何组合路由、服务和消费者上的插件配置,请参阅插件。
请求生命周期
下表按照 NGINX 阶段展示 APISIX 如何处理单个 HTTP 请求:
| 阶段 | APISIX 会做什么 |
|---|---|
ssl_client_hello / ssl_certificate | 使用客户端的 SNI 值,从 radixtree_sni 路由器中选择证书。 |
access | 使用 HTTP 路由器匹配请求并确定路由,然后按优先级运行该路由在 rewrite 和 access 阶段的插件。插件可以在此提前终止请求,例如身份认证插件可直接返回 401。选定上游后,系统会在 NGINX 将请求转发到上游之前运行 before_proxy 阶段的插件。 |
balancer | 根据配置的负载均衡算法以及可选的主动健康检查状态,从路由的上游定义中选择一个上游节点。 |
header_filter | 在 NGINX 组装响应头时运行响应头处理插件。 |
body_filter | 在响应体以流式方式返回客户端时运行响应体处理插件。 |
log | 响应发送完成后运行日志插件。大多数日志插件使用 NGINX 定时器,因此客户端无需等待日志写入完成。 |
下图展示 APISIX 对单个 HTTP 请求执行路由、插件阶段、上游选择和代理的顺序:
Stream(四层)流量遵循类似但更精简的生命周期:
| 阶段 | APISIX 会做什么 |
|---|---|
preread | 根据流路由器匹配连接以识别路由,然后运行路由的preread和before_proxy插件. 插件可能在此关闭连接 。 |
balancer | 从路由的上游定义中选择一个单一的上游节点,使用配置的负载平衡算法,并选择主动健康检查状态. |
log | 连接关闭后运行日志插件 。 |
热配置更新
每个工作进程都在内存中保存自己的配置副本,并从配置来源刷新。因此,应用配置变更时无需重新加载 NGINX、重启工作进程,也无需在工作进程之间进行协调。
在默认传统模式中,通过 Admin API 所做的更改会写入 etcd,并在各工作进程的下一个 watch 周期中获取,无需单独的应用步骤。在独立部署模式中,apisix.yaml(或 apisix.json)更改时也会自动应用。
额外资源
- 核心概念:路由、上游、插件、Stream Route
- 参考:路由选项