开源API网关,到底哪个强?
本文主要分析了 Nginx、Kong、APISIX、Tyk、Zuul、Gravitee 几个开源 API 网关架构及基本功能,测试了一定场景下各个 API 网关的性能,文末附有源码地址。
图片来自 Pexels
我今天就在和大家探讨一下 API Gateway。在微服务的架构下,API 网关是一个常见的架构设计模式。
以下是微服务中常见的问题,需要引入 API 网关来协助解决:
微服务提供的 API 的粒度通常与客户端所需的粒度不同。微服务通常提供细粒度的 API,这意味着客户端需要与多个服务进行交互。例如,如上所述,需要产品详细信息的客户需要从众多服务中获取数据。
不同的客户端需要不同的数据。例如,产品详细信息页面桌面的桌面浏览器版本通常比移动版本更为详尽。
对于不同类型的客户端,网络性能是不同的。例如,与非移动网络相比,移动网络通常要慢得多并且具有更高的延迟。而且,当然,任何 WAN 都比 LAN 慢得多。
这意味着本机移动客户端使用的网络性能与服务器端 Web 应用程序使用的 LAN 的性能差异很大。服务器端 Web 应用程序可以向后端服务发出多个请求,而不会影响用户体验,而移动客户端只能提供几个请求。
微服务实例数量及其位置(主机+端口)动态变化。
服务划分会随着时间的推移而变化,应该对客户端隐藏。
服务可能会使用多种协议,其中一些协议可能对网络不友好。
反向代理和路由:大多数项目采用网关的解决方案的最主要的原因。给出了访问后端 API 的所有客户端的单一入口,并隐藏内部服务部署的细节。
负载均衡:网关可以将单个传入的请求路由到多个后端目的地。
身份验证和授权:网关应该能够成功进行身份验证并仅允许可信客户端访问 API,并且还能够使用类似 RBAC 等方式来授权。
IP 列表白名单/黑名单:允许或阻止某些 IP 地址通过。
性能分析:提供一种记录与 API 调用相关的使用和其他有用度量的方法。
限速和流控:控制 API 调用的能力。
请求变形:在进一步转发之前,能够在转发之前转换请求和响应(包括 Header 和 Body)。
版本控制:同时使用不同版本的 API 选项或可能以金丝雀发布或蓝/绿部署的形式提供慢速推出 API。
断路器:微服务架构模式有用,以避免使用中断。
多协议支持:WebSocket/GRPC。
缓存:减少网络带宽和往返时间消耗,如果可以缓存频繁要求的数据,则可以提高性能和响应时间
API 文档:如果计划将 API 暴露给组织以外的开发人员,那么必须考虑使用 API 文档,例如 Swagger 或 OpenAPI。
API 使用了常见的宠物商店的样例,声明如下:
openapi: "3.0.0"
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
servers:
- url: http://petstore.swagger.io/v1
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
type: integer
format: int32
responses:
'200':
description: A paged array of pets
headers:
x-next:
description: A link to the next page of responses
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
post:
summary: Create a pet
operationId: createPets
tags:
- pets
responses:
'201':
description: Null response
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
schema:
type: string
responses:
'200':
description: Expected response to a valid request
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
schemas:
Pet:
type: object
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: "#/components/schemas/Pet"
Error:
type: object
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string
构建好的 Web 服务通过 Docker Compose 来进行容器化的部署。
version: "3.7"
services:
goapi:
container_name: goapi
image: naughtytao/goapi:0.1
ports:
- "18000:8080"
deploy:
resources:
limits:
cpus: '1'
memory: 256M
reservations:
memory: 256M
nodeapi:
container_name: nodeapi
image: naughtytao/nodeapi:0.1
ports:
- "18001:8080"
deploy:
resources:
limits:
cpus: '1'
memory: 256M
reservations:
memory: 256M
flaskapi:
container_name: flaskapi
image: naughtytao/flaskapi:0.1
ports:
- "18002:8080"
deploy:
resources:
limits:
cpus: '1'
memory: 256M
reservations:
memory: 256M
springapi:
container_name: springapi
image: naughtytao/springapi:0.1
ports:
- "18003:8080"
deploy:
resources:
limits:
cpus: '1'
memory: 256M
reservations:
memory: 256M
这里用户发送的请求 server/service_name/v1/ 会发送给 API 网关,网关通过 service name 来路由到不同的后端服务。
Nginx
由 C 编写,占用的资源和内存低,性能高。
单进程多线程,当启动 Nginx 服务器,会生成一个 master 进程,master 进程会 fork 出多个 worker 进程,由 worker 线程处理客户端的请求。
支持反向代理,支持 7 层负载均衡(拓展负载均衡的好处)。
高并发,Nginx 是异步非阻塞型处理请求,采用的 epollandqueue 模式。
处理静态文件速度快。
高度模块化,配置简单。社区活跃,各种高性能模块出品迅速。
为了实现 API 的路由转发,需要只需要对 Nginx 作出如下的配置:
server {
listen 80 default_server;
location /goapi {
rewrite ^/goapi(.*) $1 break;
proxy_pass http://goapi:8080;
}
location /nodeapi {
rewrite ^/nodeapi(.*) $1 break;
proxy_pass http://nodeapi:8080;
}
location /flaskapi {
rewrite ^/flaskapi(.*) $1 break;
proxy_pass http://flaskapi:8080;
}
location /springapi {
rewrite ^/springapi(.*) $1 break;
proxy_pass http://springapi:8080;
}
}
Nginx 的部署如下:
version: "3.7"
services:
web:
container_name: nginx
image: nginx
volumes:
- ./templates:/etc/nginx/templates
- ./conf/default.conf:/etc/nginx/conf.d/default.conf
ports:
- "8080:80"
environment:
- NGINX_HOST=localhost
- NGINX_PORT=80
deploy:
resources:
limits:
cpus: '1'
memory: 256M
reservations:
memory: 256M
Kong
而 Kong 本身利用这些挂钩来路由和转换请求。数据库支持 Cassandra 或 Postgres 存储所有配置。
我们使用以下的配置部署 Kong 到容器中(省略四个微服务的部署):
version: '3.7'
volumes:
kong_data: {}
networks:
kong-net:
external: false
services:
kong:
image: "${KONG_DOCKER_TAG:-kong:latest}"
user: "${KONG_USER:-kong}"
depends_on:
- db
environment:
KONG_ADMIN_ACCESS_LOG: /dev/stdout
KONG_ADMIN_ERROR_LOG: /dev/stderr
KONG_ADMIN_LISTEN: '0.0.0.0:8001'
KONG_CASSANDRA_CONTACT_POINTS: db
KONG_DATABASE: postgres
KONG_PG_DATABASE: ${KONG_PG_DATABASE:-kong}
KONG_PG_HOST: db
KONG_PG_USER: ${KONG_PG_USER:-kong}
KONG_PROXY_ACCESS_LOG: /dev/stdout
KONG_PROXY_ERROR_LOG: /dev/stderr
KONG_PG_PASSWORD_FILE: /run/secrets/kong_postgres_password
secrets:
- kong_postgres_password
networks:
- kong-net
ports:
- "8080:8000/tcp"
- "127.0.0.1:8001:8001/tcp"
- "8443:8443/tcp"
- "127.0.0.1:8444:8444/tcp"
healthcheck:
test: ["CMD", "kong", "health"]
interval: 10s
timeout: 10s
retries: 10
restart: on-failure
deploy:
restart_policy:
condition: on-failure
db:
image: postgres:9.5
environment:
POSTGRES_DB: ${KONG_PG_DATABASE:-kong}
POSTGRES_USER: ${KONG_PG_USER:-kong}
POSTGRES_PASSWORD_FILE: /run/secrets/kong_postgres_password
secrets:
- kong_postgres_password
healthcheck:
test: ["CMD", "pg_isready", "-U", "${KONG_PG_USER:-kong}"]
interval: 30s
timeout: 30s
retries: 3
restart: on-failure
deploy:
restart_policy:
condition: on-failure
stdin_open: true
tty: true
networks:
- kong-net
volumes:
- kong_data:/var/lib/postgresql/data
secrets:
kong_postgres_password:
file: ./POSTGRES_PASSWORD
数据库选择了 PostgreSQL,开源版本没有 Dashboard,我们使用 RestAPI 创建所有的网关路由:
curl -i -X POST http://localhost:8001/services \
--data name=goapi \
--data url='http://goapi:8080'
curl -i -X POST http://localhost:8001/services/goapi/routes \
--data 'paths[]=/goapi' \
--data name=goapi
使用 K6 压力测试的结果如下:
APISIX
云原生设计,轻巧且易于容器化。
集成了统计和监视组件,例如 Prometheus,Apache Skywalking 和 Zipkin。
支持 gRPC,Dubbo,WebSocket,MQTT 等代理协议,以及从 HTTP 到 gRPC 的协议转码,以适应各种情况。
担当 OpenID 依赖方的角色,与 Auth0,Okta 和其他身份验证提供程序的服务连接。
通过在运行时动态执行用户功能来支持无服务器,从而使网关的边缘节点更加灵活。
支持插件热加载。
不锁定用户,支持混合云部署架构。
网关节点无状态,可以灵活扩展。
APISIX 的架构如下图所示:
我们同样使用 Docker Compose 来部署 APISIX:
version: "3.7"
services:
apisix-dashboard:
image: apache/apisix-dashboard:2.4
restart: always
volumes:
- ./dashboard_conf/conf.yaml:/usr/local/apisix-dashboard/conf/conf.yaml
ports:
- "9000:9000"
networks:
apisix:
ipv4_address: 172.18.5.18
apisix:
image: apache/apisix:2.3-alpine
restart: always
volumes:
- ./apisix_log:/usr/local/apisix/logs
- ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
depends_on:
- etcd
##network_mode: host
ports:
- "8080:9080/tcp"
- "9443:9443/tcp"
networks:
apisix:
ipv4_address: 172.18.5.11
deploy:
resources:
limits:
cpus: '1'
memory: 256M
reservations:
memory: 256M
etcd:
image: bitnami/etcd:3.4.9
user: root
restart: always
volumes:
- ./etcd_data:/etcd_data
environment:
ETCD_DATA_DIR: /etcd_data
ETCD_ENABLE_V2: "true"
ALLOW_NONE_AUTHENTICATION: "yes"
ETCD_ADVERTISE_CLIENT_URLS: "http://0.0.0.0:2379"
ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379"
ports:
- "2379:2379/tcp"
networks:
apisix:
ipv4_address: 172.18.5.10
networks:
apisix:
driver: bridge
ipam:
config:
- subnet: 172.18.0.0/16
创建一个服务的路由的命令如下:
curl --location --request PUT 'http://127.0.0.1:8080/apisix/admin/routes/1' \
--header 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' \
--header 'Content-Type: text/plain' \
--data-raw '{
"uri": "/goapi/*",
"plugins": {
"proxy-rewrite": {
"regex_uri": ["^/goapi(.*)$","$1"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"goapi:8080": 1
}
}
}'
使用 K6 压力测试的结果如下:
Tyk
Tyk 支持不同的运行方式:云,混合(在自己的基础架构中为 GW)和本地。
网关:处理所有应用流量的代理。
仪表板:可以从中管理 Tyk,显示指标和组织 API 的界面。
Pump:负责持久保存指标数据,并将其导出到 MongoDB(内置),ElasticSearch 或 InfluxDB 等。
我们同样使用 Docker Compose 来创建 Tyk 网关来进行功能验证。
version: '3.7'
services:
tyk-gateway:
image: tykio/tyk-gateway:v3.1.1
ports:
- 8080:8080
volumes:
- ./tyk.standalone.conf:/opt/tyk-gateway/tyk.conf
- ./apps:/opt/tyk-gateway/apps
- ./middleware:/opt/tyk-gateway/middleware
- ./certs:/opt/tyk-gateway/certs
environment:
- TYK_GW_SECRET=foo
depends_on:
- tyk-redis
tyk-redis:
image: redis:5.0-alpine
ports:
- 6379:6379
curl --location --request POST 'http://localhost:8080/tyk/apis/' \
--header 'x-tyk-authorization: foo' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "GO API",
"slug": "go-api",
"api_id": "goapi",
"org_id": "goapi",
"use_keyless": true,
"auth": {
"auth_header_name": "Authorization"
},
"definition": {
"location": "header",
"key": "x-api-version"
},
"version_data": {
"not_versioned": true,
"versions": {
"Default": {
"name": "Default",
"use_extended_paths": true
}
}
},
"proxy": {
"listen_path": "/goapi/",
"target_url": "http://host.docker.internal:18000/",
"strip_listen_path": true
},
"active": true
}'
使用 K6 压力测试的结果如下:
Zuul
Zuul 是 Netflix 开源的基于 Java 的 API 网关组件。
zuul-core:该库包含编译和执行过滤器的核心功能。
zuul-simple-webapp:该 Webapp 展示了一个简单的示例,说明如何使用 zuul-core 构建应用程序。
zuul-netflix:将其他 NetflixOSS 组件添加到 Zuul 的库,例如,使用 Ribbon 路由请求。
zuul-netflix-webapp:将 zuul-core 和 zuul-netflix 打包到一个易于使用的程序包中的 webapp。
Hystrix 用于流控。包装对始发地的呼叫,这使我们可以在发生问题时丢弃流量并确定流量的优先级。
Ribbon 是来自 Zuul 的所有出站请求的客户,它提供有关网络性能和错误的详细信息,并处理软件负载平衡以实现均匀的负载分配。
Turbine 实时汇总细粒度的指标,以便我们可以快速观察问题并做出反应。
Archaius 处理配置并提供动态更改属性的能力。
类型:通常定义路由流程中应用过滤器的阶段。(尽管它可以是任何自定义字符串)
执行顺序:在类型中应用,定义跨多个过滤器的执行顺序。
准则:执行过滤器所需的条件。
动作:如果符合条件,则要执行的动作。
class DeviceDelayFilter extends ZuulFilter {
def static Random rand = new Random()
@Override
String filterType() {
return 'pre'
}
@Override
int filterOrder() {
return 5
}
@Override
boolean shouldFilter() {
return RequestContext.getRequest().
getParameter("deviceType")?equals("BrokenDevice"):false
}
@Override
Object run() {
sleep(rand.nextInt(20000)) // Sleep for a random number of
// seconds between [0-20]
}
}
而是通过每个请求唯一的 RequestContext 共享状态。过滤器使用 Groovy 编写。
Pre 过滤器在路由到原点之前执行。示例包括请求身份验证,选择原始服务器以及记录调试信息。
Route 路由过滤器处理将请求路由到源。这是使用 Apache HttpClient 或 Netflix Ribbon 构建和发送原始 HTTP 请求的地方。
在将请求路由到源之后,将执行 Post 过滤器。示例包括将标准 HTTP 标头添加到响应,收集统计信息和指标以及将响应从源流传输到客户端。
在其他阶段之一发生错误时,将执行 Error 过滤器。
对应的 Java 的 POM 如下:
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>naughtytao.apigateway</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.7.RELEASE</version>
<relativePath />
<!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!-- Dependencies -->
<spring-cloud.version>Camden.SR7</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!-- enable authentication if security is included -->
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- API, java.xml.bind module -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.2</version>
</dependency>
<!-- Runtime, com.sun.xml.bind module -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.0.0-M5</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
主要应用代码如下:
package naughtytao.apigateway.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Bean;
import naughtytao.apigateway.demo.filters.ErrorFilter;
import naughtytao.apigateway.demo.filters.PostFilter;
import naughtytao.apigateway.demo.filters.PreFilter;
import naughtytao.apigateway.demo.filters.RouteFilter;
@SpringBootApplication
@EnableAutoConfiguration(exclude = { RabbitAutoConfiguration.class })
@EnableZuulProxy
@ComponentScan("naughtytao.apigateway.demo")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Docker 构建文件如下:
FROM maven:3.6.3-openjdk-11
WORKDIR /usr/src/app
COPY src ./src
COPY pom.xml ./
RUN mvn -f ./pom.xml clean package -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true
EXPOSE 8080
ENTRYPOINT ["java","-jar","/usr/src/app/target/demo-0.0.1-SNAPSHOT.jar"]
路由的配置写在 application.properties 中:
#Zuul routes.
zuul.routes.goapi.url=http://goapi:8080
zuul.routes.nodeapi.url=http://nodeapi:8080
zuul.routes.flaskapi.url=http://flaskapi:8080
zuul.routes.springapi.url=http://springapi:8080
ribbon.eureka.enabled=false
server.port=8080
我们同样使用 Docker Compose 运行 Zuul 的网关来进行验证:
version: '3.7'
services:
gateway:
image: naughtytao/zuulgateway:0.1
ports:
- 8080:8080
volumes:
- ./config/application.properties:/usr/src/app/config/application.properties
deploy:
resources:
limits:
cpus: '1'
memory: 256M
reservations:
memory: 256M
使用 K6 压力测试的结果如下:
在相同的配置条件下(单核,256M),Zuul 的压测结果要明显差于其它几个,只有 200 左右。
Gravitee
Gravitee 是 Gravitee.io 开源的,基于 Java 的,简单易用,性能高,且具成本效益的开源 API 平台,可帮助组织保护,发布和分析您的 API。
Gravitee 可以通过设计工作室和路径的两种方式来创建和管理 API:
Gravity 提供网关,API 门户和 API 管理,其中网关和管理 API 部分是开源的,门户需要注册许可证来使用。
我们同样使用 Docker Compose 来部署整个 Gravitee 的栈:
#
# Copyright (C) 2015 The Gravitee team (http://gravitee.io)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
version: '3.7'
networks:
frontend:
name: frontend
storage:
name: storage
volumes:
data-elasticsearch:
data-mongo:
services:
mongodb:
image: mongo:${MONGODB_VERSION:-3.6}
container_name: gio_apim_mongodb
restart: always
volumes:
- data-mongo:/data/db
- ./logs/apim-mongodb:/var/log/mongodb
networks:
- storage
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:${ELASTIC_VERSION:-7.7.0}
container_name: gio_apim_elasticsearch
restart: always
volumes:
- data-elasticsearch:/usr/share/elasticsearch/data
environment:
- http.host=0.0.0.0
- transport.host=0.0.0.0
- xpack.security.enabled=false
- xpack.monitoring.enabled=false
- cluster.name=elasticsearch
- bootstrap.memory_lock=true
- discovery.type=single-node
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
nofile: 65536
networks:
- storage
gateway:
image: graviteeio/apim-gateway:${APIM_VERSION:-3}
container_name: gio_apim_gateway
restart: always
ports:
- "8082:8082"
depends_on:
- mongodb
- elasticsearch
volumes:
- ./logs/apim-gateway:/opt/graviteeio-gateway/logs
environment:
- gravitee_management_mongodb_uri=mongodb://mongodb:27017/gravitee?serverSelectionTimeoutMS=5000&connectTimeoutMS=5000&socketTimeoutMS=5000
- gravitee_ratelimit_mongodb_uri=mongodb://mongodb:27017/gravitee?serverSelectionTimeoutMS=5000&connectTimeoutMS=5000&socketTimeoutMS=5000
- gravitee_reporters_elasticsearch_endpoints_0=http://elasticsearch:9200
networks:
- storage
- frontend
deploy:
resources:
limits:
cpus: '1'
memory: 256M
reservations:
memory: 256M
management_api:
image: graviteeio/apim-management-api:${APIM_VERSION:-3}
container_name: gio_apim_management_api
restart: always
ports:
- "8083:8083"
links:
- mongodb
- elasticsearch
depends_on:
- mongodb
- elasticsearch
volumes:
- ./logs/apim-management-api:/opt/graviteeio-management-api/logs
environment:
- gravitee_management_mongodb_uri=mongodb://mongodb:27017/gravitee?serverSelectionTimeoutMS=5000&connectTimeoutMS=5000&socketTimeoutMS=5000
- gravitee_analytics_elasticsearch_endpoints_0=http://elasticsearch:9200
networks:
- storage
- frontend
management_ui:
image: graviteeio/apim-management-ui:${APIM_VERSION:-3}
container_name: gio_apim_management_ui
restart: always
ports:
- "8084:8080"
depends_on:
- management_api
environment:
- MGMT_API_URL=http://localhost:8083/management/organizations/DEFAULT/environments/DEFAULT/
volumes:
- ./logs/apim-management-ui:/var/log/nginx
networks:
- frontend
portal_ui:
image: graviteeio/apim-portal-ui:${APIM_VERSION:-3}
container_name: gio_apim_portal_ui
restart: always
ports:
- "8085:8080"
depends_on:
- management_api
environment:
- PORTAL_API_URL=http://localhost:8083/portal/environments/DEFAULT
volumes:
- ./logs/apim-portal-ui:/var/log/nginx
networks:
- frontend
我们使用管理 UI 来创建四个对应的 API 来进行网关的路由,也可以用 API 的方式,Gravitee 是这个开源网关中,唯一管理 UI 也开源的产品。
使用 K6 压力测试的结果如下:
和同样采用 Java 的 Zuul 类似,Gravitee 的响应只能达到 200 左右,而且还出现了一些错误。我们只好再一次提高网关的资源分配到 4 核 2G。
总结
https://github.com/gangtao/api-gateway
作者:Gang Tao
编辑:陶家龙
出处:zhuanlan.zhihu.com/p/358862217
长链接转短链的那些难事!!!
程序员的妈妈居然是产品经理,她会如何逼你结婚?