理解与选择API网关: Kong 的详解
本文已参与「新人创作礼」活动,一起开启掘金创作之路
API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。 API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供REST/HTTP的访问API。服务端通过API-GW注册和管理服务。
为什么需要 API 网关
在微服务架构之下,服务被拆的非常零散,降低了耦合度的同时也给服务的统一管理增加了难度。在旧的服务治理体系之下,鉴权,限流,日志,监控等通用功能需要在每个服务中单独实现,这使得系统维护者没有一个全局的视图来统一管理这些功能。
不需要网关的情况,是由客户端直接访问服务提供方,由注册中心向客户端返回服务方的地址
API网关的功能
- 路由:根据上下文或消息内容将请求发送到不同的目标。
- 转换:负责转换或屏蔽数据的组件。
- 入站和出站流量监控。
- 为API添加身份验证,授权和加密的安全策略。
- 使用策略:它们可以创建消耗,性能和失败策略以保护SLA。
单节点网关 针对不同的客户端的多节点网关
API网关选型
-
私有云开源解决方案: Netflix Zuul,zuul是spring cloud的一个推荐组件,github.com/Netflix/zuu… Kong kong是基于Nginx+Lua进行二次开发的方案, konghq.com/ Tyk是2014年创建的开源API网关,甚至比AWS的API网关即服务功能还要早。Tyk用Golang编写并使用Golang自己的HTTP服务器。
-
公有云解决方案: Amazon API Gateway,aws.amazon.com/cn/api-gate… 阿里云API网关,www.aliyun.com/product/api… 腾讯云API网关, cloud.tencent.com/product/api…
-
自开发解决方案 基于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
API 网关实现对比
kong vs tyk
禁用基本身份验证的结果。纵轴表示每秒请求数(Req / Sec),水平轴表示运行的微服务实例数。
启用基本身份验证的结果。纵轴表示每秒请求数(Req / Sec),水平轴表示运行的微服务实例数。
kong
ref:www.pocketdigi.com/book/kong/
Kong(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 支持功能
-
云原生: 与平台无关,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 的父集
Kong 的管理方式
所有的管理操作都是基于 HTTP Restful API 来进行的,使用Postgres 或者 Cassandra 来存储路由配置,服务配置,upstream 配置等信息。
kong端点
其中 8000/8443 分别是 Http 和 Https 的转发端口,等价于 Nginx 默认的 80 端口,而 8001 端口便是默认的管理端口,我们可以通过 HTTP Restful API 来动态管理 Kong 的配置。
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 可组合使用,但比较复杂,不建议使用。
docker启动kong
# 启动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
基于kong + oauth2 + acl的用户访问权限管理
ref:docs.konghq.com/hub/kong-in…
ref:docs.konghq.com/hub/kong-in…
OAuth2密码模式: 用户认证
acl白名单: 用户分组权限
在网关层做访问权限管控,而非后端应用的业务权限
整体流程
用户认证服务器在Kong的内侧,我们需要通过Kong进行访问
- 用户发送账号密码到 Kong服务器的用户验证API;
- Kong服务器将请求1转发给用户验证服务器;
- 用户认证服务器验证用户账号密码是否正确,如果不正确直接返回错误结果并完成用户认证;如果正确则将:用户账号密码、client_id和client_secret、scope、provision_key、用户ID 发送给 Kong 的OAuth2 接口
- Kong生成access_token并返回给用户认证服务器,并缓存与过期时间相同的 scope,用户ID
- 认证服务器将4中收到的access_token返回请求2给Kong,Kong再返回请求1给用户。
- 用户得到access_token之后,就可以访问有OAuth2验证的接口了。access_token中已隐含了用户ID和scope。
需求
对用户进行分组管理,不同的用户有访问不同api(服务)的权限,类似django admin的用户组功能
由于认证系统是完全可信的内部系统,简单起见使用密码授权方式
实现
服务和权限一对一关系,每一个服务(或者api)拥有唯一的权限名,不同的服务不同的权限, 通过对用户赋予不同的权限,从而限制用户访问指定的api或服务
具体参见: 基于kong + oauth2 + acl的用户访问权限管理
推荐阅读
-
谈API网关和应用网关--从技术选型谈起:API网关的性能是第一指标,一般会选择Kong、Apisix等基于OpenResty+Lua的高性能网关(得益于Ngnix基于C++的高性能无阻塞网络IO模型),应用网关一般是结合自身业务的技术栈来选择,比如SpringCloud Gateway、Zuul等。当然,这也不是绝对的,如果你对 Kong 非常熟悉,用它来做应用网关也不是不可能。 一些开源网关项目的例子: Kong Apisix 特使 Traefik SpringCloud 网关 Zuul / Zuul2 接下来,我们将重点介绍应用网关。在网格中,应用网关侧重于以下功能(与 API 网关不同) 动态路由 服务发现 服务聚合/协调 可观察性 如果您使用的是 Sping 技术栈,使用 SpringCloud Gateway 和 Zuul 可以轻松重用现有类库,如集成您的注册表,使用 Hystrix、resilience4j 完成熔断和限流功能等,快速完成一个生产级可用应用网关,如果引入新的复杂技术栈 成本将直线上升。根据使用场景的不同,性能有时并不是第一指标,但通常我们很容易陷入性能误区。
-
理解与选择API网关: Kong 的详解
-
理解与实战:Java SSH库JSch - 用途解析、四大认证法、无密码登录设置、SSH公钥验证深入讲解、三种选择方案、SFTP文件传输详解、Maven集成及实用代码实例 - 专讲JSch在SFTP文件传输中的应用
-
理解域名层次:一级域、二级域与三级域的区别与应用" "*域名、主域名、子域名详解:对SEO的影响及使用决策" "搭建网站时:二级域名与子目录的选择指南" "详解如何在*域下设置Apache的二级域名" "初学者必读:挑选理想域名的五大关键建议" "构建网站时,一级域名与二级域名的实践配置教程