每核一线程 Worker
AISIX 网关使用一组 Worker 线程处理流量。两个启动设置控制该线程池:proxy.workers 设置处理流量的 Worker 线程数,proxy.thread_per_core 决定这些 Worker 如何共享代理监听器和上游连接。本页介绍这两个设置及其默认值,说明如何验证正在运行的网关使用哪种模式,并介绍独立 Worker 服务模式带来的行为。
了解服务模式
在每核一线程服务模式下,每个 Worker 都是独立线程,拥有自己的运行时、proxy.addr 监听器和上游连接池。Worker 通过 SO_REUSEPORT Socket 选项共享代理地址,内核根据连接的地址和端口进行哈希,将每个新客户端连接分配给一个 Worker。请求随后由单个线程接受、处理和响应,其发起的上游调用也始终在该线程上执行。
当 proxy.thread_per_core: false 时,网关改用一个共享运行时:单个监听器接受连接,Worker 线程通过工作窃取在彼此之间平衡任务。请求在处理过程中可能在线程之间迁移,例如上游响应到达的线程与请求发起线程不同时。每次迁移都会产生一次线程唤醒和上下文切换。每核一线程服务模式让请求从头到尾留在同一线程上,因此不会发生这些交接。
每核一线程服务模式在 Linux 上默认启用,在其他平台上默认关闭,因为它依赖 Linux 内核的连接分配行为。在该模式的验证基准中,与共享运行时相比,它在使用 4 个 Worker 的 x86 虚拟机上每秒处理的请求数提高了 54–88%,在 Arm(AWS Graviton)硬件上提高了 28–42%。两种平台在负载下的 p99 延迟均大约减半。差异体现在网关吞吐能力上;无论使用哪种模式,模型服务提供方延迟都在端到端请求时间中占主导地位。
配置 Worker 池
这两个设置都位于启动配置的 proxy 块中:
proxy:
addr: "0.0.0.0:3000"
thread_per_core: true
workers: 4
| 字段 | 默认值 | 说明 |
|---|---|---|
proxy.thread_per_core | Linux 上为 true,其他平台为 false | 使用各自具有监听器和上游连接池的独立 Worker 提供服务。设置为 false 可在任何平台上改用单个共享运行时。 |
proxy.workers | 进程可用的并行度 | 在任一模式下处理流量的 Worker 线程数。最小值为 1。 |
这两个设置都只在进程启动时读取一次。更改任一设置都会在网关下次重启时生效。
大多数部署无需设置 proxy.workers。默认值会跟随进程实际可用的并行度,因此容器 CPU limit、cgroup 配额或 taskset CPU 亲和性掩码都可以确定线程池大小,无需在配置中重复声明数量。即使主机有 16 个 CPU 核心,限制为 4 vCPU 的网关也会启动 4 个 Worker。只有当网关应使用少于其可运行线程数的线程时 才显式设置,例如网关需要与 Sidecar 共享 CPU 配额时。
AISIX 会在启动时拒绝 proxy.workers: 0,因为零个 Worker 不会绑定任何监听器。请省略该字段以使用默认值。
这两个字段都遵循标准环境变量覆盖形式,嵌套字段名之间使用双下划线:
export AISIX_PROXY__THREAD_PER_CORE=false
export AISIX_PROXY__WORKERS=8
通过环境变量注入全部启动配置的部署(例如 Kubernetes 安装)会以这种方式设置字段。有关覆盖机制,请参阅环境变量。
验证当前模式
无需专用端点即可查看服务模式。
启动时,处于每核一线程模式的网关会为每个 Worker 记录一 行 aisix listening (http, thread-per-core) 日志,每行都包含其 Worker 索引;如果代理监听器终止 TLS,则记录 (https, thread-per-core)。共享运行时只记录一行 aisix listening (http)。
在运行中的进程上列出其线程:
ps -T -p "$(pgrep -x aisix)"
在每核一线程模式下,Worker 线程命名为 tpc-0 至 tpc-<N-1>,每个 Worker 对应一个线程:
PID SPID TTY TIME CMD
23110 23110 ? 00:00:00 aisix
23110 23111 ? 00:00:00 tokio-runtime-w
23110 23112 ? 00:00:00 tokio-runtime-w
23110 23115 ? 00:00:41 tpc-0
23110 23116 ? 00:00:40 tpc-1
23110 23117 ? 00:00:41 tpc-2
23110 23118 ? 00:00:39 tpc-3
在此模式下,一个小型控制运行时负责指标监听器、信号处理和后台导出工作。它的 tokio-runtime-w 线程会与 Worker 一同显示,但不计入 proxy.workers。当 thread_per_core: false 时,不会出现 tpc- 线程,所有服务线程都使用默认运行时线程名 tokio-runtime-w。
考虑各 Worker 的连接池
在每核一线程服务模式下,每个 Worker 都维护自己的上游主机连接池。池化连接绝不会在 Worker 之间移交:持有某个模型服务提供方空闲连接的 Worker 会复用该连接,没有连接的 Worker 则会自行建立连接。
这会带来两个容量规划影响:
upstream.pool_max_idle_per_host对每个 Worker 分别生效。一个具有 8 个 Worker 且pool_max_idle_per_host: 32的网关,对单个模型服务提供方主机最多可保留 256 个空闲连接。如果要限制整个进程的连接总数,请用预期总数除以 Worker 数量。- 进程持有的空闲上游连接数会随 Worker 数量增加。当模型服务提供方、NAT 网关或企业出站代理限制每个客户端的连接数时,需要将这一点计入规划。
连接池超时的含义保持不变;有关这些连接池设置,请参阅调优上游连接层。
规划低并发流量
内核在 Worker 之间分配的是客户端连接,而不是单个请求。连接数量较多时分配会比较均匀,数量较少时则可能不均匀。当每个 Worker 对应的客户端连接少于约 4 个 时,一些 Worker 可能空闲,而其他 Worker 同时承载多个连接。在这种情况下,吞吐量可能低于共享运行时,因为共享运行时平衡的是单个请求,而不是连接。
关键是网关自身接受的连接数,而不是终端客户端数量。来自大量客户端的直接流量会远高于该阈值。不过,按照网络与安全的建议,在网关面向调用方的端口前部署 L7 负载均衡器或 Ingress 时,前置层可能把许多客户端请求汇聚到少量面向网关的连接上。只使用少量长连接驱动网关的基准测试也属于同一情况:用 8 个连接测试具有 8 个 Worker 的网关,测量的是连接分配情况,而不是网关容量。
如果网关只通过少量长连接接收流量,请增加前置层到网关的连接数,或减少 proxy.workers,确保每个 Worker 仍能收到多个连接,也可以设置 proxy.thread_per_core: false。
了解监听器共享
每核一线程 Worker 通过 SO_REUSEPORT Socket 选项共享一个代理地址。运维或审计网关主机时,需要了解该选项的两个特性。
端口冲突仍会在启动时明确失败。 网关在绑定各 Worker 监听器之前,会先使用普通绑定探测地址。因此,如果另一个进程(包括第二个网关)占用了该地址,网关会在启动时失败,与使用单监听器的进程完全相同。该探测存在一个理论上的间隙:同时启动的两个网关可能都通过探测并绑定同一地址。编排器执行的顺序重启不会遇到该窗口;请避免刻意让两个网关同时在同一地址上启动。
网关运行时,同一用户的进程可以加入监听器。 网关提供服务期间,以相同有效用户 ID 运行且自身设置了 SO_REUSEPORT 的任何进程,都可以绑定代理地址并接收一部分新连接。内核只允许相同有效用户 ID 的进程加入,因此这不是跨用户风险。不过,审计网关主机上运行的进程时需要记住此模式特性:如果某些连接看起来绕过了网关,请检查是否有其他进程绑定代理端口,例如使用 ss -tlpn。