开源API网关,到底哪个强?

我今天就在和大家探讨一下 API Gateway。在微服务的架构下,API 网关是一个常见的架构设计模式。

目前创新互联已为近1000家的企业提供了网站建设、域名、虚拟主机网站托管运营、企业网站设计、关岭网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。

以下是微服务中常见的问题,需要引入 API 网关来协助解决:

  • 微服务提供的 API 的粒度通常与客户端所需的粒度不同。微服务通常提供细粒度的 API,这意味着客户端需要与多个服务进行交互。例如,如上所述,需要产品详细信息的客户需要从众多服务中获取数据。
  • 不同的客户端需要不同的数据。例如,产品详细信息页面桌面的桌面浏览器版本通常比移动版本更为详尽。
  • 对于不同类型的客户端,网络性能是不同的。例如,与非移动网络相比,移动网络通常要慢得多并且具有更高的延迟。而且,当然,任何 WAN 都比 LAN 慢得多。
  • 这意味着本机移动客户端使用的网络性能与服务器端 Web 应用程序使用的 LAN 的性能差异很大。服务器端 Web 应用程序可以向后端服务发出多个请求,而不会影响用户体验,而移动客户端只能提供几个请求。
  • 微服务实例数量及其位置(主机+端口)动态变化。
  • 服务划分会随着时间的推移而变化,应该对客户端隐藏。
  • 服务可能会使用多种协议,其中一些协议可能对网络不友好。

常见的API网关主要提供以下的功能:

  • 反向代理和路由:大多数项目采用网关的解决方案的最主要的原因。给出了访问后端 API 的所有客户端的单一入口,并隐藏内部服务部署的细节。
  • 负载均衡:网关可以将单个传入的请求路由到多个后端目的地。
  • 身份验证和授权:网关应该能够成功进行身份验证并仅允许可信客户端访问 API,并且还能够使用类似 RBAC 等方式来授权。
  • IP 列表白名单/黑名单:允许或阻止某些 IP 地址通过。
  • 性能分析:提供一种记录与 API 调用相关的使用和其他有用度量的方法。
  • 限速和流控:控制 API 调用的能力。
  • 请求变形:在进一步转发之前,能够在转发之前转换请求和响应(包括 Header 和 Body)。
  • 版本控制:同时使用不同版本的 API 选项或可能以金丝雀发布或蓝/绿部署的形式提供慢速推出 API。
  • 断路器:微服务架构模式有用,以避免使用中断。
  • 多协议支持:WebSocket/GRPC。
  • 缓存:减少网络带宽和往返时间消耗,如果可以缓存频繁要求的数据,则可以提高性能和响应时间
  • API 文档:如果计划将 API 暴露给组织以外的开发人员,那么必须考虑使用 API 文档,例如 Swagger 或 OpenAPI。

有很多的开源软件可以提供 API 网关的支持,下面我们就看看他们各自的架构和功能。

为了对这些开源网关进行基本功能的验证,我创建了一些代码,使用 OpenAPI 生成了四个基本的 API 服务,包含 Golang,Nodejs,Python Flask 和 Java Spring。

API 使用了常见的宠物商店的样例,声明如下:

 
 
 
 
  1. openapi: "3.0.0"
  2. info:
  3.   version: 1.0.0
  4.   title: Swagger Petstore
  5.   license:
  6.     name: MIT
  7. servers:
  8.   - url: http://petstore.swagger.io/v1
  9. paths:
  10.   /pets:
  11.     get:
  12.       summary: List all pets
  13.       operationId: listPets
  14.       tags:
  15.         - pets
  16.       parameters:
  17.         - name: limit
  18.           in: query
  19.           description: How many items to return at one time (max 100)
  20.           required: false
  21.           schema:
  22.             type: integer
  23.             format: int32
  24.       responses:
  25.         '200':
  26.           description: A paged array of pets
  27.           headers:
  28.             x-next:
  29.               description: A link to the next page of responses
  30.               schema:
  31.                 type: string
  32.           content:
  33.             application/json:    
  34.               schema:
  35.                 $ref: "#/components/schemas/Pets"
  36.         default:
  37.           description: unexpected error
  38.           content:
  39.             application/json:
  40.               schema:
  41.                 $ref: "#/components/schemas/Error"
  42.     post:
  43.       summary: Create a pet
  44.       operationId: createPets
  45.       tags:
  46.         - pets
  47.       responses:
  48.         '201':
  49.           description: Null response
  50.         default:
  51.           description: unexpected error
  52.           content:
  53.             application/json:
  54.               schema:
  55.                 $ref: "#/components/schemas/Error"
  56.   /pets/{petId}:
  57.     get:
  58.       summary: Info for a specific pet
  59.       operationId: showPetById
  60.       tags:
  61.         - pets
  62.       parameters:
  63.         - name: petId
  64.           in: path
  65.           required: true
  66.           description: The id of the pet to retrieve
  67.           schema:
  68.             type: string
  69.       responses:
  70.         '200':
  71.           description: Expected response to a valid request
  72.           content:
  73.             application/json:
  74.               schema:
  75.                 $ref: "#/components/schemas/Pet"
  76.         default:
  77.           description: unexpected error
  78.           content:
  79.             application/json:
  80.               schema:
  81.                 $ref: "#/components/schemas/Error"
  82. components:
  83.   schemas:
  84.     Pet:
  85.       type: object
  86.       required:
  87.         - id
  88.         - name
  89.       properties:
  90.         id:
  91.           type: integer
  92.           format: int64
  93.         name:
  94.           type: string
  95.         tag:
  96.           type: string
  97.     Pets:
  98.       type: array
  99.       items:
  100.         $ref: "#/components/schemas/Pet"
  101.     Error:
  102.       type: object
  103.       required:
  104.         - code
  105.         - message
  106.       properties:
  107.         code:
  108.           type: integer
  109.           format: int32
  110.         message:
  111.           type: string

构建好的 Web 服务通过 Docker Compose 来进行容器化的部署。

 
 
 
 
  1. version: "3.7"
  2. services:
  3.   goapi:
  4.     container_name: goapi
  5.     image: naughtytao/goapi:0.1
  6.     ports:
  7.       - "18000:8080"
  8.     deploy:
  9.       resources:
  10.         limits:
  11.           cpus: '1'
  12.           memory: 256M
  13.         reservations:
  14.           memory: 256M
  15.   nodeapi:
  16.     container_name: nodeapi
  17.     image: naughtytao/nodeapi:0.1
  18.     ports:
  19.       - "18001:8080"
  20.     deploy:
  21.       resources:
  22.         limits:
  23.           cpus: '1'
  24.           memory: 256M
  25.         reservations:
  26.           memory: 256M
  27.   flaskapi:
  28.     container_name: flaskapi
  29.     image: naughtytao/flaskapi:0.1
  30.     ports:
  31.       - "18002:8080"
  32.     deploy:
  33.       resources:
  34.         limits:
  35.           cpus: '1'
  36.           memory: 256M
  37.         reservations:
  38.           memory: 256M
  39.   springapi:
  40.     container_name: springapi
  41.     image: naughtytao/springapi:0.1
  42.     ports:
  43.       - "18003:8080"
  44.     deploy:
  45.       resources:
  46.         limits:
  47.           cpus: '1'
  48.           memory: 256M
  49.         reservations:
  50.           memory: 256M

我们在学习这些开源网关架构的同时,也会对其最基本的路由转发功能作出验证。

这里用户发送的请求 server/service_name/v1/ 会发送给 API 网关,网关通过 service name 来路由到不同的后端服务。

我们使用 K6 用 100 个并发跑 1000 次测试的结果如上图,我们看到直连的综合响应,每秒可以处理的请求数量大概是 1100+。

Nginx

Nginx 是异步框架的网页服务器,也可以用作反向代理、负载平衡器和 HTTP 缓存。

该软件由伊戈尔·赛索耶夫创建并于 2004 年首次公开发布。2011 年成立同名公司以提供支持。2019 年 3 月 11 日,Nginx 公司被 F5 Networks 以 6.7 亿美元收购。

Nginx 有以下的特点:

  • 由 C 编写,占用的资源和内存低,性能高。
  • 单进程多线程,当启动 Nginx 服务器,会生成一个 master 进程,master 进程会 fork 出多个 worker 进程,由 worker 线程处理客户端的请求。
  • 支持反向代理,支持 7 层负载均衡(拓展负载均衡的好处)。
  • 高并发,Nginx 是异步非阻塞型处理请求,采用的 epollandqueue 模式。
  • 处理静态文件速度快。
  • 高度模块化,配置简单。社区活跃,各种高性能模块出品迅速。

如上图所示,Nginx 主要由 Master,Worker 和 Proxy Cache 三个部分组成。

Master 主控:NGINX 遵循主从架构。它将根据客户的要求为 Worker 分配工作。

将工作分配给 Worker 后,Master 将寻找客户的下一个请求,因为它不会等待 Worker 的响应。一旦响应来自 Worker,Master 就会将响应发送给客户端。

Worker 工作单元:Worker 是 NGINX 架构中的 Slave。每个工作单元可以单线程方式一次处理 1000 个以上的请求。

一旦处理完成,响应将被发送到主服务器。单线程将通过在相同的内存空间而不是不同的内存空间上工作来节省 RAM 和 ROM 的大小。多线程将在不同的内存空间上工作。

Cache 缓存:Nginx 缓存用于通过从缓存而不是从服务器获取来非常快速地呈现页面。在第一个页面请求时,页面将被存储在高速缓存中。

为了实现 API 的路由转发,需要只需要对 Nginx 作出如下的配置:

 
 
 
 
  1. server {
  2.     listen 80 default_server; 
  3.     location /goapi {
  4.         rewrite ^/goapi(.*) $1 break;
  5.         proxy_pass  http://goapi:8080;
  6.     }
  7.     location /nodeapi {
  8.         rewrite ^/nodeapi(.*) $1 break;
  9.         proxy_pass  http://nodeapi:8080;
  10.     }
  11.     location /flaskapi {
  12.         rewrite ^/flaskapi(.*) $1 break;
  13.         proxy_pass  http://flaskapi:8080;
  14.     }
  15.     location /springapi {
  16.         rewrite ^/springapi(.*) $1 break;
  17.         proxy_pass  http://springapi:8080;
  18.     }
  19. }

我们基于不同的服务 goapi,nodeapi,flaskapi 和 springapi,分别配置一条路由,在转发之前,需要利用 rewrite 来去掉服务名,并发送给对应的服务。

使用容器把 Nginx 和后端的四个服务部署在同一个网络下,通过网关连接路由转发的。

Nginx 的部署如下:

 
 
 
 
  1. version: "3.7"
  2. services:
  3.   web:
  4.     container_name: nginx
  5.     image: nginx
  6.     volumes:
  7.       - ./templates:/etc/nginx/templates
  8.       - ./conf/default.conf:/etc/nginx/conf.d/default.conf
  9.     ports:
  10.       - "8080:80"
  11.     environment:
  12.       - NGINX_HOST=localhost
  13.       - NGINX_PORT=80
  14.     deploy:
  15.       resources:
  16.         limits:
  17.           cpus: '1'
  18.           memory: 256M
  19.         reservations:
  20.           memory: 256M

K6 通过 Nginx 网关的测试结果如下:

每秒处理的请求数量是 1093,和不通过网关转发相比非常接近。

从功能上看,Nginx 可以满足用户对于 API 网关的大部分需求,可以通过配置和插件的方式来支持不同的功能,性能非常优秀。

缺点是没有管理的 UI 和管理 API,大部分的工作都需要手工配置 config 文件的方式来进行。商业版本的功能会更加完善。

Kong

Kong 是基于 NGINX 和 OpenResty 的开源 API 网关。

Kong 的总体基础结构由三个主要部分组成:NGINX 提供协议实现和工作进程管理,OpenResty 提供 Lua 集成并挂钩到 NGINX 的请求处理阶段。

而 Kong 本身利用这些挂钩来路由和转换请求。数据库支持 Cassandra 或 Postgres 存储所有配置。

Kong 附带各种插件,提供访问控制,安全性,缓存和文档等功能。它还允许使用 Lua 语言编写和使用自定义插件。

Kong 也可以部署为 Kubernetes Ingress 并支持 GRPC 和 WebSockets 代理。

NGINX 提供了强大的 HTTP 服务器基础结构。它处理 HTTP 请求处理,TLS 加密,请求日志记录和操作系统资源分配(例如,侦听和管理客户端连接以及产生新进程)。

NGINX 具有一个声明性配置文件,该文件位于其主机操作系统的文件系统中。

虽然仅通过 NGINX 配置就可以实现某些 Kong 功能(例如,基于请求的 URL 确定上游请求路由),但修改该配置需要一定级别的操作系统访问权限,以编辑配置文件并要求 NGINX 重新加载它们。

而 Kong 允许用户执行以下操作:通过 RESTful HTTP API 更新配置。Kong 的 NGINX 配置是相当基本的:除了配置标准标头,侦听端口和日志路径外,大多数配置都委托给 OpenResty。

在某些情况下,在 Kong 的旁边添加自己的 NGINX 配置非常有用,例如在 API 网关旁边提供静态网站。在这种情况下,您可以修改 Kong 使用的配置模板。

NGINX 处理的请求经过一系列阶段。NGINX 的许多功能(例如,使用 C 语言编写的模块)都提供了进入这些阶段的功能(例如,使用 gzip 压缩的功能)。

虽然可以编写自己的模块,但是每次添加或更新模块时都必须重新编译 NGINX。为了简化添加新功能的过程,Kong 使用了 OpenResty。

OpenResty 是一个软件套件,捆绑了 NGINX,一组模块,LuaJIT 和一组 Lua 库。

其中最主要的是 ngx_http_lua_module一个NGINX 模块,该模块嵌入 Lua 并为大多数 NGINX 请求阶段提供 Lua 等效项。

这有效地允许在 Lua 中开发 NGINX 模块,同时保持高性能(LuaJIT 相当快),并且 Kong 用它来提供其核心配置管理和插件管理基础结构。

Kong 通过其插件体系结构提供了一个框架,可以挂接到上述请求阶段。从上面的示例开始,Key Auth 和 ACL 插件都控制客户端(也称为使用者)是否应该能够发出请求。

每个插件都在其处理程序中定义了自己的访问函数,并且该函数针对通过给定路由或服务启用的每个插件执行 kong.access()。

执行顺序由优先级值决定,如果 Key Auth 的优先级为 1003,ACL 的优先级为 950,则 Kong 将首先执行 Key Auth 的访问功能,如果它不放弃请求,则将执行 ACL,然后再通过将该 ACL 传递给上游 proxy_pass。

由于 Kong 的请求路由和处理配置是通过其 admin API 控制的,因此可以在不编辑底层 NGINX 配置的情况下即时添加和删除插件配置。

因为 Kong 本质上提供了一种在 API 中注入位置块(通过 API 定义)和配置的方法。它们通过将插件,证书等分配给这些 API。

我们使用以下的配置部署 Kong 到容器中(省略四个微服务的部署):

 
 
 
 
  1. version: '3.7'
  2. volumes:
  3.   kong_data: {}
  4. networks:
  5.   kong-net:
  6.     external: false
  7. services:
  8.   kong:
  9.     image: "${KONG_DOCKER_TAG:-kong:latest}"
  10.     user: "${KONG_USER:-kong}"
  11.     depends_on:
  12.       - db
  13.     environment:
  14.       KONG_ADMIN_ACCESS_LOG: /dev/stdout
  15.       KONG_ADMIN_ERROR_LOG: /dev/stderr
  16.       KONG_ADMIN_LISTEN: '0.0.0.0:8001'
  17.       KONG_CASSANDRA_CONTACT_POINTS: db
  18.       KONG_DATABASE: postgres
  19.       KONG_PG_DATABASE: ${KONG_PG_DATABASE:-kong}
  20.       KONG_PG_HOST: db
  21.       KONG_PG_USER: ${KONG_PG_USER:-kong}
  22.       KONG_PROXY_ACCESS_LOG: /dev/stdout
  23.       KONG_PROXY_ERROR_LOG: /dev/stderr
  24.       KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password
  25.     secrets:
  26.       - kong_postgres_password
  27.     networks:
  28.       - kong-net
  29.     ports:
  30.       - "8080:8000/tcp"
  31.       - "127.0.0.1:8001:8001/tcp"
  32.       - "8443:8443/tcp"
  33.       - "127.0.0.1:8444:8444/tcp"
  34.     healthcheck:
  35.       test: ["CMD", "kong", "health"]
  36.       interval: 10s
  37.       timeout: 10s
  38.       retries: 10
  39.     restart: on-failure
  40.     deploy:
  41.       restart_policy:
  42.         condition: on-failure
  43.   db:
  44.     image: postgres:9.5
  45.     environment:
  46.       POSTGRES_DB: ${KONG_PG_DATABASE:-kong}
  47.       POSTGRES_USER: ${KONG_PG_USER:-kong}
  48.       POSTGRES_PASSWORD_FILE: /run/secrets/kong_postgres_password
  49.     secrets:
  50.       - kong_postgres_password
  51.     healthcheck:
  52.       test: ["CMD", "pg_isready", "-U", "${KONG_PG_USER:-kong}"]
  53.       interval: 30s
  54.       timeout: 30s
  55.       retries: 3
  56.     restart: on-failure
  57.     deploy:
  58.       restart_policy:
  59.         condition: on-failure
  60.     stdin_open: true
  61.     tty: true
  62.     networks:
  63.       - kong-net
  64.     volumes:
  65.       - kong_data:/var/lib/postgresql/data
  66. secrets:
  67.   kong_postgres_password:
  68.     file: ./POSTGRES_PASSWORD

数据库选择了 PostgreSQL,开源版本没有 Dashboard,我们使用 RestAPI 创建所有的网关路由:

 
 
 
 
  1. curl -i -X POST http://localhost:8001/services \
  2.           --data name=goapi \
  3.           --data url='http://goapi:8080'
  4.     curl -i -X POST http://localhost:8001/services/goapi/routes \
  5.         --data 'paths[]=/goapi' \
  6.           --data name=goapi

需要先创建一个 service,然后在该 service 下创建一条路由。

使用 K6 压力测试的结果如下:

每秒请求数 705 要明显弱于 Nginx,所以所有的功能都是有成本的。

APISIX

Apache APISIX 是一个动态、实时、高性能的 API 网关, 提供负载均衡、动态上游、灰度发布、服务熔断、身份认证、可观测性等丰富的流量管理功能。

APISIX 于 2019 年 4 月由中国的支流科技创建,于 6 月开源,并于同年 10 月进入 Apache 孵化器。

支流科技对应的商业化产品的名字叫 API7 。APISIX 旨在处理大量请求,并具有较低的二次开发门槛。

APISIX 的主要功能和特点有:

  • 云原生设计,轻巧且易于容器化。
  • 集成了统计和监视组件,例如 Prometheus,Apache Skywalking 和 Zipkin。
  • 支持 gRPC,Dubbo,WebSocket,MQTT 等代理协议,以及从 HTTP 到 gRPC 的协议转码,以适应各种情况。
  • 担当 OpenID 依赖方的角色,与 Auth0,Okta 和其他身份验证提供程序的服务连接。
  • 通过在运行时动态执行用户功能来支持无服务器,从而使网关的边缘节点更加灵活。
  • 支持插件热加载。
  • 不锁定用户,支持混合云部署架构。
  • 网关节点无状态,可以灵活扩展。

从这个角度来看,API 网关可以替代 Nginx 来处理南北流量,也可以扮演 Istio 控制平面和 Envoy 数据平面的角色来处理东西向流量。

APISIX 的架构如下图所示:

APISIX 包含一个数据平面,用于动态控制请求流量;一个用于存储和同步网关数据配置的控制平面,一个用于协调插件的 AI 平面,以及对请求流量的实时分析和处理。

它构建在 Nginx 反向代理服务器和键值存储 etcd 的之上,以提供轻量级的网关。

它主要用 Lua 编写,Lua 是类似于 Python 的编程语言。它使用 Radix 树进行路由,并使用前缀树进行 IP 匹配。

使用 etcd 而不是关系数据库来存储配置可以使它更接近云原生,但是即使在任何服务器宕机的情况下,也可以确保整个网关系统的可用性。

所有组件都是作为插件编写的,因此其模块化设计意味着功能开发人员只需要关心自己的项目即可。

内置的插件包括流控和速度限制,身份认证,请求重写,URI 重定向,开放式跟踪和无服务器。

APISIX 支持 OpenResty 和 Tengine 运行环境,并且可以在 Kubernetes 的裸机上运行。它同时支持 X86 和 ARM64。

我们同样使用 Docker Compose 来部署 APISIX:

 
 
 
 
  1. version: "3.7"
  2. services:
  3.   apisix-dashboard:
  4.     image: apache/apisix-dashboard:2.4
  5.     restart: always
  6.     volumes:
  7.     - ./dashboard_conf/conf.yaml:/usr/local/apisix-dashboard/conf/conf.yaml
  8.     ports:
  9.     - "9000:9000"
  10.     networks:
  11.       apisix:
  12.         ipv4_address: 172.18.5.18
  13.   apisix:
  14.     image: apache/apisix:2.3-alpine
  15.     restart: always
  16.     volumes:
  17.       - ./apisix_log:/usr/local/apisix/logs
  18.       - ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
  19.     depends_on:
  20.       - etcd
  21.     ##network_mode: host
  22.     ports:
  23.       - "8080:9080/tcp"
  24.       - "9443:9443/tcp"
  25.     networks:
  26.       apisix:
  27.         ipv4_address: 172.18.5.11
  28.     deploy:
  29.       resources:
  30.         limits:
  31.           cpus: '1'
  32.           memory: 256M
  33.         reservations:
  34.           memory: 256M
  35.   etcd:
  36.     image: bitnami/etcd:3.4.9
  37.     user: root
  38.     restart: always
  39.     volumes:
  40.       - ./etcd_data:/etcd_data
  41.     environment:
  42.       ETCD_DATA_DIR: /etcd_data
  43.       ETCD_ENABLE_V2: "true"
  44.       ALLOW_NONE_AUTHENTICATION: "yes"
  45.       ETCD_ADVERTISE_CLIENT_URLS: "http://0.0.0.0:2379"
  46.       ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379"
  47.     ports:
  48.       - "2379:2379/tcp"
  49.     networks:
  50.       apisix:
  51.         ipv4_address: 172.18.5.10
  52. networks:
  53.   apisix:
  54.     driver: bridge
  55.     ipam:
  56.       config:
  57.       - subnet: 172.18.0.0/16

开源的 APISIX 支持 Dashboard 的方式来管理路由,而不是像 KONG 把仪表盘功能限制在商业版本中。

但是 APISIX 的仪表盘不支持对路由 URI 进行改写,所以我们只好使用 RestAPI 来创建路由。

创建一个服务的路由的命令如下:

 
 
 
 
  1. curl --location --request PUT 'http://127.0.0.1:8080/apisix/admin/routes/1' \
  2. --header 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' \
  3. --header 'Content-Type: text/plain' \
  4. --data-raw '{
  5.     "uri": "/goapi/*",
  6.     "plugins": {
  7.         "proxy-rewrite": {
  8.             "regex_uri": ["^/goapi(.*)$","$1"]
  9.         }
  10.     },
  11.     "upstream": {
  12.         "type": "roundrobin",
  13.         "nodes": {
  14.             "goapi:8080": 1
  15.         }
  16.     }
  17. }'

使用 K6 压力测试的结果如下:

APISix 取得了 1155 的好成绩,表现出接近不经过网关的性能,可能缓存起到了很好的效果。

Tyk

Tyk 是一款基于 Golang 和 Redis 构建的开源 API 网关。它于 2014 年创建,比 AWS 的 API 网关即服务功能早。Tyk 用 Golang 编写,并使用 Golang 自己的 HTTP 服务器。

Tyk 支持不同的运行方式:云,混合(在自己的基础架构中为 GW)和本地。

Tyk 由 3 个组件组成:

  • 网关:处理所有应用流量的代理。
  • 仪表板:可以从中管理 Tyk,显示指标和组织 API 的界面。
  • Pump:负责持久保存指标数据,并将其导出到 MongoDB(内置),ElasticSearch 或 InfluxDB 等。

我们同样使用 Docker Compose 来创建 Tyk 网关来进行功能验证。

 
 
 
 
  1. version: '3.7'
  2. services:
  3.   tyk-gateway:
  4.     image: tykio/tyk-gateway:v3.1.1
  5.     ports:
  6.       - 8080:8080
  7.     volumes:
  8.       - ./tyk.standalone.conf:/opt/tyk-gateway/tyk.conf
  9.       - ./apps:/opt/tyk-gateway/apps
  10.       - ./middleware:/opt/tyk-gateway/middleware
  11.       - ./certs:/opt/tyk-gateway/certs
  12.     environment:
  13.       - TYK_GW_SECRET=foo
  14.     depends_on:
  15.       - tyk-redis
  16.   tyk-redis:
  17.     image: redis:5.0-alpine
  18.     ports:
  19.       - 6379:6379

Tyk 的 Dashboard 也是属于商业版本的范畴,所我们又一次需要借助 API 来创建路由,Tyk 是通过 app 的概念来创建和管理路由的,你也可以直接写 app 文件。

 
 
 
 
  1. curl --location --request POST 'http://localhost:8080/tyk/apis/' \
  2. --header 'x-tyk-authorization: foo' \
  3. --header 'Content-Type: application/json' \
  4. --data-raw '{
  5.     "name": "GO API",
  6.     "slug": "go-api",
  7.     "api_id": "goapi",
  8.     "org_id": "goapi",
  9.     "use_keyless": true,
  10.     "auth": {
  11.       "auth_header_name": "Authorization"
  12.     },
  13.     "definition": {
  14.       "location": "header",
  15.       "key": "x-api-version"
  16.     },
  17.     "version_data": {
  18.       "not_versioned": true,
  19.       "versions": {
  20.         "Default": {
  21.           "name": "Default",
  22.           "use_extended_paths": true
  23.         }
  24.       }
  25.     },
  26.     "proxy": {
  27.       "listen_path": "/goapi/",
  28.       "target_url": "http://host.docker.internal:18000/",
  29.       "strip_listen_path": true
  30.     },
  31.     "active": true
  32. }'

使用 K6 压力测试的结果如下:

Tyk 的结果在 400-600 左右,性能上和 KONG 接近。

Zuul

Zuul 是 Netflix 开源的基于 Java 的 API 网关组件。

Zuul 包含多个组件:

  • zuul-core:该库包含编译和执行过滤器的核心功能。
  • zuul-simple-webapp:该 Webapp 展示了一个简单的示例,说明如何使用 zuul-core 构建应用程序。
  • zuul-netflix:将其他 NetflixOSS 组件添加到 Zuul 的库,例如,使用 Ribbon 路由请求。
  • zuul-netflix-webapp:将 zuul-core 和 zuul-netflix 打包到一个易于使用的程序包中的 webapp。

Zuul 提供了灵活性和弹性,部分是通过利用其他 Netflix OSS 组件进行的:

  • Hystrix 用于流控。包装对始发地的呼叫,这使我们可以在发生问题时丢弃流量并确定流量的优先级。
  • Ribbon 是来自 Zuul 的所有出站请求的客户,它提供有关网络性能和错误的详细信息,并处理软件负载平衡以实现均匀的负载分配。
  • Turbine 实时汇总细粒度的指标,以便我们可以快速观察问题并做出反应。
  • Archaius 处理配置并提供动态更改属性的能力。

Zuul 的核心是一系列过滤器,它们能够在路由 HTTP 请求和响应期间执行一系列操作。

以下是 Zuul 过滤器的主要特征:

  • 类型:通常定义路由流程中应用过滤器的阶段。(尽管它可以是任何自定义字符串)
  • 执行顺序:在类型中应用,定义跨多个过滤器的执行顺序。
  • 准则:执行过滤器所需的条件。
  • 动作:如果符合条件,则要执行的动作。
 
 
 
 
  1. class DeviceDelayFilter extends ZuulFilter {
  2.     def static Random rand = new Random()
  3.     @Override
  4.     String filterType() {
  5.        return 'pre'
  6.     }
  7.     @Override
  8.     int filterOrder() {
  9.        return 5
  10.     }
  11.     @Override
  12.     boolean shouldFilter() {
  13.        return  RequestContext.getRequest().
  14.        getParameter("deviceType")?equals("BrokenDevice"):false
  15.     }
  16.     @Override
  17.     Object run() {
  18.        sleep(rand.nextInt(20000)) // Sleep for a random number of
  19.                                   // seconds between [0-20]
  20.     }
  21. }

Zuul 提供了一个框架来动态读取,编译和运行这些过滤器。过滤器不直接相互通信。

而是通过每个请求唯一的 RequestContext 共享状态。过滤器使用 Groovy 编写。

有几种与请求的典型生命周期相对应的标准过滤器类型:

  • Pre 过滤器在路由到原点之前执行。示例包括请求身份验证,选择原始服务器以及记录调试信息。
  • Route 路由过滤器处理将请求路由到源。这是使用 Apache HttpClient 或 Netflix Ribbon 构建和发送原始 HTTP 请求的地方。
  • 在将请求路由到源之后,将执行 Post 过滤器。示例包括将标准 HTTP 标头添加到响应,收集统计信息和指标以及将响应从源流传输到客户端。
  • 在其他阶段之一发生错误时,将执行 Error 过滤器。

Spring Cloud 创建了一个嵌入式 Zuul 代理,以简化一个非常常见的用例的开发,在该用例中,UI 应用程序希望代理对一个或多个后端服务的调用。

此功能对于用户界面代理所需的后端服务很有用,从而避免了为所有后端独立管理 CORS 和身份验证问题的需求 。

要启用它,请使用 @EnableZuulProxy 注解一个 Spring Boot 主类,这会将本地调用转发到适当的服务。

Zuul 是 Java 的一个库,他并不是一款开箱即用的 API 网关,所以需要用 Zuul 开发一个应用来对其功能进行测试。

对应的 Java 的 POM 如下:

 
 
 
 
  1.     xmlns="http://maven.apache.org/POM/4.0.0"
  2.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4.     4.0.0
  5.     naughtytao.apigateway
  6.    &n

    本文标题:开源API网关,到底哪个强?
    浏览路径:http://www.36103.cn/qtweb/news19/14219.html

    网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

    广告

    声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联