API 网关实战:Kong 与 APISIX 选型、etcd 部署、动态路由与统一限流鉴权全流程

很多个人站长在站点规模变大之后会遇到同一个问题:后端服务越来越多——主站一个进程、图床一个、一个 API 接口服务、一个后台管理、还有几个自建的小工具站。每个服务都直接暴露端口、各自处理跨域、各自加访问控制、各自的限流逻辑写一遍。等到要改一个公共策略(比如全站加一个 IP 白名单、统一加一个请求日志、某个接口要限流),就得挨个服务改一遍,并且每个服务的实现方式还不一样,维护成本成倍上升。

解决这个问题的标准答案,就是引入一层 API 网关(API Gateway)。这篇文章不讲抽象概念,而是用个人站能实际落地的角度,讲清楚网关到底解决什么问题、Kong 和 APISIX 这两个主流开源网关怎么选、以及一个"反代 + 网关"的最小可用架构长什么样。

一、网关到底解决什么问题

先说清楚一个常见误解:API 网关不等于反向代理。Nginx 反代你做的是"把请求转发给后端",它是一个通用的、无状态的分发层;API 网关做的是"在转发的基础上,对每个请求执行一整套策略"——认证、限流、鉴权、熔断、日志、监控、协议转换。这些策略是声明式配置、集中管理的,改一个地方全站生效。

网关真正带来的价值有四点,个人站最该关心的也是这四点:

  • 统一入口:所有服务都藏在网关后面,网关是唯一的公网暴露面。后端服务只绑内网,攻击面一下子收缩了;
  • 统一策略:限流、鉴权、CORS、请求日志这些横切关注点(cross-cutting concerns)在网关一处配置,后端服务完全不用管;
  • 动态路由与灰度:新增一个服务只需在网关加一条路由规则,不用改任何后端代码,很适合个人站渐进式重构;
  • 可观测:所有请求都过网关,天然成为统一的日志和监控采集点。

反过来说,如果你只有一两个服务、也没什么策略需求,那引入网关就是过度设计——Nginx 反代足够。网关的价值随服务数量增长而放大,服务越多越值。

二、Kong 与 APISIX 怎么选

开源 API 网关里,最主流的是 Kong 和 Apache APISIX,两者都基于 Nginx/OpenResty 内核,都提供了丰富的插件生态,架构思路上大同小异。给个人站选,可以从这几个维度权衡:

  • 语言与二次开发:Kong 用 Lua 加部分 Go/Python 插件,社区插件多;APISIX 也是 Lua(OpenResty),并且支持在插件里跑 Java/Wasm,扩展性略强一点;
  • 配置方式:Kong 早期只有 Admin API + 数据库(PostgreSQL/Cassandra),后来出了 DB-less 声明式模式;APISIX 从一开始就有 etcd 作为配置中心,天然支持热更新、无重启生效;
  • 资源占用:APISIX 基于 etcd 存储配置,单机跑起来比 Kong 带数据库轻一些,个人站更友好;
  • 上手难度:两者都有 Docker 一键起,但 APISIX 的 dashboard 和 etcd 组合封装得比较完整,新手体验更顺。

个人站我倾向推荐 APISIX:配置存 etcd(免了数据库依赖)、支持配置热更新(改路由不用重启)、资源占用小、官方 dashboard 开箱即用。当然如果你团队已经熟悉 Kong、或者有现成的 PostgreSQL,用 Kong 也完全没问题。下面以 APISIX 为例讲部署,Kong 的思路完全类似。

三、APISIX 部署:etcd + apisix + dashboard

APISIX 依赖 etcd 存储配置。用 docker-compose 三个服务一起起:

services:
  etcd:
    image: bitnami/etcd:3.5
    restart: unless-stopped
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd:2379
    volumes:
      - ./etcd-data:/bitnami/etcd

  apisix:
    image: apache/apisix:3.9.0-debian
    restart: unless-stopped
    depends_on: [etcd]
    volumes:
      - ./apisix/config.yaml:/usr/local/apisix/conf/config.yaml:ro
    ports:
      - "127.0.0.1:9080:9080"
      - "127.0.0.1:9180:9180"
      - "127.0.0.1:9443:9443"

端口要理解清楚:9080 是网关代理端口(业务流量从这里进)、9180 是 Admin API(配置管理用)、9443 是 HTTPS 代理端口。三个端口一律只绑 127.0.0.1,靠前面的 Nginx 或 CDN 对外。9180 尤其不能暴露——Admin API 没有认证时,任何人调它都能改你的全部路由和插件,等于把网关管理权送人。

config.yaml 里最关键的一项是把 Admin Key 换成随机值:

deployment:
  admin:
    admin_key:
      - name: admin
        key: ChangeMeToARandomAdminKey
        role: admin
    allow_admin:
      - 127.0.0.0/24

allow_admin 是 Admin API 的访问来源白名单,默认只允许本机和内网,这个配置别随便放开。key 用 openssl rand -hex 16 生成。

四、路由与上游:把请求转发到后端服务

网关里两个核心对象:Upstream(上游,即后端服务组) 和 Route(路由,即匹配规则)。先把后端服务登记成 upstream:

curl "http://127.0.0.1:9180/apisix/admin/upstreams/1" \
  -X PUT \
  -H "X-API-KEY: ${ADMIN_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "roundrobin",
    "nodes": {
      "127.0.0.1:9000": 1
    }
  }'

再建一条路由,把路径匹配到该 upstream:

curl "http://127.0.0.1:9180/apisix/admin/routes/1" \
  -X PUT \
  -H "X-API-KEY: ${ADMIN_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "uri": "/api/*",
    "methods": ["GET", "POST"],
    "upstream_id": "1"
  }'

这样访问 http://网关:9080/api/xxx 的请求就会被转发到 127.0.0.1:9000 上的后端服务。注意 upstream_id 和路由里的 id 是分开的,路由也可以内联写 upstream,但拆开更清晰、也方便多路由共用同一个后端组。

节点权重(上面的 "127.0.0.1:9000": 1)在单后端时无所谓,但一旦你同一服务跑两个实例,权重就用于负载均衡分流,这是网关顺手做的事。APISIX 除了 roundrobin(轮询),还支持 chash(一致性哈希)和 least_conn(最少连接)等负载策略——一致性哈希能把同一个用户的请求固定打到同一个后端实例,适合有本地会话或缓存的后端;最少连接则优先把新请求给当前压力小的实例,适合处理耗时差异大的接口。这些同样只是 upstream 里改一个字段,不用动后端分毫。

五、接入插件:限流、鉴权、CORS 一个都不用自己写

插件是网关的灵魂。给上面的路由挂一个限流插件(limit-req),每个 IP 每秒最多 10 次:

curl "http://127.0.0.1:9180/apisix/admin/routes/1" \
  -X PATCH \
  -H "X-API-KEY: ${ADMIN_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "plugins": {
      "limit-req": {
        "rate": 10,
        "burst": 20,
        "rejected_code": 429,
        "key_type": "var",
        "key": "remote_addr"
      }
    }
  }'

rate=10 是稳定速率(每秒 10 个),burst=20 是允许的突发桶容量,超过就返回 429。key=remote_addr 表示按客户端 IP 维度限流,也可以换成按 API Key、按用户 ID。这就是网关最省事的地方——限流逻辑集中一处、对所有后端生效,不用在每个服务里再写一遍。

常用插件还有几个:

  • cors:统一处理跨域预检,后端服务再也不用各自实现 OPTIONS 响应;
  • key-auth / jwt-auth:统一的 API 认证,内部服务之间调用可以走网关鉴权;
  • proxy-cache:网关层缓存后端响应,静态性接口可以直接命中;
  • ip-restriction:IP 黑白名单,把后台管理接口限制到固定 IP;
  • prometheus:把网关的请求指标暴露给监控系统,配合 Grafana 出图。

插件是声明式、可按路由热挂载的——改插件配置不需要重启 APISIX 进程,请求立刻按新策略走,这是相比手工改 Nginx 配置 reload 的明显优势。

六、把网关摆到架构里的正确位置

对个人站,推荐的层次是:CDN → Nginx(反向代理 + HTTPS 终止)→ API 网关 → 后端服务。Nginx 负责 TLS 证书、静态资源、缓存这些边缘工作;网关负责业务路由、策略、鉴权;后端服务只绑内网,永远不直接对外。

网关有几个必须记住的坑:

  1. Admin API(9180)暴露公网——最严重的问题,等于把网关配置权交出去。绑回环 + allow_admin 白名单 + 随机 admin key,三件事都要做;
  2. etcd 没做认证——默认 etcd 无认证时,任何能连到 2379 的人都能读改网关配置。生产至少加 basic auth,并限制 2379 只在内网;
  3. 误把网关当成"又能反代又能做全站"——网关适合 API 和动态请求,静态资源、大文件下载交给 Nginx/CDN 更高效,别让网关承担它不擅长的活;
  4. 后端服务如果还绑着 0.0.0.0 暴露公网——那网关这层就白加了,一定要把后端端口收回到 127.0.0.1 或内网网段;
  5. 配置没纳入版本管理——网关的路由和插件一旦多了,手工改容易乱。建议把 Admin API 的调用写成脚本、存进 Git,跟基础设施一起版本化。

七、个人站该不该上网关

最后给一个务实的判断:服务少于 3 个、没有任何跨服务策略需求的时候,别上网关。Nginx 反代足够,引入 etcd、网关进程、dashboard 反而增加维护负担和故障点。

但只要你的情况符合下面任何一条,网关就开始值回成本:后端服务超过三四个、需要统一限流或鉴权、需要做灰度或 A/B、想让所有请求有统一日志和监控。这时候把横切逻辑从各个服务里抽出来、集中到网关一层,是唯一可持续的方向。对个人站长来说,APISIX 的 etcd 免数据库依赖、配置热更新、资源占用小这几个特点,是最友好的选择。

Last modification:October 13th, 2026 at 01:25 pm

Leave a Comment