API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。
API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供REST/HTTP的访问API。服务端通过API-GW注册和管理服务。
在微服务架构之下,服务被拆的非常零散,降低了耦合度的同时也给服务的统一管理增加了难度。在旧的服务治理体系之下,鉴权,限流,日志,监控等通用功能需要在每个服务中单独实现,这使得系统维护者没有一个全局的视图来统一管理这些功能。
不需要网关的情况,是由客户端直接访问服务提供方,由注册中心向客户端返回服务方的地址
私有云开源解决方案:
Netflix Zuul,zuul是spring cloud的一个推荐组件,https://github.com/Netflix/zuul
Kong kong是基于Nginx+Lua进行二次开发的方案, https://konghq.com/
Tyk是2014年创建的开源API网关,甚至比AWS的API网关即服务功能还要早。Tyk用Golang编写并使用Golang自己的HTTP服务器。
公有云解决方案:
Amazon API Gateway,https://aws.amazon.com/cn/api-gateway/
阿里云API网关,https://www.aliyun.com/product/apigateway/
腾讯云API网关, https://cloud.tencent.com/product/apigateway
自开发解决方案
基于Nginx+Lua+ OpenResty的方案,可以看到Kong,orange都是基于这个方案
基于Netty、非阻塞IO模型。 通过网上搜索可以看到国内的宜人贷等一些公司是基于这种方案,是一种成熟的方案。
基于Node.js的方案。 这种方案是应用了Node.js天生的非阻塞的特性。
基于java Servlet的方案。 zuul基于的就是这种方案,这种方案的效率不高,这也是zuul总是被诟病的原因。
如果没有开源项目的支撑前提下,自己来做这样一套东西,是非常大的一个工作量,而且还要做 API 网关本身的高可用等,如果一旦做不好,有可能最先挂掉的不是你的其他服务,而就是这个API网关。
国外目前比较成型的是kong和tyk
kong是基于ngnix+lua的,它借助于Nginx的事件驱动模型和非阻塞IO,性能方面是非常棒的,但是从公司的角度比较难于找到能去维护这种架构产品的人。 需求评估当前公司是否有这个能力去维护这个产品。
SpringCloud-Zuul 社区活跃,基于 SrpingCloud 完整生态,但因为架构的原因(zull基于 Servlet 框架构建,采用的是阻塞和多线程方式,即一个线程处理一次连接请求,当出现问题时,如后端延迟或设备错误重试,活跃的连接和线程数量会增加,这会加大服务器负载并可能使集群无法承受)在高并发的情况下性能不高,同时需要去基于研究整合开源的适配zuul的监控和管理系统。较新的Spring cloud Gateway和zuul2倒是不错
Tyk用Golang编写,并发性能较好,但一切均导向收费版本,免费版本第一次申请有一年的使用授权.没找到明确表示是否可以免费继续使用的说明.
扩展Tyk需要会Go语言,扩展Kong需要会写lua脚本,使用 zuul 还得会Java
禁用基本身份验证的结果。纵轴表示每秒请求数(Req / Sec),水平轴表示运行的微服务实例数。
启用基本身份验证的结果。纵轴表示每秒请求数(Req / Sec),水平轴表示运行的微服务实例数。
ref:https://www.pocketdigi.com/book/kong/
Kong(https://github.com/Kong/kong) 是一个云原生,高效,可扩展的分布式 API 网关。 自 2015 年在 github 开源后,广泛受到关注,最新版本1.2.1,目前已收获 2.23w+ 的 star,其核心价值在于高性能和可扩展性。
准确地说,Kong是一个使用了lua-nginx-module运行在Nginx之上的Lua应用。Kong没有作为一个module和Nginx一起编译,而是与OpenResty(一个已经包含lua-nginx-module的应用)一起分发。OpenResty不是Nginx的分支,而是一些继承它能力的module的合集。
云原生: 与平台无关,Kong可以从裸机运行到Kubernetes
动态路由:Kong 的背后是 OpenResty+Lua,所以从 OpenResty 继承了动态路由的特性
熔断: 追踪不健康的upstream services,当某服务出现不可用或响应超时的情况时熔断
健康检查: 对upstream services进行主动或者被动地监控
日志: 可以记录通过 Kong 的 HTTP,TCP,UDP 请求和响应。
鉴权: 权限控制,IP 黑白名单
SSL: Setup a Specific SSL Certificate for an underlying service or API.
监控: Kong 提供了实时监控插件
认证: 如数支持 HMAC, JWT, Basic, OAuth2.0 等常用协议
限流: 基于多变量对请求进行阻塞或者限制
REST API: 通过 Rest API 进行配置管理,从繁琐的配置文件中解放
可用性: 天然支持分布式
高性能: 背靠非阻塞通信的 nginx,性能自不用说
插件机制: 提供众多开箱即用的插件,且有易于扩展的自定义插件接口,用户可以使用 Lua 自行开发插件
使用 Kong 之后,Nginx 可以完全摒弃,Kong 的功能是 Nginx 的父集
所有的管理操作都是基于 HTTP Restful API 来进行的,使用Postgres 或者 Cassandra 来存储路由配置,服务配置,upstream 配置等信息。
其中 8000/8443 分别是 Http 和 Https 的转发端口,等价于 Nginx 默认的 80 端口,而 8001 端口便是默认的管理端口,我们可以通过 HTTP Restful API 来动态管理 Kong 的配置。
为了便于理解,将Kong目前能实现模式简单分为两种,以便于理解:Request host 和 Request path。
Request host
- www.domain1.com/api1 → s1.domain1.com/api1
- www.domain1.com/api2 → s1.domain1.com/api2
- ...
- www.domain1.com/* → s1.domain1.com/*
- www.domain2.com/api1 → s2.domain1.com/api1
- www.domain2.com/api2 → s2.domain1.com/api2
- ...
- www.domain2.com/* → s2.domain1.com/*
要在Kong服务器上绑定多个域名。(提供api服务的服务器可以没有域名绑定,只要有IP即可)
Request path
- www.domain1.com/s1/api1 → s1.domain1.com/s1/api1
- www.domain1.com/s1/api2 → s1.domain1.com/s1/api2
- ...
- www.domain1.com/s1/* → s1.domain1.com/s1/*
- www.domain1.com/s2/api1 → s2.domain1.com/s2/api1
- www.domain1.com/s2/api2 → s2.domain1.com/s2/api2
- ...
- www.domain1.com/s2/* → s2.domain1.com/s2/*
Kong服务器上只需要绑定一个域名,不同的API集合依靠不同的请求路径实现。(同上,提供api服务的服务器可以没有域名绑定,只要有IP即可)
Request host 和 Request path 可组合使用,但比较复杂,不建议使用。
# 启动kong使用的数据库postgres/cassandra
docker run -d --name kong-database \
-p 5432:5432 \
-e "POSTGRES_USER=kong" \
-e "POSTGRES_DB=kong" \
postgres:9.6
# kong配置数据初始化
docker run --rm \
--link kong-database:kong-database \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
kong:0.14.0 kong migrations up
# 启动kong容器
docker run -d --name kong \
--link kong-database:kong-database \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \
-e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \
-e "KONG_PROXY_ERROR_LOG=/dev/stderr" \
-e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \
-e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" \
-p 8000:8000 \
-p 8443:8443 \
-p 8001:8001 \
-p 8444:8444 \
kong:0.14.0
ref:https://docs.konghq.com/hub/kong-inc/oauth2/
ref:https://docs.konghq.com/hub/kong-inc/acl/
OAuth2密码模式: 用户认证
acl白名单: 用户分组权限
在网关层做接入权限管控,而非后端应用的业务权限
用户认证服务器在Kong的内侧,我们需要通过Kong进行访问
对用户进行分组管理,不同的用户有访问不同api(服务)的权限,类似django admin的用户组功能
由于认证系统是完全可信的内部系统,简单起见使用密码授权方式
服务和权限一对一关系,每一个服务(或者api)拥有唯一的权限名,不同的服务不同的权限, 通过对用户赋予不同的权限,从而限制用户访问指定的api或服务
具体参见: 基于kong + oauth2 + acl的用户接入权限管理