从Nginx走到Istio:API 网关笔记

这次做微服务改造,从 Nginx 到专业的 API 网关,再到 Istio Gateway,架构演进了好几轮。优势:简单,配置直接 劣势:功能有限,需要写 lua 插件

问题:Lua 开发成本高,维护困难

Kong 基于 OpenResty,插件生态丰富。

最初用 Nginx 做反向代理

简单的反向代理配置

upstream user_service {
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
}

upstream order_service {
    server 192.168.1.20:8080;
    server 192.168.1.21:8080;
}

server {
    listen 80;
    server_name api.example.com;

    # 用户服务
    location /api/users/ {
        proxy_pass http://user_service/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # 订单服务
    location /api/orders/ {
        proxy_pass http://order_service/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

优势:简单,配置直接 劣势:功能有限,需要写 lua 插件

Nginx + Lua 增强

# 鉴权
location /api/ {
    access_by_lua_block {
        local token = ngx.var.http_authorization
        if not token then
            ngx.status = ngx.HTTP_UNAUTHORIZED
            ngx.say("Missing token")
            ngx.exit(ngx.HTTP_UNAUTHORIZED)
        end
        
        -- 验证 token
        local ok, err = verify_token(token)
        if not ok then
            ngx.status = ngx.HTTP_FORBIDDEN
            ngx.say("Invalid token")
            ngx.exit(ngx.HTTP_FORBIDDEN)
        end
    }
    
    proxy_pass http://backend/;
}

问题:Lua 开发成本高,维护困难

专业的 API 网关

Kong 网关

Kong 基于 OpenResty,插件生态丰富。

部署 Kong

# 使用 Docker 部署
docker run -d --name kong \
  -e "KONG_DATABASE=postgres" \
  -e "KONG_PG_HOST=kong-database" \
  -e "KONG_PG_PASSWORD=kong" \
  -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \
  -p 8000:8000 \
  -p 8443:8443 \
  kong:latest

配置路由

# 添加服务
curl -X POST http://localhost:8001/services \
  --data "name=user-service" \
  --data "url=http://user-service:8080"

# 添加路由
curl -X POST http://localhost:8001/services/user-service/routes \
  --data "paths[]=/api/users"

# 启用插件
curl -X POST http://localhost:8001/services/user-service/plugins \
  --data "name=jwt"

优势

  • 插件丰富(鉴权、限流、监控等)
  • 管理界面友好
  • 集群支持

APISIX 网关

APISIX 是国产的 API 网关,基于 Nginx + Lua。

部署 APISIX

# 使用 Docker 部署
docker run -d --name apisix \
  -p 9080:9080 \
  -p 9443:9443 \
  -p 9180:9180 \
  -v "$(pwd)/apisix_conf:/usr/local/apisix/conf" \
  apache/apisix:latest

配置路由

# apisix_conf/config.yaml
routes:
  - uri: /api/users/*
    upstream:
      type: roundrobin
      nodes:
        "192.168.1.10:8080": 1
        "192.168.1.11:8080": 1
    plugins:
      jwt-auth:
        key: my-secret-key
      limit-req:
        rate: 100
        burst: 50
        key_type: var
        key: remote_addr
        rejected_code: 429

优势

  • 性能好
  • 支持动态配置
  • 云原生友好

Kubernetes 环境

Ingress Controller

Kubernetes 的 Ingress Controller 是默认的网关方案。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/enable-cors: "true"
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /api/users
        pathType: Prefix
        backend:
          service:
            name: user-service
            port:
              number: 80
      - path: /api/orders
        pathType: Prefix
        backend:
          service:
            name: order-service
            port:
              number: 80

限制:功能有限,不适合复杂场景

Service Mesh Gateway

Istio Gateway 提供了更强大的功能。

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: api-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "api.example.com"
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: api-virtualservice
spec:
  hosts:
  - "api.example.com"
  gateways:
  - api-gateway
  http:
  - match:
    - uri:
        prefix: /api/users
    route:
    - destination:
        host: user-service
        port:
          number: 80
  - match:
    - uri:
        prefix: /api/orders
    route:
    - destination:
        host: order-service
        port:
          number: 80

核心功能实践

鉴权与认证

JWT 鉴权

plugins:
  jwt-auth:
    key: my-secret-key
    claims_to_verify:
      - exp

OAuth2 鉴权

plugins:
  openid-connect:
    client_id: my-client-id
    client_secret: my-client-secret
    discovery: https://auth.example.com/.well-known/openid-configuration
    introspection_endpoint: https://auth.example.com/oauth/introspect

限流

基于 IP 的限流

plugins:
  limit-req:
    rate: 100
    burst: 50
    key_type: var
    key: remote_addr
    rejected_code: 429

基于用户的限流

plugins:
  limit-req:
    rate: 1000
    burst: 100
    key_type: var
    key: http_x_user_id
    rejected_code: 429

熔断与降级

熔断配置

plugins:
  circuit-breaker:
    break_response_code: 503
    break_response_body: "Service Unavailable"
    max_breaker_sec: 30
    unhealthy:
      http_statuses:
      - 500
      - 502
      - 503
      failures: 3

降级配置

plugins:
  traffic-split:
    rules:
      - match:
          - name: vars
            value: degraded_mode
            value_type: EQUAL
      weighted_upstreams:
        - upstream:
            name: user-service
          weight: 0
        - upstream:
            name: user-service-fallback
          weight: 100

灰度发布

plugins:
  traffic-split:
    rules:
      - weighted_upstreams:
          - upstream:
              name: user-service-v1
            weight: 90
          - upstream:
              name: user-service-v2
            weight: 10

10% 的流量会路由到 v2 版本。

踩过的坑

坑一:网关成为单点

一开始网关只有一个实例,挂了整个服务都不可用。

解决:部署多个网关节点,用负载均衡分发流量。

坑二:插件性能问题

开启了太多插件,导致网关性能下降。

解决

  • 只开启必要的插件
  • 在服务端做复杂逻辑,网关只做路由和鉴权
  • 定期评估插件性能

坑三:配置热更新问题

配置更新后,有些请求还是用的旧配置。

解决:使用网关的配置热更新功能,或者灰度更新。

# Kong 配置热更新
curl -X POST http://localhost:8001/config

选型建议

小团队(<5 个服务)

用 Nginx 就够了,简单直接。

中等团队(5-20 个服务)

Kong 或 APISIX,插件丰富,管理方便。

大团队(>20 个服务)

Istio Gateway,与 Service Mesh 集成,功能强大。

特殊需求

  • 需要高性能:APISIX 或 Nginx
  • 需要丰富插件:Kong
  • 需要与 Service Mesh 集成:Istio
  • 需要自定义逻辑:基于 Lua 或 Go 开发插件

写在最后

API 网关这东西,不是技术问题,是架构问题。

它解决了:

  • 统一入口
  • 鉴权认证
  • 限流熔断
  • 灰度发布
  • 监控日志

但也会带来:

  • 单点风险
  • 性能瓶颈
  • 复杂度增加

选型之前先评估:服务数量、团队规模、功能需求、性能要求。

不是最先进就好用,而是最合适。


这次 API 网关改造花了两周,从 Nginx 迁移到 Kong,再到 Istio Gateway。迁移完成后,鉴权、限流这些功能统一管理,维护成本降低了 40%。

版权声明: 本文首发于 指尖魔法屋-从Nginx走到Istio:API 网关笔记https://blog.thinkmoon.cn/post/60-api-gateway-nginx-istio-architecture-evolution/) 转载或引用必须申明原指尖魔法屋来源及源地址!