APISIX 集群支持详解
APISIX 原生支持集群部署,且集群架构是其核心设计之一
集群架构总览
┌─────────────────────────────────────────────────────────────┐
│ 客户端流量 │
└─────────────────────────┬───────────────────────────────────┘
↓
┌───────────────────────┐
│ 负载均衡器 / SLB │
│ (Nginx / 阿里SLB等) │
└───────────┬───────────┘
┌───────────┼───────────┐
↓ ↓ ↓
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ APISIX-1 │ │ APISIX-2 │ │ APISIX-3 │
│ (数据面) │ │ (数据面) │ │ (数据面) │
│ Node1 │ │ Node2 │ │ Node3 │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
└────────────────┼────────────────┘
↓ Watch 监听配置变更
┌──────────────────────────────┐
│ etcd 集群 │
│ etcd-1 etcd-2 etcd-3 │
│ (3节点高可用) │
└──────────────────────────────┘
↑
┌──────────────────────────────┐
│ 控制面 │
│ Admin API + Dashboard │
└──────────────────────────────┘
核心:数据面与控制面分离
APISIX 集群 = 无状态数据面节点 + 有状态 etcd 集群
数据面节点(APISIX 实例):
✅ 完全无状态
✅ 可随意水平扩展
✅ 任意节点宕机不影响其他节点
✅ 配置全量缓存在本地内存
控制面(etcd):
✅ 存储所有路由/插件/上游配置
✅ 变更通过 Watch 机制推送给所有数据面
✅ etcd 本身也支持集群(奇数节点 3/5/7)
集群核心特性
1. 无中心化设计(去中心化)
传统中心化网关集群:
┌─────────────┐
│ 主节点 │ ← 单点,宕机影响全局
│ (Master) │
└──────┬──────┘
┌────────┼────────┐
↓ ↓ ↓
Worker1 Worker2 Worker3
─────────────────────────────────────────
APISIX 集群(无中心):
APISIX-1 ──┐
APISIX-2 ──┼── 都从 etcd 获取配置,地位完全对等
APISIX-3 ──┘
任何一个节点宕机:
✅ 其他节点完全不受影响
✅ 流量自动由 SLB 切走
✅ 无需主从切换
2. 配置一致性保证
配置变更同步流程:
① 管理员通过 Admin API 修改路由
↓
② 写入 etcd 集群(强一致性)
↓
③ 所有 APISIX 节点同时收到 Watch 事件
↓
④ 各节点更新本地内存缓存
↓
⑤ 毫秒内全集群配置统一生效
关键保证:
✅ 任意节点看到的配置完全一致
✅ etcd 宕机期间:数据面继续用本地缓存服务
✅ etcd 恢复后:自动同步最新配置
3. etcd 宕机期间的容灾能力
场景:etcd 集群全部宕机
APISIX 的行为:
┌─────────────────────────────────────┐
│ 数据面继续正常工作! │
│ │
│ 原因:APISIX 启动时将配置全量加载 │
│ 到共享内存(shared dict) │
│ │
│ 影响:无法修改路由/插件配置 │
│ 不影响:现有流量处理(读内存) │
└─────────────────────────────────────┘
etcd 宕机 → 只影响控制面(改配置)
不影响数据面(处理请求)
这是 APISIX 高可用设计的核心之一
集群部署实践
Docker Compose 本地集群(开发验证)
# docker-compose-cluster.yml
version: "3"
services:
# etcd 集群(3节点)
etcd1:
image: bitnami/etcd:3.5.7
environment:
- ETCD_NAME=etcd1
- ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd1:2380
- ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
- ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
- ETCD_ADVERTISE_CLIENT_URLS=http://etcd1:2379
- ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- ETCD_INITIAL_CLUSTER_STATE=new
- ALLOW_NONE_AUTHENTICATION=yes
etcd2:
image: bitnami/etcd:3.5.7
environment:
- ETCD_NAME=etcd2
- ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd2:2380
- ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
- ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
- ETCD_ADVERTISE_CLIENT_URLS=http://etcd2:2379
- ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- ETCD_INITIAL_CLUSTER_STATE=new
- ALLOW_NONE_AUTHENTICATION=yes
etcd3:
image: bitnami/etcd:3.5.7
environment:
- ETCD_NAME=etcd3
- ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd3:2380
- ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
- ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
- ETCD_ADVERTISE_CLIENT_URLS=http://etcd3:2379
- ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- ETCD_INITIAL_CLUSTER_STATE=new
- ALLOW_NONE_AUTHENTICATION=yes
# APISIX 数据面节点1
apisix1:
image: apache/apisix:3.6.0-debian
volumes:
- ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml
ports:
- "9080:9080" # HTTP 流量
- "9443:9443" # HTTPS 流量
depends_on:
- etcd1
- etcd2
- etcd3
# APISIX 数据面节点2
apisix2:
image: apache/apisix:3.6.0-debian
volumes:
- ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml
ports:
- "9081:9080"
- "9444:9443"
depends_on:
- etcd1
- etcd2
- etcd3
# APISIX 数据面节点3
apisix3:
image: apache/apisix:3.6.0-debian
volumes:
- ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml
ports:
- "9082:9080"
- "9445:9443"
depends_on:
- etcd1
- etcd2
- etcd3
# Admin API / 控制面(只需一个)
apisix-dashboard:
image: apache/apisix-dashboard:3.0.0
ports:
- "9000:9000"
depends_on:
- etcd1
# 前端负载均衡
nginx-lb:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx-lb.conf:/etc/nginx/nginx.conf
depends_on:
- apisix1
- apisix2
- apisix3
APISIX 配置文件(连接 etcd 集群)
# config.yaml
apisix:
node_listen: 9080
enable_ipv6: false
deployment:
role: data_plane # 数据面角色
role_data_plane:
config_provider: etcd
etcd:
host: # 连接所有 etcd 节点
- "http://etcd1:2379"
- "http://etcd2:2379"
- "http://etcd3:2379"
prefix: "/apisix"
timeout: 30
# 开启 TLS(生产必须)
tls:
cert: /path/to/etcd-client.crt
key: /path/to/etcd-client.key
verify: true
sni: etcd.cluster.local
Nginx 前端负载均衡配置
# nginx-lb.conf
events { worker_processes auto; }
stream {
upstream apisix_cluster {
least_conn; # 最少连接负载均衡
server apisix1:9080 weight=1;
server apisix2:9080 weight=1;
server apisix3:9080 weight=1;
}
server {
listen 80;
proxy_pass apisix_cluster;
proxy_timeout 30s;
proxy_connect_timeout 5s;
}
}
Kubernetes 集群部署(生产推荐)
Helm 一键部署
# 添加 APISIX Helm 仓库
helm repo add apisix https://charts.apiseven.com
helm repo update
# 创建命名空间
kubectl create namespace apisix
# 部署 APISIX 集群(含 etcd、Dashboard)
helm install apisix apisix/apisix \
--namespace apisix \
--set replicaCount=3 \
--set etcd.replicaCount=3 \
--set dashboard.enabled=true \
--set ingress-controller.enabled=true \
--set apisix.ssl.enabled=true
K8s 部署结构
# apisix-values.yaml
replicaCount: 3 # APISIX 数据面副本数
resources:
requests:
cpu: "2"
memory: "2Gi"
limits:
cpu: "4"
memory: "4Gi"
# 反亲和性:确保节点分散在不同物理机
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: apisix
topologyKey: kubernetes.io/hostname
# HPA 自动扩缩容
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 20
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
# etcd 集群配置
etcd:
replicaCount: 3
persistence:
storageClass: "ssd-storage"
size: 20Gi
# Ingress Controller(让 APISIX 管理 K8s Ingress)
ingress-controller:
enabled: true
config:
apisix:
serviceName: apisix-admin
serviceNamespace: apisix
K8s 内部架构
┌──────────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Node 1 │ │ Node 2 │ │ Node 3 │ │
│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │
│ │ │ apisix │ │ │ │ apisix │ │ │ │ apisix │ │ │
│ │ │ Pod-1 │ │ │ │ Pod-2 │ │ │ │ Pod-3 │ │ │
│ │ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ │
│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │
│ │ │ etcd │ │ │ │ etcd │ │ │ │ etcd │ │ │
│ │ │ Pod-1 │ │ │ │ Pod-2 │ │ │ │ Pod-3 │ │ │
│ │ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ apisix Service (LoadBalancer / NodePort) │ │
│ │ 自动将流量分发到3个 apisix Pod │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ HPA (Horizontal Pod Autoscaler) │ │
│ │ CPU > 70% 自动扩容,最多 20 个副本 │ │
│ └────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
集群限流:跨节点共享计数
集群中最常见的问题:每个节点各自计数,限流不准确
问题场景:
限流设置:100次/分钟/用户
3个 APISIX 节点各自计数:
Node1: 用户A请求 100次 → 不触发限流
Node2: 用户A请求 100次 → 不触发限流
Node3: 用户A请求 100次 → 不触发限流
实际:用户A请求了 300次,但没有任何限流!
解决方案:Redis 集群共享计数
# 配置 limit-count 使用 Redis 集群共享计数
curl -X PUT http://localhost:9180/apisix/admin/routes/1 \
-d '{
"uri": "/api/*",
"plugins": {
"limit-count": {
"count": 100,
"time_window": 60,
"key": "consumer_name",
"policy": "redis-cluster",
"redis_cluster_nodes": [
"redis-node1:6379",
"redis-node2:6379",
"redis-node3:6379"
],
"redis_cluster_name": "apisix-redis-cluster",
"redis_password": "your-password",
"rejected_code": 429
}
},
"upstream": {
"type": "roundrobin",
"nodes": {"backend:8080": 1}
}
}'
加入 Redis 集群后:
Node1 收到用户A请求 → Redis 计数器 +1(当前: 33)
Node2 收到用户A请求 → Redis 计数器 +1(当前: 67)
Node3 收到用户A请求 → Redis 计数器 +1(当前: 100)→ 触发限流!
三个节点共享同一个 Redis 计数器
全局精准限流 ✅
完整集群限流架构
┌─────────────────────────────────────────────────────┐
│ APISIX 集群(3节点) │
│ │
│ Node1: limit-count ──┐ │
│ Node2: limit-count ──┼──→ Redis Cluster(共享计数)│
│ Node3: limit-count ──┘ │
│ │
│ 所有节点读写同一个计数器 → 全局精准限流 │
└─────────────────────────────────────────────────────┘
集群健康检查与故障转移
# 上游健康检查配置
upstream:
type: roundrobin
nodes:
"backend1:8080": 1
"backend2:8080": 1
"backend3:8080": 1
# 主动健康检查(APISIX 主动探测)
checks:
active:
type: http
http_path: "/health"
timeout: 3
interval: 5 # 每5秒检查一次
healthy:
interval: 2
successes: 2 # 连续2次成功 → 标记健康
unhealthy:
interval: 1
http_failures: 3 # 连续3次失败 → 标记不健康
tcp_failures: 2
http_statuses: [500, 502, 503, 504]
# 被动健康检查(基于真实流量判断)
passive:
healthy:
http_statuses: [200, 201, 204]
successes: 3
unhealthy:
http_statuses: [500, 502, 503, 504]
http_failures: 5
tcp_failures: 2
健康检查工作机制:
APISIX 集群每个节点都独立做健康检查
backend2 宕机
↓
Node1 检测到 → 标记 backend2 不健康 → 停止转发
Node2 检测到 → 标记 backend2 不健康 → 停止转发
Node3 检测到 → 标记 backend2 不健康 → 停止转发
backend2 恢复
↓
各节点主动探测成功 → 自动重新加入负载均衡
多机房 / 异地多活部署
┌─────────────────┐ ┌─────────────────┐
│ 机房 A │ │ 机房 B │
│ │ │ │
│ ┌─────────────┐ │ │ ┌─────────────┐ │
│ │ APISIX 集群 │ │ │ │ APISIX 集群 │ │
│ │ Node1 │ │ │ │ Node4 │ │
│ │ Node2 │ │ │ │ Node5 │ │
│ │ Node3 │ │ │ │ Node6 │ │
│ └──────┬──────┘ │ │ └──────┬──────┘ │
│ │ │ │ │ │
│ ┌──────┴──────┐ │ │ ┌──────┴──────┐ │
│ │ etcd 集群 │◄├─────────►│ etcd 集群 │ │
│ │ A1 A2 A3 │ │ 数据同步 │ │ B1 B2 B3 │ │
│ └─────────────┘ │ │ └─────────────┘ │
└─────────────────┘ └─────────────────┘
↑ ↑
└───────────┬───────────────┘
│
全局流量调度
(DNS/GTM/GSLB)
异地多活策略:
✅ 就近接入:用户连接最近的机房
✅ 配置同步:etcd 跨机房数据同步
✅ 机房故障:DNS 切换到另一机房
✅ 数据隔离:各机房 APISIX 前缀区分
机房A: /apisix-dc-a
机房B: /apisix-dc-b
集群运维要点
滚动升级(零停机)
# K8s 环境下滚动升级 APISIX 版本
kubectl set image deployment/apisix \
apisix=apache/apisix:3.7.0-debian \
-n apisix \
--record
# 观察滚动过程(逐个替换 Pod,不中断流量)
kubectl rollout status deployment/apisix -n apisix
# 升级过程:
# Pod-1 → 新版本(等待就绪)
# ↓
# Pod-2 → 新版本(等待就绪)
# ↓
# Pod-3 → 新版本(等待就绪)
# 全程流量不中断 ✅
节点扩缩容
# 手动扩容到5个节点
kubectl scale deployment apisix --replicas=5 -n apisix
# 自动扩缩容已由 HPA 管理
# 新节点启动后自动从 etcd 拉取全量配置
# 无需人工干预,立即加入集群处理流量
集群监控关键指标
必须监控的指标:
APISIX 节点:
├── apisix_http_requests_total 请求总数
├── apisix_http_latency 响应延迟
├── apisix_node_info 节点信息
└── apisix_nginx_http_current_connections 当前连接数
etcd 集群:
├── etcd_server_is_leader 谁是 Leader
├── etcd_server_proposals_failed 提案失败次数
├── etcd_disk_wal_fsync_duration 磁盘写入延迟
└── etcd_network_peer_round_trip_time 节点间延迟
Redis(限流共享计数):
├── redis_connected_clients 连接数
├── redis_commands_processed 命令处理速率
└── redis_cluster_state 集群状态
集群高可用保障总结
┌───────────────────────────────────────────────────────┐
│ APISIX 集群高可用矩阵 │
├─────────────────┬─────────────────────────────────────┤
│ 故障场景 │ 影响 & 应对 │
├─────────────────┼─────────────────────────────────────┤
│ 1个APISIX节点宕机│ ✅ 其他节点继续服务,SLB自动切流 │
├─────────────────┼─────────────────────────────────────┤
│ etcd 1个节点宕机 │ ✅ etcd集群仍有多数派,正常工作 │
├─────────────────┼─────────────────────────────────────┤
│ etcd 全部宕机 │ ✅ 数据面读本地缓存继续服务 │
│ │ ❌ 无法修改路由配置 │
├─────────────────┼─────────────────────────────────────┤
│ Redis 宕机 │ ⚠️ 集群限流降级为本地限流 │
│ │ ✅ 流量处理不中断 │
├─────────────────┼─────────────────────────────────────┤
│ 上游服务宕机 │ ✅ 健康检查自动摘除,故障转移 │
├─────────────────┼─────────────────────────────────────┤
│ 整机房故障 │ ✅ DNS/GTM 切换到另一机房 │
└─────────────────┴─────────────────────────────────────┘
总结
一句话:APISIX 集群是真正的生产级高可用架构 —— 数据面无状态可无限水平扩展,控制面 etcd 集群保证配置一致性,任何单点故障都不会影响流量处理,是企业级 API 网关的标准部署方式。