Apache APISIX 从入门到原理:架构、路由、插件与生产实践

Apache APISIX 是建立在 NGINX、OpenResty 与 LuaJIT 之上的动态 API Gateway。它并不只是把请求从入口转发到后端,而是把路由、认证、限流、负载均衡、服务发现、灰度发布、缓存、可观测性等横切能力集中到流量入口统一治理。

本文从可运行的安装与 Admin API 实践出发,进一步拆解 APISIX 的数据面、控制面、etcd 动态配置、RadixTree 路由、Upstream 负载均衡、插件生命周期、服务发现、Standalone 与 Kubernetes 部署等内部机制,并补充生产环境安全、性能、版本差异与故障排查方法。

APISIX 到底解决什么问题

在单体应用中,一个 Nginx 配置可能就足够:

1
2
3
4
5
6
7
8
Client
|
v
Nginx
|
+----> Web
|
+----> API

但进入微服务以后,一个请求可能面对几十甚至几百个服务:

1
2
3
4
5
/api/order/*
/api/user/*
/api/product/*
/api/payment/*
/api/inventory/*

每个服务又可能存在多个实例:

1
2
3
4
order-service
├── 10.0.1.11:8080
├── 10.0.1.12:8080
└── 10.0.1.13:8080

同时还会出现大量与业务无关、却必须统一解决的问题:

  • API 应该转发到哪个服务;
  • 一个服务的多个实例如何负载均衡;
  • 服务实例扩缩容后如何动态发现;
  • API 是否需要登录;
  • 哪些 Consumer 可以访问;
  • 一个 IP 每秒允许访问多少次;
  • 下游异常时是否熔断;
  • 新版本如何只放 5% 流量;
  • 是否需要修改请求头;
  • 是否需要缓存上游响应;
  • 如何记录日志、Metrics 和 Trace;
  • HTTPS 证书如何统一管理;
  • 配置变化后能不能立即生效。

如果把这些逻辑全部写进业务服务,就会形成:

1
2
3
4
5
6
7
8
9
Order Service
├── Authentication
├── Rate Limit
├── Retry
├── Circuit Breaker
├── Logging
├── Tracing
├── Header Rewrite
└── Order Business Logic

而真正属于订单服务的,其实只有最后一项。

API Gateway 的核心价值,就是把这些与流量有关、但与业务领域逻辑无关的能力从业务服务中抽离出来

Apache APISIX 是 Apache 顶级项目,官方将其定位为动态、实时、高性能的 API Gateway。当前官方稳定文档版本为 APISIX 3.17.0,发布时间为 2026 年 6 月 15 日。

从系统架构角度,可以把 APISIX 看成:

1
2
3
4
5
6
7
8
9
10
11
动态反向代理
+
API 路由系统
+
负载均衡器
+
流量治理平台
+
插件运行时
+
API 控制面

所以它并不是单纯的“Nginx 管理页面”。


建立 APISIX 的整体心智模型

先不要急着记 Route、Service、Upstream 等对象,先看完整系统。

flowchart LR
    Client[Client / App / Browser]

    subgraph Gateway["APISIX Data Plane"]
        Nginx[NGINX / OpenResty]
        Router[Route Matcher<br/>libradixtree]
        Plugins[Plugin Engine]
        Balancer[Load Balancer]
    end

    Admin[Admin API]
    UI[Dashboard]
    Controller[Ingress Controller / ADC]
    ETCD[(etcd)]

    Registry[Service Registry<br/>Nacos / Consul / Kubernetes / Eureka]

    U1[Upstream A]
    U2[Upstream B]
    U3[Upstream C]

    OBS[Prometheus / Logs / Tracing]

    Client --> Nginx
    Nginx --> Router
    Router --> Plugins
    Plugins --> Balancer

    Balancer --> U1
    Balancer --> U2
    Balancer --> U3

    Admin --> ETCD
    UI --> Admin
    Controller --> Admin

    ETCD -->|watch config changes| Gateway
    Registry -->|service discovery| Gateway

    Gateway --> OBS

这里有几个非常重要的边界。

数据面 Data Plane

真正处理用户请求的是 APISIX Data Plane:

1
2
3
4
5
Client

APISIX

Upstream

用户的每个 HTTP 请求都会经过这里。

它负责:

  • 接收连接;
  • TLS;
  • Route 匹配;
  • Plugin 执行;
  • Upstream 选择;
  • 负载均衡;
  • 请求转发;
  • 响应处理。

APISIX 的数据面建立在 NGINX、ngx_lua/OpenResty 和 LuaJIT 之上。NGINX 负责成熟、高性能的网络代理能力,Lua 层则承担动态路由、插件、配置等控制逻辑。

控制面 Control Plane

控制面的任务不是代理业务请求,而是管理配置:

1
2
3
4
5
6
7
Route
Upstream
Service
Plugin
Consumer
SSL
...

例如:

1
PUT /apisix/admin/routes/100

本质上是在告诉 APISIX:

从现在开始,请按照这条规则处理后续请求。

etcd

在默认的 Traditional / Decoupled 等模式下,etcd 是 APISIX 的配置存储与同步中心。

里面保存的是:

1
2
3
4
5
6
7
8
9
Route
Service
Upstream
Consumer
Credential
PluginConfig
SSL
GlobalRule
...

APISIX Worker 通过 etcd Watch 感知这些配置变化,然后更新自身内存中的配置。etcd 因而不需要出现在每个用户请求的数据路径上。

Service Registry

服务注册中心和 etcd 不要混为一谈。

例如:

1
etcd

可能负责保存:

1
Route / Plugin / Upstream 配置

而:

1
2
3
4
Nacos
Consul
Eureka
Kubernetes

负责告诉 APISIX:

1
order-service 当前有哪些实例?

也就是:

1
2
3
配置中心

服务注册中心

即使某些组件理论上可以同时承担两种职责,在 APISIX 架构里也应该先把这两个概念分开理解。


为什么 APISIX 选择 NGINX + OpenResty + Lua

理解 APISIX 最关键的问题不是:

Route 怎么配置?

而是:

为什么已经有 Nginx 了,还需要 APISIX?

答案藏在“动态”两个字里。

原生 Nginx 的典型工作方式

传统 Nginx 配置类似:

1
2
3
4
5
6
7
location /api/order/ {
proxy_pass http://order_service;
}

location /api/user/ {
proxy_pass http://user_service;
}

修改以后通常需要:

1
nginx -s reload

这对于几十条静态规则完全没有问题。

但如果有:

1
2
3
4
5
6
10000 Routes
频繁服务上线
服务自动扩缩容
动态灰度
动态限流
动态证书

事情就不同了。

如果每次修改 Route 都生成一次新的:

1
nginx.conf

然后 Reload:

1
2
3
4
5
6
7
Config Change

Generate nginx.conf

nginx reload

Worker replacement

API Gateway 的动态配置能力就会受到 Nginx 静态配置模型限制。

APISIX 的做法

APISIX 不把每条 API Route 都直接写成一个 Nginx location

更接近:

1
2
3
4
5
6
7
NGINX

固定入口

Lua Runtime

Dynamic Route Matcher

Nginx 负责:

1
2
3
4
5
6
TCP
HTTP
TLS
Event Loop
Connection
Proxy

Lua/OpenResty 负责:

1
2
3
4
5
6
Dynamic Route
Plugin
Authentication
Rate Limit
Service Discovery
Dynamic Upstream

于是:

1
新增 Route

不再意味着:

1
2
3
重新生成 10000 个 location
+
nginx reload

而是:

1
更新动态路由数据结构

官方对这一设计的解释也是:APISIX 使用 NGINX 作为网络代理基础设施,而把动态路由等能力放入 Lua 层;路由匹配关键路径又使用 C 实现的 Radix Tree,以兼顾动态性和性能。

可以把这种设计理解成:

1
2
3
4
5
6
7
8
NGINX
负责稳定的数据传输引擎

Lua
负责动态策略

C Data Structure
负责热点匹配性能

这实际上是 APISIX 很重要的架构取舍:

不是抛弃 Nginx 的性能,而是在 Nginx 之上增加一个动态控制层。


APISIX 动态配置到底是怎么生效的

假设管理员执行:

1
PUT /apisix/admin/routes/100

完整过程可以抽象成:

sequenceDiagram
    participant O as Operator
    participant A as Admin API
    participant E as etcd
    participant W as APISIX Worker
    participant C as Client

    O->>A: PUT Route
    A->>A: Authentication
    A->>A: JSON Schema Validation
    A->>E: Persist Configuration
    E-->>W: Watch Event
    W->>W: Refresh In-Memory Configuration

    C->>W: New Request
    W->>W: Match New Route
    W-->>C: Response

Admin API 会对资源配置进行校验,然后写入配置存储;Worker 监听配置变化并更新运行时配置。这个机制使 Route、Plugin、Upstream 等大量资源的变化不必依赖传统的 Nginx Reload。

因此:

1
2
3
4
5
6
7
配置修改

etcd

Watch Event

APISIX Worker Memory

而不是:

1
2
3
4
5
配置修改

nginx.conf

nginx reload

这也是为什么 APISIX 能比较自然地实现:

1
2
3
4
5
6
7
动态路由
动态限流
动态插件
动态上游
动态权重
动态灰度
动态证书

APISIX 中有两类完全不同的配置

这是初学者最容易混淆的地方。

静态运行配置

例如:

1
conf/config.yaml

里面主要配置:

1
2
3
4
5
6
7
8
监听端口
Admin API
etcd 地址
部署模式
插件加载列表
Prometheus Export Server
Lua 路径
Nginx 参数

它描述的是:

APISIX 这个程序本身应该怎么运行。

例如:

1
2
3
4
5
6
7
8
9
deployment:
admin:
allow_admin:
- 127.0.0.1/32

admin_key:
- name: admin
key: CHANGE_ME_TO_A_LONG_RANDOM_SECRET
role: admin

生产环境不要直接照抄示例 Secret,应通过 Secret Manager、环境变量或部署平台安全注入。

动态业务配置

包括:

1
2
3
4
5
6
7
8
Route
Service
Upstream
Consumer
Credential
PluginConfig
GlobalRule
SSL

它们描述:

请求应该怎么处理。

一般通过:

1
2
3
4
Admin API
Dashboard
Ingress Controller
ADC

进行管理。

不要直接修改生成后的 nginx.conf

APISIX 会根据自己的配置模板生成 Nginx 配置。

因此:

1
直接修改 nginx.conf

往往是错误做法。

APISIX 再次启动或重新生成配置时,很可能覆盖这些修改。当前官方安装文档明确区分了用户配置 config.yaml 与生成的 nginx.conf,推荐修改 APISIX 配置而不是直接修改生成文件。


快速运行 APISIX

官方 Quick Start

开发环境最快的方式是:

1
curl -sL https://run.api7.ai/apisix/quickstart | sh

然后验证:

1
curl -I http://127.0.0.1:9080

Quick Start 会启动 APISIX 和 etcd。

需要特别注意:当前官方 Quick Start 为降低学习门槛,会关闭 Admin API 授权,这种配置只适合本地体验,不应该直接复制到生产环境。

Docker Compose

更接近完整实验环境的方式是使用官方 Docker 仓库:

1
2
3
4
5
git clone https://github.com/apache/apisix-docker.git

cd apisix-docker/example

docker compose -p docker-apisix up -d

部分 Docker 环境仍可能使用:

1
docker-compose -p docker-apisix up -d

可以查看:

1
docker ps

确认:

1
2
3
APISIX
etcd
Upstream Test Services

等组件是否正常。官方当前安装文档仍提供 Docker Compose 与 Helm 两类常用安装方式,并由容器化安装自动处理 etcd 等依赖。

常用端口

常见默认端口可以先记住两个:

端口 用途
9080 APISIX HTTP Gateway
9180 Admin API

生产环境中端口本身可以修改,因此不要把这些数字硬编码进业务系统。


Dashboard 的当前使用方式

旧版本 APISIX 教程中经常可以看到:

1
2
http://IP:9000
admin/admin

这是早期独立 apisix-dashboard 组件的典型部署方式。一些 2022~2023 年文章和 Docker Compose 示例仍然采用这一架构。

当前 APISIX 3.17 文档已经采用内置 Admin UI,默认入口为:

1
http://127.0.0.1:9180/ui

并由:

1
2
3
deployment:
admin:
enable_admin_ui: true

控制。Dashboard 最终仍然通过 Admin API 管理 APISIX 资源。

所以遇到教程要求访问:

1
:9000

不要立刻怀疑安装坏了,先看它写的是哪个 APISIX / Dashboard 版本。


Admin API:理解 APISIX 的第一把钥匙

APISIX 大量动态资源都可以通过 REST API 管理。

基础路径:

1
/apisix/admin

例如:

1
2
3
4
5
6
7
/apisix/admin/routes
/apisix/admin/upstreams
/apisix/admin/services
/apisix/admin/consumers
/apisix/admin/plugin_configs
/apisix/admin/global_rules
/apisix/admin/ssls

Admin API 支持常见 CRUD 操作:

Method 含义
GET 查询
PUT 创建指定 ID 或完整更新
POST 创建并由系统分配 ID
PATCH 局部修改
DELETE 删除

Upstream 等资源当前同时支持完整 PATCH 和字段路径 PATCH。

获取 Admin Key

普通安装环境可以从配置中读取:

1
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')

后续统一:

1
-H "X-API-KEY: $admin_key"

本文后面的 Admin API 示例均按启用了 Admin API 鉴权的正常环境书写。


跑通第一条 Route

创建 Route:

1
2
3
4
5
6
7
8
9
10
11
12
13
curl http://127.0.0.1:9180/apisix/admin/routes/1 \
-H "X-API-KEY: $admin_key" \
-X PUT \
-d '
{
"uri": "/get",
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

请求:

1
curl http://127.0.0.1:9080/get

完整数据流:

1
2
3
4
5
6
7
8
9
10
11
12
13
curl

127.0.0.1:9080

APISIX

Route: /get

Upstream

httpbin.org:80

Response

这也是 APISIX 最小工作模型:

1
2
3
Route
+
Upstream

Route 负责回答:

1
谁的请求?

Upstream 负责回答:

1
发到哪里?

APISIX 核心资源模型

理解 APISIX 后续所有配置前,应该先把几个核心对象彻底区分清楚。

资源 核心职责
Route 判断请求匹配哪条规则
Upstream 描述后端节点与负载均衡
Service 复用一组 Route 的公共能力
Plugin 给请求增加认证、限流、改写等能力
Plugin Config 复用一组插件配置
Consumer API 调用方身份
Credential Consumer 的认证凭证
Consumer Group 一组 Consumer 的公共插件策略
Global Rule 全局执行的 Plugin
SSL TLS 证书资源
Secret 安全引用密码、Token、证书等敏感值

它们之间大致是:

flowchart TD
    Client[Client]

    Route[Route]
    Service[Service]
    PluginConfig[Plugin Config]
    Upstream[Upstream]

    Consumer[Consumer]
    Credential[Credential]
    ConsumerGroup[Consumer Group]

    GlobalRule[Global Rule]
    Plugins[Plugins]

    Backend[Backend Nodes]

    Client --> Route

    Route --> Service
    Route --> PluginConfig
    Route --> Upstream
    Service --> Upstream

    Credential --> Consumer
    Consumer --> ConsumerGroup
    Consumer --> Plugins

    Route --> Plugins
    Service --> Plugins
    PluginConfig --> Plugins

    GlobalRule --> Plugins
    Upstream --> Backend

下面逐个拆开。


Route:APISIX 如何判断一个请求应该去哪里

Route 是整个 APISIX 最重要的资源之一。

一条 Route 可以包含:

1
2
3
4
5
6
7
8
9
URI
Host
Method
Remote Address
Header
Query Parameter
Nginx Variable
Plugin
Upstream

例如:

1
2
3
4
5
6
7
8
{
"uri": "/api/orders/*",
"methods": [
"GET",
"POST"
],
"host": "api.example.com"
}

它表示:

1
2
3
4
5
6
7
8
9
Host = api.example.com

AND

URI starts with /api/orders/

AND

Method in GET,POST

Route 不是只有 URI

实际系统很可能需要:

1
2
3
4
5
同一个 URI
+
不同 Header
=
不同版本

例如:

1
2
3
4
5
6
7
8
9
10
11
{
"uri": "/api/orders/*",
"priority": 10,
"vars": [
[
"http_x_api_version",
"==",
"v2"
]
]
}

那么:

1
X-API-Version: v2

可以匹配到新版本。

而普通请求:

1
/api/orders/100

进入默认版本。

这给 APISIX 带来了非常灵活的:

1
2
3
4
5
6
Header Routing
Cookie Routing
Query Routing
IP Routing
Version Routing
Canary Routing

能力。


APISIX 为什么使用 RadixTree 做路由

假设存在:

1
2
3
4
5
/api
/api/order
/api/order/*
/api/order/detail/*
/api/order/detail/history/*

最简单的实现当然可以:

1
2
3
for route in routes:
if route.matches(request):
return route

但当 Route 数量不断增大时,每个请求都线性遍历所有规则并不理想。

APISIX 使用 libradixtree,基于 Adaptive Radix Tree 实现高效 URI 路由匹配。当前文档中的典型匹配方式包括 Exact Match 与 Prefix Match,并按照 URI 匹配深度等规则选择候选 Route。

例如:

1
/blog/foo

可以做精确匹配。

而:

1
/blog/bar*

可以表示前缀匹配。

可以把 Radix Tree 粗略理解成:

1
2
3
4
5
6
7
/
└── api
├── order
│ ├── detail
│ │ └── history
│ └── create
└── user

查找:

1
/api/order/detail

时,可以沿路径向下寻找,而不是简单把请求拿去和所有 Route 逐条比较。

Route Priority

如果存在多条可能匹配的 Route,可以通过:

1
2
3
{
"priority": 100
}

帮助控制优先级。

工程上最好做到:

尽量让路由条件本身清晰互斥,而不是大量依赖 priority 修复重叠规则。

否则半年后会出现:

1
为什么请求命中了 Route 731?

然后所有人一起考古。


Upstream:真正决定请求发给谁

Route 决定:

1
请求属于哪个 API

Upstream 决定:

1
这个 API 后面有哪些 Backend

例如:

1
2
3
4
5
6
7
8
{
"type": "roundrobin",
"nodes": {
"10.10.10.11:8080": 1,
"10.10.10.12:8080": 1,
"10.10.10.13:8080": 1
}
}

结构:

1
2
3
4
5
6
7
APISIX
|
+----> Node A
|
+----> Node B
|
+----> Node C

APISIX 当前 Upstream 支持负载均衡、健康检查、重试、连接/发送/读取超时、Host 传递、HTTP/HTTPS/gRPC 等协议,以及连接池参数。


独立管理 Upstream

不推荐每条 Route 都复制:

1
2
3
4
5
{
"upstream": {
...
}
}

例如:

1
2
3
Route A ─┐
Route B ─┼── order-service
Route C ─┘

可以先建立:

1
Upstream 100
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
curl http://127.0.0.1:9180/apisix/admin/upstreams/100 \
-H "X-API-KEY: $admin_key" \
-X PUT \
-d '
{
"type": "roundrobin",
"nodes": {
"10.10.10.11:8080": 1,
"10.10.10.12:8080": 1
},
"retries": 1,
"timeout": {
"connect": 2,
"send": 5,
"read": 5
}
}'

然后 Route:

1
2
3
4
5
6
7
8
curl http://127.0.0.1:9180/apisix/admin/routes/100 \
-H "X-API-KEY: $admin_key" \
-X PUT \
-d '
{
"uri": "/api/orders/*",
"upstream_id": "100"
}'

以后扩容:

1
10.10.10.13:8080

只需要修改 Upstream。

所有引用它的 Route 都一起生效。

这就是对象化配置的价值:

1
2
不要复制配置
而是引用资源

官方同样推荐在多个 Route 重复使用后端配置时独立创建 Upstream,通过 upstream_id 复用。


APISIX 的负载均衡算法

当前 Upstream 常用算法包括:

算法 用途
roundrobin 加权轮询
chash 一致性 Hash
ewma 根据历史延迟选择节点
least_conn 优先选择连接压力较低的节点

APISIX 当前 Admin API 文档定义了这些 Upstream 类型,其中 roundrobin 为默认算法,chash 可以按变量、Header、Cookie 或 Consumer 做一致性哈希。

roundrobin

例如:

1
2
3
4
5
6
{
"nodes": {
"10.0.0.1:8080": 1,
"10.0.0.2:8080": 2
}
}

第二个节点拥有更高权重。

适合:

1
Backend 性能不同

例如:

1
2
Node A:2C4G
Node B:8C16G

chash

一致性 Hash 适合:

1
同一个用户尽量落到同一实例

可以基于:

1
2
3
4
remote_addr
header
cookie
consumer

例如:

1
2
3
4
5
6
7
8
9
{
"type": "chash",
"hash_on": "cookie",
"key": "sid",
"nodes": {
"10.0.0.1:8080": 1,
"10.0.0.2:8080": 1
}
}

如果客户端:

1
Cookie: sid=abc123

相同 sid 在节点拓扑稳定时会倾向于进入相同 Backend。

least_conn

适合请求耗时差异比较大的系统。

大致思想不是:

1
大家轮流一次

而是:

1
谁现在更空闲,就优先给谁

当前实现依据节点活动连接数量与权重进行选择。

EWMA

EWMA 会把历史响应延迟纳入计算。

如果:

1
2
Node A = 20ms
Node B = 200ms

即使两个节点理论权重相同,也可以尽量避免持续给慢节点施加更多压力。


Upstream 超时必须明确配置

网关非常容易出现一个反模式:

1
所有下游请求都等很久

然后:

1
2
3
4
5
6
7
8
9
一个慢服务

占满 Gateway 连接

请求堆积

更多超时

雪崩

Upstream 可以设置:

1
2
3
4
5
6
7
{
"timeout": {
"connect": 2,
"send": 5,
"read": 5
}
}

三者对应:

1
2
3
4
5
6
7
8
connect
连接上游允许多久

send
向上游发送请求允许多久

read
等待/读取上游响应允许多久

默认值未必适合所有业务。

例如:

1
用户查询 API

和:

1
大文件导出 API

显然不应该使用完全相同的超时策略。


Retry 不是免费的可靠性

APISIX Upstream 支持:

1
2
3
{
"retries": 2
}

但看到 Retry 时不要自动理解成:

1
可靠性 +2

真正的问题是:

1
第一次请求到底有没有被后端执行?

例如:

1
POST /payment

后端实际上已经扣款:

1
transaction commit

但返回过程中连接中断。

Gateway 如果错误地重新执行:

1
POST /payment

可能变成第二次扣款。

因此 Retry 必须和:

1
2
3
4
5
HTTP Method
幂等性
Idempotency-Key
业务事务
上游故障类型

一起设计。

正确的思路不是:

请求失败就多重试几次。

而是:

只有明确知道能够安全重试的失败才应该重试。


Upstream 健康检查

APISIX 支持主动和被动健康检查。

Active Health Check

Gateway 主动发:

1
GET /status

判断:

1
Backend 是否健康

例如官方形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"nodes": {
"10.10.10.11:8080": 1
},
"type": "roundrobin",
"retries": 2,
"checks": {
"active": {
"http_path": "/status",
"healthy": {
"interval": 2,
"successes": 1
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}
}

APISIX 的 Upstream 可以配置主动/被动检查,并结合 Retry 在后端故障时完成节点摘除与恢复判断。

Passive Health Check

被动检查则观察真实业务请求:

1
2
3
4
5
6
7
8
9
10
APISIX
|
| real traffic
v
Backend
|
+-- 200
+-- timeout
+-- TCP error
+-- 5xx

连续异常后将节点标记为 Unhealthy。

被动检测有一个非常容易忽略的问题:

1
2
3
4
5
节点已经被摘掉

不再收到真实请求

怎样知道它恢复了?

因此生产环境通常会把:

1
2
3
Passive Detection
+
Active Recovery Probe

组合使用,而不是只依赖被动健康检查。官方健康检查说明也特别指出了这一恢复问题。


Service:把公共配置从 Route 中抽出来

假设订单 API:

1
2
3
4
GET    /orders/*
POST /orders
PUT /orders/*
DELETE /orders/*

每条 Route 都可能使用同一个:

1
2
3
4
Upstream
Authentication
Rate Limit
Logging

如果每条都写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Route A
Plugin X
Plugin Y
Upstream

Route B
Plugin X
Plugin Y
Upstream

Route C
Plugin X
Plugin Y
Upstream

会产生大量重复。

Service 就是为了:

1
2
3
4
5
6
7
Route A ─┐
Route B ─┼── Service
Route C ─┘
|
+--- Plugins
|
+--- Upstream

官方将 Service 定义为一组 API/Route 的抽象,可以承载它们共同的 Upstream 与 Plugin 配置;Route 上相同 Plugin 的配置可以覆盖 Service 层配置。

创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
curl http://127.0.0.1:9180/apisix/admin/services/100 \
-H "X-API-KEY: $admin_key" \
-X PUT \
-d '
{
"name": "order-service",
"plugins": {
"limit-count": {
"count": 1000,
"time_window": 60,
"rejected_code": 429
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"10.10.10.11:8080": 1,
"10.10.10.12:8080": 1
}
}
}'

Route:

1
2
3
4
{
"uri": "/api/orders/*",
"service_id": "100"
}

Plugin Config:专门复用插件组合

如果多个完全不同的 Service 都需要:

1
2
3
4
5
6
7
request-id
+
limit-count
+
cors
+
prometheus

可以建立 Plugin Config:

1
2
3
4
5
PluginConfig
├── request-id
├── limit-count
├── cors
└── ...

然后:

1
2
3
Route A ──> PluginConfig
Route B ──> PluginConfig
Route C ──> PluginConfig

这样能够进一步减少策略复制。

需要注意:

Service 是业务服务抽象,而 Plugin Config 是插件策略组合抽象。

两者不是同一个概念。


Consumer 与 Credential

Consumer 表示:

1
谁在调用 API

例如:

1
2
3
4
5
mobile-app
payment-system
erp-system
partner-a
partner-b

而 Credential 表示:

1
这个 Consumer 用什么凭证证明自己是谁

当前 APISIX 已经把 Credential 作为独立资源,可以让同一个 Consumer 拥有多个认证凭证,而不仅仅把 Key 直接塞进 Consumer 本身。

例如:

1
2
3
Consumer: erp-system
├── key-auth credential A
└── key-auth credential B

这样做非常适合密钥轮换:

1
2
3
4
5
Old Key + New Key

客户端迁移

删除 Old Key

而不需要瞬间让所有客户端一起换 Key。


APISIX 插件体系

如果 Route 和 Upstream 解决的是:

1
Where?

Plugin 解决的是:

1
How?

比如:

1
请求进来以后应该怎么处理?

APISIX 当前提供大量内置插件,覆盖认证、安全、流量控制、请求/响应改写、缓存、灰度、可观测性以及其他协议等能力。

典型分类如下:

类型 示例
Authentication key-authjwt-authbasic-authopenid-connect
Security corsip-restrictionuri-blocker
Traffic limit-countlimit-reqlimit-conn
Resilience api-breaker
Rewrite proxy-rewriteresponse-rewrite
Cache proxy-cache
Canary traffic-split
Metrics prometheus
Tracing opentelemetryzipkinskywalking
Logging http-loggerkafka-loggerloki-logger
Protocol gRPC、Dubbo、Kafka 等相关插件

这也是 APISIX 与“普通反向代理”最大的区别之一:

很多网关能力不是硬编码进 APISIX Core,而是插件化。


一个请求经过哪些 Plugin Phase

APISIX Plugin 并不是随机执行的。

典型生命周期可以理解为:

flowchart LR
    A[Client Request]
    B[Route Match]
    C[rewrite]
    D[access]
    E[before_proxy]
    F[Upstream]
    G[header_filter]
    H[body_filter]
    I[Client Response]
    J[log]

    A --> B
    B --> C
    C --> D
    D --> E
    E --> F
    F --> G
    G --> H
    H --> I
    I --> J

官方 Plugin 生命周期定义了 rewriteaccessbefore_proxyheader_filterbody_filterlog 等阶段。

rewrite

适合:

1
2
3
认证
URI 修改
部分请求预处理

例如当前 APISIX 插件开发文档明确规定认证插件通常在 rewrite 阶段工作。

access

适合:

1
2
3
访问控制
限流
权限判断

这是请求进入 Upstream 之前最常见的插件阶段之一。

before_proxy

在真正代理上游之前执行。

header_filter

用于修改上游响应 Header。

例如:

1
X-Gateway: APISIX

body_filter

对响应 Body 做处理。

log

请求基本处理完成后:

1
2
3
日志
Metrics
Trace

等逻辑可以在这里收尾。


插件优先级不是配置文件里的先后顺序

假设:

1
2
3
4
5
6
{
"plugins": {
"plugin-a": {},
"plugin-b": {}
}
}

不要认为:

1
2
JSON 里谁写在前面
谁就先执行

APISIX Plugin 有:

1
priority

同一执行阶段中:

1
2
priority 越大
越先执行

自定义插件也必须避免与已有 Plugin 使用重复 Priority。官方建议在开发自定义插件时通过 Control API /v1/schema 检查现有插件优先级。


同一个 Plugin 配在多个资源上,谁生效

例如:

1
2
3
4
5
6
7
8
Service:
limit-count = 1000

Route:
limit-count = 100

Consumer:
limit-count = 10

当前 APISIX 对同一个本地 Plugin 配置的合并优先级可以概括为:

1
2
3
4
5
6
7
8
9
Consumer
>
Consumer Group
>
Route
>
Plugin Config
>
Service

Global Rule 属于另一层全局执行语义,不能简单理解成被 Route 覆盖;全局插件会在对象级插件之前执行。

这个设计非常适合做:

1
2
3
4
5
Service 默认策略

Route 特例

Consumer 单独配额

例如:

1
2
3
4
5
6
7
8
普通 API
1000 req/min

导出 API
10 req/min

VIP Consumer
100 req/min

Global Rule

某些规则不应该一条 Route 一条 Route 地配置。

例如:

1
2
3
4
5
Request ID
Prometheus
Global Logging
WAF
Global Header

这时可以使用:

1
Global Rule

思路:

1
2
3
4
5
6
7
所有请求

Global Rule

Route Plugin

Upstream

例如:

1
2
3
4
5
6
7
8
9
10
curl http://127.0.0.1:9180/apisix/admin/global_rules/1 \
-H "X-API-KEY: $admin_key" \
-X PUT \
-d '
{
"plugins": {
"prometheus": {},
"request-id": {}
}
}'

这样不需要:

1
2
3
1000 Routes
×
1000 次配置

实战:基于 IP 的固定窗口限流

APISIX 提供三类常见限流插件:

Plugin 控制目标
limit-req 请求速率
limit-count 一个时间窗口中的请求总数
limit-conn 并发连接/请求数量

其中当前 limit-count 使用固定窗口计数算法。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
curl http://127.0.0.1:9180/apisix/admin/routes/200 \
-H "X-API-KEY: $admin_key" \
-X PUT \
-d '
{
"uri": "/limited",
"plugins": {
"limit-count": {
"count": 100,
"time_window": 60,
"key_type": "var",
"key": "remote_addr",
"rejected_code": 429,
"policy": "local"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

含义:

1
2
3
4
5
6
7
8
Key:
remote_addr

Window:
60s

Quota:
100

所以:

1
2
一个 IP
一分钟最多 100 次

超出:

1
HTTP 429

多 APISIX 节点下,local 限流不是全局限流

这是生产环境非常常见的坑。

假设:

1
2
3
APISIX A
APISIX B
APISIX C

每台:

1
2
3
4
{
"count": 100,
"policy": "local"
}

那么理论上整个 Gateway Cluster 可能承受:

1
2
3
4
5
A = 100
B = 100
C = 100

Total ≈ 300

因为:

1
local counter

只存在当前节点内存。

当前 limit-count 支持:

1
2
3
local
redis
redis-cluster

三种 Counter Storage Policy。需要集群共享配额时,可以使用 Redis 或 Redis Cluster。

所以设计限流前一定要先问:

1
2
3
4
5
6
7
我要限制的是:

单 Gateway 节点?
单 Consumer?
单 IP?
整个 Gateway Cluster?
整个租户?

这比“限多少 QPS”更重要。


实战:key-auth

创建 Consumer:

1
2
3
4
5
6
7
curl http://127.0.0.1:9180/apisix/admin/consumers \
-H "X-API-KEY: $admin_key" \
-X PUT \
-d '
{
"username": "erp-system"
}'

创建 Credential:

1
2
3
4
5
6
7
8
9
10
11
12
curl http://127.0.0.1:9180/apisix/admin/consumers/erp-system/credentials \
-H "X-API-KEY: $admin_key" \
-X PUT \
-d '
{
"id": "erp-primary-key",
"plugins": {
"key-auth": {
"key": "PLEASE-CHANGE-THIS-KEY"
}
}
}'

Route 开启认证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
curl http://127.0.0.1:9180/apisix/admin/routes/300 \
-H "X-API-KEY: $admin_key" \
-X PUT \
-d '
{
"uri": "/erp/*",
"plugins": {
"key-auth": {
"hide_credentials": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"10.10.20.10:8080": 1
}
}
}'

客户端:

1
2
curl http://127.0.0.1:9080/erp/orders \
-H "apikey: PLEASE-CHANGE-THIS-KEY"

当前 key-auth 默认从:

1
apikey Header

或 Query String 中读取 Key,Header 优先级更高;hide_credentials=true 可以阻止认证凭证继续被代理到 Upstream。

生产环境通常更推荐:

1
Authorization / Header

而不是:

1
?apikey=xxx

因为 Query String 更容易出现在:

1
2
3
4
Access Log
Browser History
Proxy Log
Monitoring

中。


Consumer 能与限流组合

例如:

1
2
3
4
5
6
7
8
Consumer A
1000 req/min

Consumer B
100 req/min

Anonymous
10 req/min

APISIX 可以先:

1
key-auth

得到:

1
consumer_name

再使用:

1
limit-count

按:

1
Consumer

进行限流。

还可以组合:

1
2
3
$remote_addr
+
$consumer_name

当前 limit-count 支持 var_combination,因此可以按照多个变量组合生成 Counter Key。

这比简单 IP 限流更适合真正的 SaaS API:

1
2
3
4
Tenant
Consumer
API
IP

共同参与限流策略。


实战:proxy-cache

缓存链路:

1
2
3
4
5
6
7
8
9
10
11
12
13
Client

APISIX

Cache Hit?
┌───┴────┐
Yes No
↓ ↓
Return Upstream

Cache

Return

例如:

1
2
3
4
5
6
7
8
9
{
"plugins": {
"proxy-cache": {
"cache_strategy": "memory",
"cache_zone": "memory_cache",
"cache_ttl": 60
}
}
}

适合:

1
2
3
4
商品分类
公共配置
静态元数据
低频变化查询

不适合随便缓存:

1
2
3
4
订单状态
账户余额
权限信息
用户隐私数据

当前 proxy-cache 支持 Memory 与 Disk 两类缓存,并能控制 Cache Key、Method、HTTP Status、TTL、Cache-Control、Vary、Consumer Isolation 等行为。默认情况下还会避免缓存带有 privateno-storeno-cache 等上游 Cache-Control 语义的响应。

缓存真正难的不是:

1
怎么存

而是:

1
什么时候失效

所以生产设计时应该先确定:

1
2
3
4
5
6
7
Cache Key
TTL
Invalidation
User Isolation
Vary
Set-Cookie
Error Response

再启用 Cache。


实战:灰度发布

假设:

1
2
order-v1
order-v2

目标:

1
2
90% -> v1
10% -> v2

创建两个 Upstream:

1
2
Upstream 200 = order-v1
Upstream 201 = order-v2

然后使用:

1
traffic-split

概念配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream_id": 200,
"weight": 90
},
{
"upstream_id": 201,
"weight": 10
}
]
}
]
}
},
"upstream_id": 200
}

APISIX 当前 traffic-split 可以依据条件和 Weight 将流量分配到不同 Upstream,适合 Canary 与 Blue-Green 等发布模式。

灰度过程可以做成:

1
2
3
4
5
6
7
8
9
10
11
v2 = 1%

v2 = 5%

v2 = 10%

v2 = 30%

v2 = 50%

v2 = 100%

每一步观察:

1
2
3
4
5
6
7
Error Rate
P95
P99
CPU
Memory
Business Error
Conversion

发现异常:

1
v2 = 0%

即可快速回滚流量。

需要注意,在很小的请求样本下,权重得到的是统计意义上的比例,而不是保证“连续 10 个请求一定精确 9:1”。官方文档也提醒小样本或状态重置情况下实际比例可能存在偏差。


服务发现:不要把 Backend IP 写死

最简单的 Upstream:

1
2
3
4
5
6
{
"nodes": {
"10.0.1.11:8080": 1,
"10.0.1.12:8080": 1
}
}

但微服务环境中:

1
2
3
4
Pod Restart
Auto Scaling
Node Failure
Rolling Update

都会造成:

1
IP Change

因此更理想的方式是:

1
Service Registry

例如:

1
2
3
4
5
Nacos
Consul
Eureka
Kubernetes
DNS

当前 APISIX 文档列出了 Nacos、Consul、Eureka、Kubernetes、DNS 等多种服务发现方式。

Upstream 可以表达为:

1
2
3
4
5
{
"type": "roundrobin",
"service_name": "order-service",
"discovery_type": "nacos"
}

不再直接关心:

1
2
3
10.10.10.11
10.10.10.12
10.10.10.13

而是:

1
2
3
4
5
order-service

Service Discovery

Current Instances

当前 Upstream Admin API 也明确规定:

1
nodes

和:

1
service_name + discovery_type

属于两种不同的 Backend 获取方式。


etcd 与 Nacos 的职责再区分一次

如果同时存在:

1
2
3
APISIX
etcd
Nacos

一个很典型的职责分工是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
               etcd

APISIX Configuration
|
Admin API ------+
|
v
APISIX
|
| query/watch discovery
v
Nacos
|
order-service
┌───────┼───────┐
↓ ↓ ↓
A B C

etcd 保存:

1
2
3
4
5
6
7
8
9
10
Route:
/orders/*

Plugin:
key-auth
limit-count

Upstream:
discovery_type = nacos
service_name = order-service

Nacos 保存:

1
2
3
4
order-service
├── 10.0.1.11:8080
├── 10.0.1.12:8080
└── 10.0.1.13:8080

这就是:

1
Gateway Configuration

和:

1
Service Instance Discovery

两个层次。


自定义 Lua Plugin

当内置 Plugin 不能满足需求时,可以开发自定义 Lua Plugin。

例如,希望所有响应增加:

1
X-Gateway: APISIX

一个简化 Plugin 可以写成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
local core = require("apisix.core")

local plugin_name = "add-response-header"

local schema = {
type = "object",
properties = {
header = {
type = "string",
minLength = 1
},
value = {
type = "string"
}
},
required = {
"header",
"value"
}
}

local _M = {
version = 0.1,
priority = 23,
name = plugin_name,
schema = schema
}

function _M.check_schema(conf)
return core.schema.check(schema, conf)
end

function _M.header_filter(conf, ctx)
ngx.header[conf.header] = conf.value
end

return _M

这里体现了 APISIX Plugin 的几个核心组成:

1
2
3
4
5
name
version
priority
schema
phase function

生产使用前需要检查 Priority 是否与已安装 Plugin 冲突,上面的 23 只是示例值。官方插件开发文档要求自定义 Plugin 定义 JSON Schema,并通过 core.schema.check 完成配置校验。


自定义 Plugin 的加载路径

可以通过:

1
2
apisix:
extra_lua_path: "/opt/apisix-custom/?.lua"

加载外部 Lua 代码。

目录结构:

1
2
3
4
/opt/apisix-custom/
└── apisix
└── plugins
└── add-response-header.lua

需要时再把 Plugin 加入:

1
2
3
plugins:
- ...
- add-response-header

这里有一个杀伤力很强的坑:

一旦显式配置 plugins:,这个列表会替换 APISIX 默认插件列表,而不是在默认列表上自动追加。

因此如果只写:

1
2
plugins:
- add-response-header

有可能无意中把原本需要的内置插件全部移除。

官方插件开发文档专门对此进行了 Warning。


Java、Go、Python 能不能开发 Plugin

可以。

APISIX 支持 External Plugin Runner。

架构类似:

1
2
3
4
5
6
7
         APISIX
|
RPC
|
External Plugin Runner
|
Java / Go / Python Plugin

External Plugin Runner 以 Sidecar 方式运行,APISIX 把请求相关信息通过 RPC 交给 Runner,由 Runner 创建相应请求上下文、执行外部插件并把结果返回。

这对 Java 团队很有吸引力,但需要理解它与 Lua Plugin 的架构差别:

1
2
3
4
5
6
7
8
9
Lua Plugin

APISIX Worker 内执行

External Plugin

RPC

另一个进程

这意味着 External Plugin 会额外增加:

1
2
3
4
5
IPC/RPC
Sidecar
Process Lifecycle
Failure Mode
Deployment Complexity

如果逻辑简单且团队能够维护 Lua:

1
Lua Plugin

通常路径更短。

如果逻辑高度依赖:

1
2
3
Java SDK
公司内部 Java Library
已有 Java 安全组件

External Plugin Runner 才更有价值。


APISIX 的三种部署模式

当前 APISIX 正式区分:

1
2
3
Traditional
Decoupled
Standalone

Traditional

结构:

1
2
3
4
5
6
7
8
          etcd
^
|
+--------+--------+
| |
Admin API Gateway
| |
+------ APISIX ---+

同一个 APISIX 实例同时承担:

1
2
3
Control Plane
+
Data Plane

典型端口:

1
2
9180 Admin API
9080 Gateway

适合:

1
2
3
4
开发
测试
中小规模部署
架构简单优先

Decoupled

将:

1
Control Plane

和:

1
Data Plane

逻辑分离。

flowchart LR
    Admin[Admin / CI / Platform]
    CP[APISIX Control Plane]
    ETCD[(etcd)]

    DP1[APISIX Data Plane 1]
    DP2[APISIX Data Plane 2]
    DP3[APISIX Data Plane 3]

    Client[Clients]
    Backend[Backends]

    Admin --> CP
    CP --> ETCD

    ETCD --> DP1
    ETCD --> DP2
    ETCD --> DP3

    Client --> DP1
    Client --> DP2
    Client --> DP3

    DP1 --> Backend
    DP2 --> Backend
    DP3 --> Backend

这样可以:

1
Admin API

完全留在内部控制网络。

公网只暴露:

1
Data Plane

从安全和大型生产架构角度,这通常比把 Admin API 与业务 Gateway 放在同一个暴露面上更合理。

Standalone

Standalone 不要求依赖默认的 etcd 配置中心。

数据可以来自:

1
YAML File

或当前提供的:

1
Standalone API-driven Mode

适合:

1
2
3
4
5
GitOps
Kubernetes
Declarative Configuration
不希望维护 etcd
外部控制器统一下发完整配置

Standalone 文件模式

可以把配置写成:

1
2
3
4
5
6
7
8
9
10
routes:
-
id: 1
uri: /hello
upstream:
type: roundrobin
nodes:
"httpbin.org:80": 1

#END

Standalone File 模式会周期性检查配置文件变化,当前官方文档要求 YAML 配置以:

1
#END

结束,以帮助 APISIX 判断配置文件已经完整写入。

这个设计看起来只是一个小细节,实际上解决了很重要的问题:

1
2
3
4
5
Writer 正在写文件

APISIX 正好读取

只读到半个 YAML

#END 相当于告诉 Reader:

1
这一版配置写完了

Standalone API-driven Mode

当前 APISIX 还提供 Standalone API-driven Mode。

思想变成:

1
2
3
4
5
6
7
8
Controller
|
| Full Configuration
v
Standalone Admin API
|
v
APISIX Memory

而不是:

1
2
3
4
5
Controller

etcd

APISIX

这种模式特别适合:

1
2
3
Kubernetes Controller
GitOps Agent
集中式配置平台

因为可以把 APISIX 当成:

1
纯 Data Plane

由外部控制系统负责 Desired State。当前官方文档已经把 API-driven Standalone 作为独立的 Standalone 使用方式。


Docker 与生产环境

Docker Compose 很适合:

1
2
3
4
开发环境
集成测试
PoC
小规模内网部署

生产环境则至少应该考虑:

1
2
3
4
5
6
7
8
9
10
APISIX 多实例
etcd 集群
Load Balancer
Admin API 网络隔离
Monitoring
Log Collection
TLS
Secret Management
Config Backup
Upgrade Strategy

典型结构:

flowchart LR
    Client[Internet]

    LB[Cloud LB / LVS / Nginx]

    A1[APISIX 1]
    A2[APISIX 2]
    A3[APISIX 3]

    E1[(etcd 1)]
    E2[(etcd 2)]
    E3[(etcd 3)]

    Backend[Microservices]

    Client --> LB

    LB --> A1
    LB --> A2
    LB --> A3

    A1 --> Backend
    A2 --> Backend
    A3 --> Backend

    A1 --> E1
    A2 --> E2
    A3 --> E3

    E1 --- E2
    E2 --- E3
    E3 --- E1

注意:

etcd 是控制配置基础设施,不应该为了“省机器”随便当普通临时容器使用,更不应该完全不考虑持久化和备份。


Kubernetes 中部署 APISIX

APISIX 不仅能作为普通 VM/Docker 网关,也可以作为 Kubernetes Gateway。

当前 APISIX Ingress Controller 最新文档版本为 2.1.0,并支持:

1
2
3
Gateway API
Ingress
APISIX CRD

三类 Kubernetes 配置方式。

Helm 安装

当前官方安装方式:

1
2
3
helm repo add apisix https://apache.github.io/apisix-helm-chart

helm repo update

安装 APISIX + Ingress Controller:

1
2
3
4
5
6
7
helm install apisix \
--namespace ingress-apisix \
--create-namespace \
--set ingress-controller.enabled=true \
--set ingress-controller.apisix.adminService.namespace=ingress-apisix \
--set ingress-controller.gatewayProxy.createDefault=true \
apisix/apisix

官方还提供直接安装为 Standalone API-driven 模式的 Helm 配置,可以在 Kubernetes 场景中去除 APISIX 默认 etcd 依赖。


Ingress Controller 并不代理业务流量

这是 Kubernetes 使用 APISIX 时一个非常重要的概念。

很多初学者脑中的路径是:

1
2
3
4
5
6
7
Client

Ingress Controller

APISIX

Service

实际上更准确的理解是:

1
2
3
4
5
6
7
8
9
10
11
Kubernetes API
|
v
Ingress Controller
|
| translate / sync configuration
v
APISIX Control Interface
|
v
APISIX Data Plane

业务请求则是:

1
2
3
4
5
6
7
8
9
10
11
12
13
Client
|
v
LoadBalancer
|
v
APISIX Gateway
|
v
Kubernetes Service
|
v
Pod

Ingress Controller 更像:

1
控制器

而 APISIX Gateway 才是:

1
真正承载流量的数据面

当前 Gateway API 架构同样是由 Controller 将 Gateway、HTTPRoute 等 Desired State 转换为 APISIX 能执行的配置,实际请求最终由 APISIX Gateway 处理。


Kubernetes 数据流

flowchart LR
    Developer[Developer]
    K8s[Kubernetes API Server]

    IC[APISIX Ingress Controller]
    GW[APISIX Gateway]

    SVC[Kubernetes Service]
    P1[Pod 1]
    P2[Pod 2]

    Client[Client]

    Developer -->|kubectl apply| K8s
    K8s -->|Watch| IC
    IC -->|Sync Gateway Config| GW

    Client --> GW
    GW --> SVC
    SVC --> P1
    SVC --> P2

这里实际上存在两条完全不同的链路:

1
配置链路

和:

1
流量链路

排查 Kubernetes APISIX 问题时一定要分开。


Gateway API

现在 Kubernetes Gateway 层越来越推荐使用 Gateway API 模型。

典型资源:

1
2
3
GatewayClass
Gateway
HTTPRoute

例如 GatewayClass:

1
2
3
4
5
6
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: apisix
spec:
controllerName: apisix.apache.org/apisix-ingress-controller

Gateway:

1
2
3
4
5
6
7
8
9
10
11
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: apisix
namespace: default
spec:
gatewayClassName: apisix
listeners:
- name: http
protocol: HTTP
port: 80

业务 Route 再通过:

1
HTTPRoute

挂到 Gateway。

APISIX Ingress Controller 当前同时支持标准 Gateway API,以及用于 APISIX 高级能力扩展的 CRD。

这样架构会比传统:

1
大量 Annotation

更加结构化。


可观测性

API Gateway 是整个请求链路最理想的观测点之一。

因为大部分请求都经过:

1
2
3
4
5
Client

Gateway

Backend

因此 Gateway 可以天然看到:

1
2
3
4
5
6
7
8
Request Count
Status Code
Latency
Upstream
Route
Consumer
Bandwidth
Error

APISIX 提供:

1
2
3
4
5
6
7
8
Prometheus
OpenTelemetry
Zipkin
SkyWalking
HTTP Logger
Kafka Logger
Loki Logger
...

等插件。


Prometheus

启用:

1
prometheus

后,APISIX 可以采集 API 请求、延迟等 Metrics 并导出给 Prometheus。

静态配置示例:

1
2
3
4
5
6
7
8
9
plugin_attr:
prometheus:
export_uri: /apisix/prometheus/metrics
metric_prefix: apisix_
enable_export_server: true

export_addr:
ip: 127.0.0.1
port: 9091

需要重点观察:

1
2
3
4
5
6
7
8
9
10
Gateway QPS
4xx
5xx
P50
P95
P99
Upstream Latency
Gateway Latency
Upstream Health
Bandwidth

如果:

1
2
request latency = 200ms
upstream latency = 190ms

说明:

1
瓶颈主要在 Backend

如果:

1
2
request latency = 200ms
upstream latency = 20ms

就应该继续调查:

1
2
3
4
5
Gateway Plugin
Client Network
TLS
Queue
Logging

而不是习惯性地把锅扔给数据库。


Trace

APISIX 位于请求入口,因此非常适合产生或传播:

1
2
Trace ID
Span ID

典型链路:

1
2
3
4
5
6
7
8
9
10
11
12
13
Client
|
v
APISIX Span
|
v
Order Service Span
|
+----> Redis
|
+----> DB
|
+----> Payment Service

然后接入:

1
2
3
4
OpenTelemetry Collector
Jaeger
SkyWalking
Zipkin

对于:

1
2
3
微服务延迟
跨服务调用
偶发超时

排查尤其重要。


日志

日志至少应该包含:

1
2
3
4
5
6
7
8
9
10
11
12
request_id
trace_id
route_id
service_id
consumer
upstream
status
request_time
upstream_time
method
uri
client_ip

而不是只有:

1
GET /api/orders 500

否则出了生产问题,排查过程很容易变成:

1
大家一起 grep。

API Gateway 日志尤其要注意敏感字段:

1
2
3
4
5
6
7
Authorization
Cookie
API Key
Password
Token
身份证
银行卡

不要因为 Gateway 能看见就全部写入日志。


Admin API 必须和业务 Gateway 分开看待

APISIX Gateway:

1
9080

处理:

1
业务请求

Admin API:

1
9180

处理:

1
修改整个 Gateway 配置

如果攻击者拿到 Admin API,就可能:

1
2
3
4
5
6
创建 Route
修改 Upstream
关闭 Auth
修改限流
增加恶意 Plugin
替换证书

所以生产环境绝对不能把:

1
9180

像普通业务 API 一样直接暴露给互联网。

当前官方 Admin API 提供 Admin Key 与 allow_admin 等保护机制;Quick Start 关闭 Admin API 鉴权只是本地体验上的例外。

推荐结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
Internet
|
v
Load Balancer
|
v
APISIX Data Plane :9080


Internal Management Network
|
v
APISIX Control Plane :9180

Admin API 安全建议

生产环境至少做到:

1
2
3
4
5
6
7
8
9
10
11
强随机 Admin Key
+
Network ACL
+
allow_admin
+
Private Network
+
Secret Management
+
Audit

如果采用 Decoupled Mode:

1
2
3
4
5
6
7
Internet
|
Data Plane

Internal
|
Control Plane

安全边界会更加清晰。

如果不使用 Dashboard:

1
2
3
deployment:
admin:
enable_admin_ui: false

可以考虑直接关闭 Admin UI。


Secret 不应该明文散落在 Route 中

例如:

1
2
3
4
5
Redis Password
JWT Secret
API Key
Vault Token
TLS Private Key

不应该大量出现:

1
2
3
{
"password": "123456"
}

APISIX 当前 Secret 机制可以从:

1
2
3
4
Environment Variable
HashiCorp Vault
AWS Secrets Manager
Google Cloud Secret Manager

等来源引用敏感数据。

例如环境变量 Secret Reference 可以表达为类似:

1
$ENV://MY_SECRET

这样可以把:

1
Configuration

和:

1
Secret Value

分离。


APISIX 的性能为什么不仅取决于 NGINX

很多人看到:

1
APISIX = NGINX + Lua

就认为:

1
性能 ≈ Nginx

这并不完整。

Gateway 热路径实际上是:

1
2
3
4
5
6
7
8
9
10
11
12
13
Network

Route Match

Plugin Chain

Load Balancer

Upstream Connection

Response Plugin

Logging

其中每一步都可能产生额外成本。

Route 数量

RadixTree 可以解决大量 URI 路由的核心匹配问题,但如果每条 Route 又附带非常复杂的:

1
2
3
4
vars
regex
header
cookie

条件,依然会增加处理成本。

Plugin 数量

如果一条请求执行:

1
20 Plugins

当然比:

1
2 Plugins

成本更高。

特别是自定义 Plugin 中不要随意做:

1
2
3
4
5
remote HTTP call
blocking operation
large JSON encode
large regex
large body copy

External Plugin

外部 Plugin 还增加:

1
2
3
4
5
APISIX
↓ RPC
Plugin Runner

APISIX

因此更应该关注插件是否真的适合放在 Gateway Hot Path。

Redis 限流

policy=local

1
Memory

通常路径很短。

改成:

1
policy=redis

则每次 Counter 操作可能涉及:

1
2
3
Network
+
Redis

得到的是:

1
Cluster-wide Quota

代价则是额外网络与 Redis 依赖。

这就是典型的工程取舍:

1
2
3
Consistency
vs
Latency

Logging

如果每个请求都同步调用一个远程日志系统:

1
Gateway Performance

很快会被日志基础设施反向绑架。

所以高流量系统需要考虑:

1
2
3
4
5
Batch
Buffer
Async Export
Sampling
Backpressure

etcd 不应该位于请求热路径

APISIX 动态架构一个非常重要的特点是:

1
etcd

用于:

1
配置分发

而不是:

1
每个请求实时查 Route

Worker 拿到配置以后:

1
2
3
Route
Plugin
Upstream

主要在运行时内存里完成处理。

所以更接近:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Control Plane:

Admin

etcd

Worker Memory


Data Plane:

Request

Worker Memory

Upstream

这意味着 etcd 短暂异常和:

1
已有流量立即全部无法代理

不是完全等价的问题。

但 etcd 故障会影响:

1
2
3
4
5
新配置
配置同步
节点启动
故障恢复
控制面管理

因此它依然属于关键基础设施。


API Gateway 不是业务 Service Mesh 的替代品

APISIX 可以承担:

1
North-South Traffic

也可以处理部分:

1
East-West Traffic

但它和 Service Mesh 解决问题的角度不同。

典型 Gateway:

1
2
3
4
5
Internet
|
APISIX
|
Services

Service Mesh 更偏:

1
2
3
4
5
Service A

Service B

Service C

Gateway 强项是:

1
2
3
4
5
6
API Management
Authentication
Rate Limit
Routing
API Security
External Traffic

Service Mesh 更擅长:

1
2
3
4
5
Service-to-Service
mTLS
Traffic Identity
Transparent Proxy
Service Networking

实际大型系统完全可能:

1
2
3
APISIX
+
Service Mesh

同时存在,而不是二选一。


APISIX 与普通 Nginx 怎么选

如果需求只是:

1
2
3
一个域名
两个 upstream
几条静态 location

Nginx 往往已经足够。

没有必要为了:

1
2
/ -> web
/api -> backend

专门上完整 APISIX。

APISIX 更适合:

1
2
3
4
5
6
7
8
9
10
11
12
大量 API
大量服务
动态配置
多租户
认证
限流
灰度
动态服务发现
统一日志
统一治理
平台化网关
Kubernetes Gateway

可以简单理解:

1
2
3
4
5
6
7
Nginx
更接近:
高性能 Web Server / Reverse Proxy

APISIX
更接近:
建立在 Nginx/OpenResty 之上的动态 API Gateway Platform

APISIX 与 Spring Cloud Gateway 怎么看

对于 Java 团队,经常面对:

1
2
3
APISIX
vs
Spring Cloud Gateway

两者不是简单谁替代谁。

Spring Cloud Gateway 的优势往往是:

1
2
3
4
5
6
Java
Spring Ecosystem
Reactor
GatewayFilter
Spring Security
Spring Cloud

如果团队希望所有 Gateway 逻辑:

1
100% Java

它会更加自然。

APISIX 则更强调:

1
2
3
4
5
NGINX/OpenResty 数据面
动态配置
插件化
多语言后端无关
基础设施网关

因此:

1
Java Application Gateway

和:

1
Infrastructure API Gateway

是两个不同的架构取向。

有些企业甚至会形成:

1
2
3
4
5
6
7
Internet

APISIX

Internal Spring Gateway

Microservices

不过这种双网关也会增加:

1
2
3
4
5
Latency
Configuration
Troubleshooting
Observability
Ownership

除非职责划分非常明确,否则不要为了“架构看起来高级”硬套两层 Gateway。


当前版本与旧教程需要特别区分的地方

APISIX 发展速度较快,网上很多文章的“概念”仍然有价值,但命令和默认配置未必还能直接复制。

截至 2026 年 8 月,官方 APISIX 稳定版本为 3.17.0,Ingress Controller 当前文档版本为 2.1.0。

几个典型差异如下:

旧资料中常见内容 当前实践
Dashboard 单独部署 当前 APISIX 已提供内置 Admin UI
Dashboard :9000 当前默认 Admin UI 位于 :9180/ui
admin/admin 不应继续把历史默认账号当当前生产方式
Admin/Gateway/Gateway+Admin 模式名称 当前正式分为 Traditional / Decoupled / Standalone
Consumer 直接保存所有认证 Key 当前可以独立使用 Credential
Plugin 优先级只有 Consumer/Route/PluginConfig/Service 当前还存在 Consumer Group
旧版 Ingress CRD 示例 当前 Ingress Controller 同时重点支持 Gateway API、Ingress 与 APISIX CRD
所有 APISIX 都依赖 etcd Standalone 模式可以不依赖默认 etcd
Standalone 只有 YAML 文件 当前还提供 API-driven Standalone

早期资料中将 APISIX 划分为 Admin、Gateway、Gateway+Admin 的概念,对理解控制面/数据面仍然很有帮助;2023 年 Docker 示例中的独立 Dashboard 和 :9000 入口则属于当时版本语境。

因此看到任何 APISIX 教程,第一件事建议先确认:

1
2
3
4
APISIX Version
Ingress Controller Version
Helm Chart Version
CRD Version

而不是直接:

1
2
3
Ctrl+C
Ctrl+V
kubectl apply

网关配置复制错版本,通常不会因为你复制得很认真就变正确。


常见问题排查

9080 无法访问

先看容器:

1
docker ps

检查:

1
APISIX 是否运行

再看:

1
docker logs <apisix-container>

检查端口:

1
ss -lntp | grep 9080

然后再判断:

1
2
3
4
Docker Port Mapping
Firewall
Security Group
LoadBalancer

不要一上来就怀疑 Route。


返回 404

典型原因:

1
没有匹配 Route

检查:

1
2
3
4
5
6
URI
Host
Method
Header
vars
priority

例如 Route:

1
2
3
4
{
"host": "api.example.com",
"uri": "/orders/*"
}

而你请求:

1
curl http://127.0.0.1:9080/orders/1

Host 实际是:

1
127.0.0.1

自然可能无法命中。

应该测试:

1
2
curl http://127.0.0.1:9080/orders/1 \
-H "Host: api.example.com"

返回 502

一般沿这条链路查:

1
2
3
4
5
6
7
8
9
10
11
Route

Upstream

DNS / Service Discovery

Network

Backend Port

Backend Health

测试 APISIX 节点本身是否能访问:

1
curl http://10.10.10.11:8080/health

检查:

1
2
3
4
5
6
scheme
port
pass_host
upstream_host
DNS
TLS

尤其是 HTTPS Upstream:

1
http

和:

1
https

配错后,很容易表现成 Gateway 502。


限流为什么多节点不准确

如果配置:

1
2
3
{
"policy": "local"
}

Counter 是每个 APISIX 节点自己的。

集群全局配额需要考虑:

1
2
redis
redis-cluster

而不是继续调整:

1
count

这个问题本质上不是“限流算法不准”,而是:

1
Counter Scope

选错了。


Dashboard 9000 打不开

先看 APISIX 版本。

旧教程:

1
2
Standalone Dashboard
:9000

当前 3.17:

1
2
Admin UI
:9180/ui

不要跨版本套默认行为。


配置修改后没有生效

Traditional / Decoupled 环境依次检查:

1
2
3
4
5
6
7
8
9
Admin API 是否成功

etcd 是否正常

APISIX 是否能 Watch etcd

修改的是不是正确集群

Route 是否真的匹配

Standalone File 模式额外检查:

1
apisix.yaml

是否正确完成写入,以及 YAML 是否以:

1
#END

结束。


Admin API 返回 401/403

检查:

1
2
3
4
X-API-KEY
allow_admin
Admin Key Role
访问来源 IP

不要为了排查问题直接把:

1
allow_admin = 0.0.0.0/0

然后忘记改回来。

“暂时全开放一下试试”是许多安全事故的童年照。


K8s Controller 正常,但业务流量不通

把:

1
配置链路

和:

1
业务链路

分别排查。

配置链路:

1
2
3
4
5
Kubernetes API

Ingress Controller

APISIX

流量链路:

1
2
3
4
5
6
7
8
9
Client

Service / LoadBalancer

APISIX Gateway

Kubernetes Service

Pod

Controller 日志没有 Error:

1

业务网络一定通。


生产环境架构建议

一套相对完整的 APISIX 生产环境可以设计成:

flowchart TD
    Internet[Internet]

    DNS[DNS]
    LB[Cloud LB / HAProxy / LVS]

    subgraph DP["APISIX Data Plane"]
        A1[APISIX 1]
        A2[APISIX 2]
        A3[APISIX 3]
    end

    subgraph CP["Control Plane"]
        Admin[Admin API]
        Platform[Gateway Management Platform]
        ETCD[(etcd Cluster)]
    end

    Registry[Service Registry]

    Services[Microservices]

    Metrics[Prometheus]
    Logs[Log Platform]
    Trace[Tracing Platform]

    Internet --> DNS
    DNS --> LB

    LB --> A1
    LB --> A2
    LB --> A3

    Platform --> Admin
    Admin --> ETCD

    ETCD --> A1
    ETCD --> A2
    ETCD --> A3

    Registry --> A1
    Registry --> A2
    Registry --> A3

    A1 --> Services
    A2 --> Services
    A3 --> Services

    A1 --> Metrics
    A2 --> Metrics
    A3 --> Metrics

    A1 --> Logs
    A2 --> Logs
    A3 --> Logs

    A1 --> Trace
    A2 --> Trace
    A3 --> Trace

职责非常清晰:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
DNS
负责域名

LB
负责 APISIX 节点入口高可用

APISIX
负责 API Gateway

etcd
负责 Gateway Configuration

Nacos/K8s/Consul
负责 Service Discovery

Prometheus
负责 Metrics

Logging Platform
负责日志

Tracing Platform
负责链路追踪

生产实践检查清单

上线前至少检查这些方面:

Admin Plane

1
2
3
4
5
Admin API 是否只在内网?
Admin Key 是否更换?
是否限制 allow_admin?
Dashboard 是否真的需要开启?
是否有操作审计?

Data Plane

1
2
3
4
APISIX 是否多实例?
入口 Load Balancer 是否高可用?
Gateway 超时是否配置?
Connection / Keepalive 是否合理?

etcd

1
2
3
4
5
是否高可用?
是否持久化?
是否备份?
磁盘是否可靠?
是否监控容量和延迟?

Route

1
2
3
4
Route 是否存在大量重叠?
Host 是否明确?
priority 是否被滥用?
命名是否统一?

Upstream

1
2
3
4
5
是否配置合理 Timeout?
是否需要 Retry?
是否有 Health Check?
是否明确 Scheme?
是否需要 Service Discovery?

Plugin

1
2
3
4
Plugin 是否放在正确资源层级?
是否存在重复 Plugin?
Priority 是否明确?
自定义 Plugin 是否经过性能测试?

Rate Limit

1
2
3
4
限流维度是什么?
local 还是 cluster?
是否需要 Redis?
拒绝状态码是否合理?

Security

1
2
3
4
5
API Auth 是否开启?
Credential 是否安全存储?
TLS 是否开启?
敏感字段是否进入日志?
Secret 是否明文写在 Git?

Observability

1
2
3
4
5
Metrics 是否接入?
P95/P99 是否监控?
Upstream Error 是否监控?
日志是否有 request_id / trace_id?
Trace 是否贯通?

Release

1
2
3
4
是否支持 Canary?
配置是否版本化?
是否支持快速 Rollback?
升级前是否测试 Plugin Compatibility?

理解 APISIX 最重要的几条原则

学完各种 API 和 Plugin 后,真正值得长期记住的其实不是某个 JSON 字段,而是下面这些设计思想。

配置面和数据面分离

用户请求:

1
Data Plane

配置管理:

1
Control Plane

生产架构越大,这两个边界越应该清晰。

动态配置不应该依赖不断 Reload

APISIX 的核心价值之一,就是通过:

1
2
3
4
5
Lua Runtime
+
etcd Watch
+
In-Memory Configuration

让大部分 Gateway Resource 可以实时变化。

Route、Service、Upstream 要解耦

不要把所有东西都塞进:

1
Route

应该建立:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Route
负责 Match

Service
负责 API Group

Upstream
负责 Backend

PluginConfig
负责 Policy Reuse

Consumer
负责 Caller Identity

Plugin 应该只承担横切逻辑

Gateway Plugin 很适合:

1
2
3
4
5
Auth
Limit
Rewrite
Security
Observability

不适合:

1
2
3
创建订单
计算财务结算金额
执行复杂业务事务

否则 Gateway 会从:

1
Infrastructure

慢慢长成:

1
无法维护的超级业务服务

Gateway 不是解决所有问题的地方

APISIX 可以做:

1
Rate Limit

但不意味着业务服务不用做:

1
Concurrency Control

APISIX 可以做:

1
Authentication

但不意味着业务不用做:

1
Authorization

APISIX 可以做:

1
Retry

但不意味着业务不用设计:

1
Idempotency

APISIX 可以做:

1
Circuit Breaker

但不意味着下游可以完全不考虑:

1
Graceful Degradation

正确的网关设计应该是:

在最合适的层解决最合适的问题。


总结

Apache APISIX 可以先用一个非常简单的模型理解:

1
2
3
4
5
6
7
8
9
Request

Route

Plugin

Upstream

Backend

再向外展开:

1
2
3
4
5
6
7
8
9
                  Admin API
|
v
etcd
|
v
Client → Route → Plugin → Upstream → Backend

Service Discovery

Route 解决请求匹配,Service 解决公共 API 抽象,Upstream 解决 Backend 与负载均衡,Consumer/Credential 解决调用者身份,Plugin 解决认证、限流、改写、缓存、灰度和可观测等横切能力,etcd 则让这些动态资源能够在默认部署模式下快速同步到 APISIX Worker。

从原理上看,APISIX 最有代表性的设计并不是“插件很多”,而是:

1
2
3
4
5
6
7
8
9
10
11
NGINX 的成熟网络能力
+
OpenResty/Lua 的动态执行能力
+
RadixTree 的路由匹配
+
etcd Watch 的动态配置
+
Plugin Phase 的扩展机制
+
独立的 Control/Data Plane 架构

理解这些机制以后,再看:

1
2
3
4
5
6
7
8
Docker
Kubernetes
Nacos
限流
JWT
灰度
Prometheus
自定义 Plugin

都只是同一套核心模型上的不同组合。

真正进入生产环境时,也不应该停留在“能创建 Route”这一层,而应该继续关注:

1
2
3
4
5
6
7
8
9
10
11
12
Admin Plane Security
etcd Reliability
Gateway HA
Route Governance
Upstream Timeout
Health Check
Retry Safety
Cluster Rate Limit
Observability
Secret Management
Canary Release
Version Compatibility

API Gateway 位于几乎所有服务调用之前,所以它既可能成为整套系统最有价值的治理入口,也可能成为影响范围最大的单点。APISIX 提供的是一套强大的流量治理基础设施,而真正决定它是否稳定的,仍然是对控制面、数据面、插件、配置和业务边界是否有足够清晰的工程设计。


Apache APISIX 从入门到原理:架构、路由、插件与生产实践
https://allendericdalexander.github.io/2026/08/13/java/apisix/
作者
AtLuoFu
发布于
2026年8月13日
许可协议