APISIX — 高性能 API 网关
架构设计
Apache APISIX 基于 Nginx + LuaJIT,以 etcd 作为配置中心,实现毫秒级动态路由更新。
Client ──► APISIX(数据平面)──► Upstream
│
etcd(配置存储)
│
APISIX Dashboard / Admin API(控制平面)
APISIX 核心优势:
- 配置变更实时生效(无需 reload)
- 插件热加载
- 支持 WASM 插件
- 原生 eBPF 支持(实验性)核心概念
| 概念 | 说明 |
|---|---|
| Route | 路由规则,匹配请求并转发 |
| Service | 上游服务抽象,可被多个 Route 引用 |
| Upstream | 上游节点集合,支持负载均衡 |
| Plugin | 插件,附加在 Route/Service/Global 上 |
| Consumer | API 消费者,绑定认证凭证 |
| Plugin Config | 可复用的插件配置组 |
基础配置
Admin API 操作
bash
# 创建 Upstream
curl -X PUT http://localhost:9180/apisix/admin/upstreams/1 \
-H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" \
-d '{
"type": "roundrobin",
"nodes": {
"order-service:8080": 1,
"order-service-2:8080": 1
},
"checks": {
"active": {
"http_path": "/health",
"interval": 5,
"healthy": {"successes": 2},
"unhealthy": {"http_failures": 3}
}
}
}'
# 创建 Route
curl -X PUT http://localhost:9180/apisix/admin/routes/1 \
-H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" \
-d '{
"uri": "/api/orders/*",
"methods": ["GET", "POST", "PUT", "DELETE"],
"upstream_id": "1",
"plugins": {
"limit-req": {
"rate": 100,
"burst": 50,
"key": "remote_addr"
},
"jwt-auth": {}
}
}'声明式配置(apisix.yaml)
yaml
# conf/apisix.yaml(DB-less 模式)
routes:
- id: order-route
uri: /api/orders/*
upstream_id: order-upstream
plugins:
jwt-auth: {}
limit-req:
rate: 100
burst: 50
key: remote_addr
upstreams:
- id: order-upstream
type: roundrobin
nodes:
- host: order-service
port: 8080
weight: 1
consumers:
- username: mobile-app
plugins:
jwt-auth:
key: mobile-app-key
secret: my-jwt-secret
#END插件体系
认证插件
JWT Auth:
bash
# 创建 Consumer
curl -X PUT http://localhost:9180/apisix/admin/consumers \
-d '{
"username": "mobile-app",
"plugins": {
"jwt-auth": {
"key": "mobile-app-key",
"secret": "my-jwt-secret",
"algorithm": "HS256",
"exp": 86400
}
}
}'
# 获取 JWT Token
curl http://localhost:9180/apisix/plugin/jwt/sign?key=mobile-app-key
# 请求时携带 Token
curl -H "Authorization: Bearer <token>" http://localhost:9080/api/ordersOAuth 2.0:
bash
curl -X PUT http://localhost:9180/apisix/admin/routes/1 \
-d '{
"uri": "/api/orders/*",
"plugins": {
"openid-connect": {
"client_id": "apisix",
"client_secret": "secret",
"discovery": "https://keycloak:8080/realms/myrealm/.well-known/openid-configuration",
"redirect_uri": "https://api.example.com/callback",
"scope": "openid profile"
}
}
}'流量控制插件
limit-count(计数限流):
json
{
"limit-count": {
"count": 100,
"time_window": 60,
"key": "consumer_name",
"key_type": "var",
"rejected_code": 429,
"rejected_msg": "Too many requests",
"policy": "redis",
"redis_host": "redis",
"redis_port": 6379
}
}traffic-split(流量分割/灰度):
json
{
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream": {
"nodes": {"order-v2:8080": 1},
"type": "roundrobin"
},
"weight": 10
},
{
"weight": 90
}
]
}
]
}
}可观测性插件
json
{
"prometheus": {},
"zipkin": {
"endpoint": "http://zipkin:9411/api/v2/spans",
"sample_ratio": 0.1
},
"skywalking": {
"sample_ratio": 1
},
"http-logger": {
"uri": "http://log-collector:8080/logs",
"batch_max_size": 1000,
"inactive_timeout": 5
}
}WASM 插件
APISIX 支持用 Rust/Go/C++ 编写 WASM 插件:
rust
// Rust WASM 插件示例
use proxy_wasm::traits::*;
use proxy_wasm::types::*;
struct MyPlugin;
impl HttpContext for MyPlugin {
fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
// 添加请求头
self.set_http_request_header("X-Custom-Header", Some("from-wasm"));
Action::Continue
}
}yaml
# 加载 WASM 插件
wasm:
plugins:
- name: my-plugin
priority: 7999
file: /path/to/plugin.wasmKubernetes Ingress
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: order-ingress
annotations:
kubernetes.io/ingress.class: apisix
k8s.apisix.apache.org/sslredirect: "true"
k8s.apisix.apache.org/enable-cors: "true"
spec:
rules:
- host: api.example.com
http:
paths:
- path: /orders
pathType: Prefix
backend:
service:
name: order-service
port:
number: 8080
---
# ApisixRoute CRD(更强大)
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: order-route
spec:
http:
- name: order-rule
match:
hosts:
- api.example.com
paths:
- /orders/*
backends:
- serviceName: order-service
servicePort: 8080
weight: 90
- serviceName: order-service-v2
servicePort: 8080
weight: 10
plugins:
- name: limit-req
enable: true
config:
rate: 100
burst: 50
key: remote_addr故障处理案例
案例一:etcd 连接失败导致配置无法更新
现象:Admin API 返回 500,路由配置无法更新。
排查:
bash
# 检查 etcd 连接
curl http://localhost:9090/v1/healthcheck
# 查看 APISIX 错误日志
tail -f /usr/local/apisix/logs/error.log | grep etcd解决:
- 检查 etcd 集群健康状态
- 检查 APISIX 配置中的 etcd 地址
- APISIX 有本地缓存,etcd 短暂不可用不影响流量转发
案例二:插件执行顺序问题
现象:认证插件在限流插件之后执行,导致未认证请求也消耗限流配额。
解决:APISIX 插件按 priority 排序执行,priority 越大越先执行:
常用插件优先级:
real-ip: 23000
jwt-auth: 2510
key-auth: 2500
limit-req: 1001
limit-count: 1002
proxy-rewrite: 1008认证插件(2500+)默认在限流插件(1000+)之前执行,无需手动调整。
案例三:上游健康检查误判
现象:健康的上游节点被标记为不健康,流量全部打到少数节点。
解决:
bash
# 查看上游健康状态
curl http://localhost:9180/apisix/admin/upstreams/1
# 手动恢复节点
curl -X PATCH http://localhost:9180/apisix/admin/upstreams/1 \
-d '{"nodes": {"order-service:8080": 1}}'
# 调整健康检查阈值(减少误判)
{
"checks": {
"active": {
"interval": 5,
"healthy": {"successes": 3}, # 连续3次成功才标记健康
"unhealthy": {"http_failures": 5} # 连续5次失败才标记不健康
}
}
}APISIX vs Kong 对比
| 维度 | APISIX | Kong |
|---|---|---|
| 性能 | 更高(etcd 动态配置,无 reload) | 高 |
| 配置存储 | etcd | PostgreSQL / DB-less |
| 插件语言 | Lua / WASM / Go / Python | Lua / Go |
| 社区 | Apache 孵化,活跃 | 商业公司主导 |
| 控制台 | APISIX Dashboard(开源) | Kong Manager(部分商业) |
| 云原生 | 原生 K8s 支持 | Kong Ingress Controller |
| 适用场景 | 高性能、云原生 | 企业级、插件生态丰富 |