在Kubernetes中,service IP和Pod IP主要供集群内部访问使用,对于集群外部是不可见的。
流量入口代理作为互联网系统的门户组件,具备众多选型:从老牌代理 HAProxy、Nginx,到微服务 API 网关 Kong、Zuul,再到容器化 Ingress 规范与实现,不同选型间功能、性能、可扩展性、适用场景参差不齐。当云原生时代大浪袭来,Envoy 这一 CNCF 毕业数据面组件为更多人所知。那么,优秀“毕业生”Envoy 能否成为云原生时代下流量入口标准组件?
背景 —— 流量入口的众多选型与场景
在互联网体系下,凡是需要对外暴露的系统几乎都需要网络代理:较早出现的 HAProxy、Nginx 至今仍在流行;进入微服务时代后,功能更丰富、管控能力更强的 API 网关又成为流量入口必备组件;在进入容器时代后,Kubernetes Ingress 作为容器集群的入口,是容器时代微服务的流量入口代理标准。关于这三类典型的七层代理,核心能力对比如下:
从上述核心能力对比来看:
HAProxy&Nginx 在具备基础路由功能基础上,性能、稳定性经历多年考验。Nginx 的下游社区 OpenResty 提供了完善的 Lua 扩展能力,使得 Nginx 可以更广泛的应用与扩展,如 API 网关 Kong 即是基于 Nginx+OpenResty 实现。API 网关作为微服务对外 API 流量暴露的基础组件,提供比较丰富的功能和动态管控能力。Ingress 作为 Kubernetes 入口流量的标准规范,具体能力视实现方式而定。如基于 Nginx 的 Ingress 实现能力更接近于 Nginx,Istio Ingress Gateway 基于 Envoy+Istio 控制面实现,功能上更加丰富(本质上 Istio Ingress Gateway 能力上强于通常的 Ingress 实现,但未按照 Ingress 规范实现)。那么问题来了:同样是流量入口,在云原生技术趋势下,能否找到一个能力全面的技术方案,让流量入口标准化?
API网关
计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决。— David Wheeler
API网关的观念其实和当前流行的SOA架构和微服务架构模式有关。在传统大型企业比较流行的SOA架构中,有一个企业服务总线(ESB)的概念,再ESB中融合了管理、注册、中介、编排、治理等功能,是一个访问高度频繁、功能高度集中的地方,因此常常也是性能瓶颈所在。而在微服务架构中,伴随着去中心化的理念,几乎没有EBS的的概念,分布式服务架构技术不再依赖于具体的服务中心容器技术( ESB),而是将服务寻址和调用完全分开,这样就不需要通过容器作为服务代理,在运行期实现最高效的直连调用。
在微服务架构中,服务的粒度被进一步细分,各个业务服务可以被独立的设计、开发、测试、部署和管理。各个独立部署单元可以用不同的开发测试团队维护,可以使用不同的编程语言和技术平台进行设计,这就要求必须使用一种语言和平台无关的服务协议作为各个单元间的通讯方式。而REST API 由于其简单、高效、跨平台、易开发、易测试、易集成,成为了不二选择。此时如果都是采用客户端和服务器直连的话,那么此时系统就会出现大量的冗余代码和功能,维护起来工作量巨大,而且随着服务增多,出错性也大大的增加。因此一个类似综合前置的系统就产生了,这就是 API 网关(API Gateway)。API 网关作为分散在各个业务系统微服务的 API 聚合点和统一接入点,外部请求通过访问这个接入点,即可访问内部所有的 REST API 服务。
网关的角色是作为一个 API 架构,用来保护、增强和控制对于 API 服务的访问。
API 网关是一个处于应用程序或服务(提供 REST API 接口服务)之前的系统,用来管理授权、访问控制和流量限制等,这样 REST API 接口服务就被 API 网关保护起来,对所有的调用者透明。因此,隐藏在 API 网关后面的业务系统就可以专注于创建和管理服务,而不用去处理这些策略性的基础设施。
通俗的说API网关中就是做一些通用的基础设施功能。类似AOP中的横切关注点概念,把业务系统中涉及的一些通用功能(日志分析、鉴权、路由等)抽取到API网关中统一管理。API 网关不是一个典型的业务系统, 而是一个为了让业务系统更专注与业务服务本身,给API服务提供更多附加能力的一个中间层。
请求接入:作为所有 API 接口服务请求的接入点,管理所有的接入请求;业务聚合:作为所有后端业务服务的聚合点,所有的业务服务都可以在这里被调用;中介策略:实现安全、验证、路由、过滤、流控,缓存等策略,进行一些必要的中介处理;统一管理:提供配置管理工具,对所有 API 服务的调用生命周期和相应的中介策略进行统一管理。
(1)开发维护简单,节约人力成本和维护成本。(2)高性能,节约设备成本,提高系统吞吐能力。(3)高可用(非常重要)(4)方便灵活地实现安全、验证、过滤、聚合、限流、监控等各种策略。
api网关分类
如上图所示,面对互联网复杂的业务系统,基本可以将API网关分成两类:流量网关和业务网关。
流量网关:跟具体的后端业务系统和服务完全无关的部分,比如安全策略、全局性流控策略、流量分发策略等。流量网关的功能跟 Web 应用防火墙(WAF)非常类似。WAF一般是基于 Nginx/OpenResty 的 ngx_lua 模块开发的 Web 应用防火墙。业务网关:针对具体的后端业务系统,或者是服务和业务有一定关联性的部分,并且一般被直接部署在业务服务的前面。业务网关一般部署在流量网关之后,业务系统之前,比流量网关更靠近系统。我们大部分情况下说的 API 网关,狭义上指的是业务网关。并且如果系统的规模不大,我们也会将两者合二为一,使用一个网关来处理所有的工作
开源api网关
目前常见的开源网关大致上按照语言分类有如下几类:
Nginx+lua:Open Resty、Kong、Orange、Abtesting gateway 等Java:Zuul/Zuul2、Spring Cloud Gateway、Kaazing KWG、gravitee、Dromara soul 等Go:Janus、fagongzi、Grpc-gatewayDotnet:OcelotNodeJS:Express Gateway、Micro Gateway
按照使用数量、成熟度等来划分,主流的有 4 个:
OpenRestyKongZuul/Zuul2Spring Cloud Gateway
OpenResty 基于 Nginx,集成了 Lua 语言和 Lua 的各种工具库,可用的第三方模块,这样我们就在 Nginx 既有的高效 HTTP 处理的基础上,同时获得了 Lua 提供的动态扩展能力。官网是这么介绍的:
项目地址:openresty.org/
OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
OpenResty 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。
OpenResty 的目标是让你的 Web 服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。
项目地址:
konghq.com/github.com/kong/kong
Kong 基于 OpenResty,是一个云原生、快速、可扩展、分布式的微服务抽象层(Microservice Abstraction Layer),也叫 API 网关(API Gateway),在 Service Mesh 里也叫 API 中间件(API Middleware)。
Kong 开源于 2015 年,核心价值在于高性能和扩展性。从全球 5000 强的组织统计数据来看,Kong 是现在依然在维护的,在生产环境使用最广泛的 API 网关。
Kong 宣称自己是世界上最流行的开源微服务 API 网关(The World’s Most Popular Open Source Microservice API Gateway)。
项目地址:github.com/Netflix/zuul
Zuul 是 Netflix 开源的 API 网关系统,它的主要设计目标是动态路由、监控、弹性和安全。
Zuul 的内部原理可以简单看做是很多不同功能 filter 的集合
Zuul 1.x 基于同步 IO,也是 Spring Cloud 全家桶的一部分,可以方便的配合 Spring Boot/Spring Cloud 配置和使用。在 Zuul 1.x 里,filter 的种类和处理流程可以参见下图,最主要的就是 pre、routing、post 这三种过滤器,分别作用于调用业务服务 API 之前的请求处理、直接响应、调用业务服务 API 之后的响应处理。
zuul1.x架构图
Zuul 2.x 最大的改进就是基于 Netty Server 实现了异步 IO 来接入请求,同时基于 Netty Client 实现了到后端业务服务 API 的请求。这样就可以实现更高的性能、更低的延迟。此外也调整了 filter 类型,将原来的三个核心 filter 显式命名为:Inbound Filter、Endpoint Filter 和 Outbound Filter。
zuul2.x架构图
项目地址:
github.com/spring-cloud/spring-cloud-gateway/
Spring Cloud Gateway 基于 Java 8、Spring 5.0、Spring Boot 2.0、Project Reactor,发展的比 Zuul 2 要早,目前也是 Spring Cloud 全家桶的一部分。
Spring Cloud Gateway 可以看做是一个 Zuul 1.x 的升级版和代替品,比 Zuul 2 更早的使用 Netty 实现异步 IO,从而实现了一个简单、比 Zuul 1.x 更高效的、与 Spring Cloud 紧密配合的 API 网关。
Spring Cloud Gateway 里明确的区分了 Router 和 Filter,并且一个很大的特点是内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用。
对 Zuul/Zuul2/Spring Cloud Gateway 的一些功能点分析可以参考 Spring Cloud Gateway 作者 Spencer Gibb 的文章:
spencergibb.netlify.com/preso/detroit-cf-api-gateway-2017-03/
(1)实测情况是性能 SCG~Zuul2 << OpenResty ~< Kong << Direct(直连);(2)Spring Cloud Gateway、Zuul2 的性能差不多,大概是直连的40%;(3)OpenResty、Kong 差不多,大概是直连的 60-70%;(4)大并发下,例如模拟 200 并发用户、1000 并发用户时,Zuul2 会有很大概率返回出错。zuul2.x的可用性不好。
以上测试用到的模拟服务和网关 demo 代码,大部分可以在这里找到:
github.com/kimmking/spring-cloud-gateway-demo
脱离场景谈性能,脱离业务谈架构,都是耍流氓。
(1)Kong 的性能非常不错,非常适合做流量网关,并且对于 service、route、upstream、consumer、plugins 的抽象,也是自研网关值得借鉴的。对于复杂系统,不建议业务网关用 Kong,或者更明确的说是不建议在 Java 技术栈的系统深度定制 Kong 或 OpenResty,主要是工程性方面的考虑。毕竟维护lua脚本的工作量和成本不低。
(2)pring Cloud Gateway/Zuul2 对于 Java 技术栈来说比较方便,可以依赖业务系统的一些 common jar。Lua 不方便,不光是语言的问题,更是复用基础设施的问题。另外,对于网关系统来说,性能不是差一个数量级,问题不大,多加 2 台机器就可以搞定。
(3)目前来看 Zuul2 的坑还是比较多的,因此作为java技术栈,比较建议使用 Spring Cloud Gateway 作为基础骨架。
【参考资料】
1、舍弃Kong和Nginx,Apache APISIX 在趣链科技 BaaS 平台的落地实践 - SegmentFault 思否 https://segmentfault.com/a/1190000040499708
2、云原生时代的流量入口:Envoy Gateway https://baijiahao.baidu.com/s?id=1673615010327758104
3、ingress控制器那么多,到底该选哪一个?累觉不爱。 - 知乎 https://zhuanlan.zhihu.com/p/302452502
4、Kong网关、konga、postgresql搭建及使用_Hello,树先生的博客-CSDN博客_kong postgresql https://blog.csdn.net/weixin_43883826/article/details/102841552
5、开源API网关,到底哪个强? https://baijiahao.baidu.com/s?id=1706130807453891043