作者 | 蔡芳芳
近日,阿里巴巴正式开源云原生网关Higress。Higress 是基于阿里内部两年多的 Envoy Gateway 实践沉淀、以开源 Istio + Envoy 为核心构建的下一代云原生网关,在标准上全面支持 Ingress 与 Gateway API,积极拥抱云原生下的标准 API 规范。此外,Higress Controller 支持 Nginx Ingress 平滑迁移,用户可以几乎零成本快速迁移到 Higress。
在容器化的云原生大背景下,Kubernetes 已经成为了基础设施与上层应用的标准接口,而 Kubernetes Ingress 又标准化了入口网关,同时社区也在积极推进 Gateway API 的标准定义来解决目前 Ingress 标准存在的一些不足,如路由能力偏弱、配置不够灵活等问题。
大家想到网关可能第一直觉会联想到 API 网关,这里有一个挺有意思的问题:在网关或者 Web 流量场景下什么是 API 呢?
回归到原始概念下,它代指一组具备某些特性的流量,用于描述该特征流量的规则称为路由规则,在 API 管理领域称为 API,在路由规则或者 API 之上可以附加很多策略,如熔断、限流、降级、认证与鉴权等等。在 Kubernetes 生态,Ingress 与 Gateway API 是用于定义路由规则的,因此 Ingress 与 Gateway API 事实上已经成为云原生下的标准 API 规范。
阿里巴巴从 2017-2018 年开始探索 Service Mesh,基于这些探索沉淀了大量 Istio 和 Envoy 的实践经验,不过早期这些实践并不太涉及网关场景。
2020 年,在代号为“本地生活战役”的项目背景下,阿里集团和蚂蚁集团两侧有一些业务上互相访问的诉求(比如支付宝首页需要展示跟本地生活相关的推送、商品信息,而这些信息往往存储在阿里侧),出于安全性和业务快速迭代的考虑,双方技术团队希望打造一个新的互通网关,通过走内部 RPC 调用的方式实现互通,替代掉原来走公网的方式。同时,大家希望借这个机会把两边的 RPC 协议定义成一个统一规范。以此为契机,阿里开始了基于 Envoy 打造下一代云原生网关的探索。
本文出自 InfoQ 特别策划的专题《Envoy 当道?云原生时代的下一代网关选型和实践》。我们专访了阿里云研发工程师耿蕾蕾(如葑),深入挖掘阿里巴巴针对云原生网关的技术选型思考和实践路径,希望能为想要进一步了解 Envoy 和打造下一代网关的技术团队提供参考。
阿里内部一直使用基于 Nginx 演进而来的 Tengine 作为统一接入网关。因此最初做新网关技术选型时,其实有两种演进思路,一种是基于 Tengine 优化,一种是基于 Envoy 内核来扩展网关场景。当时,如葑所在团队本身就负责 Tengine 的维护工作,同时也参与探索阿里内部 Service Mesh 的落地,因此团队对 Tengine 和 Istio+Envoy 这两套技术栈都比较熟悉,技术储备上都不存在障碍。选型的关键在于,哪种技术方案可以更简单地支持前文所述的统一 RPC 协议(这个由两方团队合作定义出的统一 RPC 协议,即后来 Dubbo 3.0 中支持的 Triple 协议)。
据介绍,Triple 协议是一种类 gRPC 协议,它的大部分能力复用了 gRPC,比如序列化和通讯协议等。因此在选型网关时,首先需要新网关对 gRPC 支持友好,这样后续支持 Triple 协议的研发工作难度会小很多。恰恰当时 Tengine 上游对 gPRC 的支持并不完善,而 Envoy 诞生在 Tengine 之后,对 gRPC 的支持相对完善很多。如果选择 Tengine 的技术路线,团队前期需要投入很大的人力把 Tengine 上游支持 gRPC 的能力补齐,如果选择 Envoy 则不需要在这方面投入额外人力了。当时基于这一点考虑,团队几乎就要把 Tengine 这个思路 Pass 掉了。
此外,Tengine(和 Nginx)还存在 Reload 访问有损的问题。由于不支持配置热更新机制,Tengine 在做配置变更的时候需要 Reload,而 Reload 对于长连接会引起抖动,导致流量短暂中断,但恰恰在 RPC 请求场景下大部分连接都是长连接。这意味着,如果要让互通网关做到接入服务快速生效,就要频繁做配置变更,Tengine 就要频繁地 Reload,长连接会频繁抖动,导致流量严重抖动。如果要控制 Reload 影响则只能减少 Reload 次数,但这又会导致接入服务生效变慢。相比之下,Envoy 原生通过 xDS 支持配置热更新,就不存在这个问题。这也是团队在做技术选型时重点考量的一点。
当然,也有团队成员对选型 Envoy 心存疑虑。毕竟 Tengine 脱胎于 Nginx,而 Nginx 作为老牌网关已经在行业内应用多年,不管是业界口碑还是性能表现都很受推崇,相比之下 Envoy 只能算是初入江湖的“萌新”选手。被挑战最多的一点是,Envoy 的性能是不是能够达到 Nginx 同等水平?或者说,至少不能出现量级的差异。针对这一点,团队找了一些网关场景,针对 gRPC 协议专门做了压测。压测结果表明,未作任何优化的情况下,Envoy 的性能确实不能完全跟 Nginx 或 Tengine 持平,但还在同一个量级上,并没有出现跨量级的性能损失,而这种同一量级的性能差异是可以通过一定的性能优化工作补齐的。
并且,在打造互通网关的项目中,原本就必须做一些整体的性能优化工作。
还有另外一个因素坚定了团队选择 Envoy。当时阿里内部已经在重点推进 Service Mesh 落地,而 Service Mesh 架构本身就包括东西向使用 Sidecar 做服务治理,同时还有一个基于 Istio+Envoy 的 Gateway 负责做跨集群之间的流量互通。如果选择 Envoy 作为网关,后续就有可能跟 Service Mesh 整合成一个大的流量调度方案,在阿里内部实现以一套技术架构同时调度南北向外部流量和东西向内部流量。从长远来看,这是更有利于未来向统一应用架构技术栈演进的选择。
由于业务体量庞大,阿里对 Envoy Gateway 的探索主要通过对单点业务场景改造的方式来推进。阿里和蚂蚁的互通网关是第一个落地场景,如葑将其称为Envoy Gateway 1.0阶段。
这一阶段 Envoy Gateway 要应用于东西向流量的 RPC 互通,其架构部署如下图:
上图主要展示的是集团侧的架构,最终采用了 Istio+Envoy 的方案,在部署的时候又分成了出口集群和入口集群。之所以拆成两个集群,一方面是当时两边互访,蚂蚁调集团的流量要远远大于集团调蚂蚁的流量,上下行特别不均等;另一方面是分开之后两个集群可以各自维护,稳定性会更好。
Envoy Gateway 1.0 从开始立项到完成第一期研发,网关改造的核心工作差不多两个人投入了一个半月左右,其中还涉及到大量网络、安全等协调部门的工作。1.0 架构并没有完全按照社区方案来设计,社区版本中配置变更和服务发现使用的是 K8s,在阿里内部庞大的服务规模及配置量下社区原生方案不管在稳定性及性能上都无法满足要求,因此阿里这套方案重点对服务发现、配置存储组件做了替换,及优化 xDS 推送性能。
这一阶段,团队基于 Envoy 演进了网关的服务管理能力,支撑了当年双十一本地生活战役数十万 TPS 的流量洪峰。基于 Envoy Gateway 的互通网关给业务带来了实打实的收益。一方面,基于 RPC 调用方式,互访请求的延时远远好于原来走公网的方式,并且对此专门做过压测,整体延时降低了 50%-60%,同时在网关侧的延时消耗几乎可以忽略不计,对用户体验的提升非常明显。另一方面,业务上线迭代速度也加快了,原来蚂蚁和阿里要调用对方一个业务,首先要走完一套安全合规的审批流程,然后配置变更走以前的统一接入网关 Tengine,至少以天为单位,改造后走新的互通网关,业务上线时间可以缩短到小时级别,具体耗时主要取决于审批流程的快慢,网关侧支持热更新,一旦发出配置变更几乎是秒级生效。
随着阿里巴巴上云战役的推进,越来越多的场景找到如葑的团队。比如云上云下业务互通,由于 Tengine 服务管理弱导致阿里内部大量二层微服务网关需要收敛,这就需要从业务上做 Tengine+Envoy 两层网关的演进,承担南北向网关流量。在 2020 年 12 月份,团队开始了向 Envoy Gateway 2.0 架构的演进,以优酷场景为例的演进过程如下图:
Envoy Gateway 2.0 南北向的架构图如下:
在两层架构中,Envoy 网关更多承担了微服务网关和微服务治理的需求,和 Tengine 流量网关完成了整合。在这个过程里,团队支撑优酷内部多个二层微服务网关统一的工作,大幅提升了性能和运维效率。
在这一阶段,Envoy Gateway 实现了东西向、南北向全域流量的调度分发,东西向上不仅支持跨业务域的蚂蚁 RPC 互通,也扩展到了混合云的云上云下 RPC 互通场景,覆盖钉钉文档、阿里视频云、达摩院的店小蜜、智慧数字人等。2.0 阶段的业务大图如下(云上云下互通场景,以钉钉为例说明):
随着 Envoy Gateway 覆盖的业务场景越来多,在跟优酷持续合作的过程中,双方团队不约而同提出了一个设想:Tengine Gateway(承担流量网关角色) + Envoy Gateway(承担微服务网关角色)的两层网关是否可以合并为一层 Envoy Gateway?
如葑和团队对这一想法做了调研,答案是肯定的,并且当时大家也合作设计了新的架构方案,如下图:
虽然由于各种各样的原因,这个方案最终没有跟优酷继续往下推进。但这个演进方向让如葑和团队明确了网关新的发展趋势:在以 K8s 主导的容器化背景下,由于 K8s 集群内外网络的天然隔离性,用户需要一款兼顾高性能与安全性,以及强大服务治理能力的入口网关。这也为后续团队将技术沉淀变成云产品、推进 Higress 的诞生打下了基础。
2021 年,阿里巴巴开启了中间件三位一体战役,目标是用云产品支撑集团业务。如葑和团队开始将孵化成熟的技术沉淀为云产品,即目前阿里云上提供的 MSE 云原生网关,一方面面向广大的公有云用户提供托管的网关服务,另一方面也对内服务集团。
目前 MSE 云原生网关已经支持通过 Envoy 将流量网关 + 微服务网关合二为一的技术方案。同时,通过硬件加速、内核优化等手段,团队也在持续不断地优化网关性能和网关资源部署成本。在功能扩展性上,团队做了高可用流量防护组件 Sentinel 商业化版本的集成,并支持将 K8s 的 Ingress 资源自动转换成 Enovy 网关能够识别的配置,便于大家从 Nginx 迁移到 Envoy 网关。
如今,这套经过内部实践沉淀下来的云原生网关方案 Higress 正式对外开源,以 Kubernetes Ingress 网关为契机带来了流量网关与微服务网关融合的可能性,结合阿里内部实践沉淀 Higress 实现了流量网关 + 微服务网关 + 安全网关三合一的高集成能力,同时深度集成了 Dubbo、Nacos、Sentinel 等,能够帮助用户极大的降低网关的部署及运维成本,而且能力不打折。
软件的扩展性是个持久的话题,Kubernetes 的成功离不开其强大 Controller 扩展能力的支持。据如葑介绍,Higress 提供多种形式的扩展机制,包括 Wasm 插件、Lua 插件、进程外插件,通过丰富的插件扩展机制,用户就可以使用多语言编写扩展插件。这能有效降低插件编写门槛,满足用户自定义的扩展诉求。
如何定义下一代云原生网关,大家可能看法各异。经过这几年在网关方向上的实践,如葑及团队也有一些思考。
在他看来,下一代云原生网关首先一定要对 Kubernetes 友好,在云原生的大背景下,必须能原生地支持相应特性,而不是依靠插件化的方式来支持,这是至关重要的一点。
其次,要具备丰富的可观测性,不管是初始化状态还是持续运行状态都要能提供丰富的指标数据,用于观测和后续的自动化运维/AI 智能运维。网关作为总的流量入口,对安全性、稳定性和性能要求都很高,目前有一些可观测解决方案通过添加 Sidecar 或者注入代码来提取可观测数据,这种方法对网关来说并不可行,更多还是要依靠网关自身来提供可观测能力。
再次,过去传统网关常常是流量网关+业务网关(或微服务网关)两层架构,不仅运维成本高,资源部署成本也比较高。在云原生时代,K8s 已经成为事实上的运维底座,由于 K8s 集群网络天然是隔离的,就诞生了 Ingress 网关,来解决流量入口的问题,而这个 Ingress 网关完全可以将过去的两层网关架构合二为一,成为一个功能更强大的网关。
生于云原生时代的“后浪”Envoy 天然能满足以上三点需求。
如葑表示,虽然国内目前使用 Envoy 作为网关的开源项目或商业化产品不多,但是国外使用 Envoy 作为网关的产品或案例并不少,比如Tetrate、Gloo Edge、Ambassador(网关改名为 Emissary-ingress)等,虽然有的使用 Istio 作为控制面,有的选择自建控制面板,但大家都不约而同地把 Envoy 作为未来演进路线的一种选择。知名企业如 Twitter、Lyft 等也都在使用 Envoy 作为网关或者把网关往 Envoy 上面迁移。
这首先得益于 Envoy 原生支持配置热更新,在如葑看来,这是一个非常重要的特性。现在已经有很多主流应用选择采用长连接,现在的 HTTP 1.1 一般默认会使用 Keep-Alive 去保持长连接,后续 HTTP 2 以及 HTTP 3 也是如此,随着网络协议的发展,未来使用长连接会变得更加普遍。而配置热更新天然对长连接非常友好。
其次也得益于 Envoy 的 xDS 能力,xDS 作为一个通用的配置请求协议规范,基于它可以做灵活地扩展,对数据面+控制面的架构天然友好。
反观 Nginx,它更多推崇的是使用本地的指令配置来做配置变更,虽然作为代理程序来说很便捷高效,但用作网关则不尽然。另外,Nginx 原生不支持配置热更新,常见的做法是使用 Lua 脚本来支持,但这会带来非常大的性能衰减,如果配置热更新、可观测性等全部使用 Lua 实现,整体性能损失相比原生 Nginx 最高可能达到 70-80%,社区中针对这一问题还有一个专门的 Issue:Poor performance in benchmark。
当然,下一代云原生网关这个方向目前还没有形成一个事实上的标准,除了 Envoy,业内还有很多企业在探索这个方向,大家其实都想要抢占先机。
国外如traefik、Kong,甚至包括 Nginx 背后的厂商 F5,都在做相关尝试。如葑认为,每种产品可能会有不同的用户群体。
比如traefik,因为它原生是用 Golang 开发的,包括扩展机制也支持用 Golang 编写,所以对于使用 Golang 的群体来说可能相对更友好,同理还有国内百度开源的 BFE。有些客户确实会因为 Golang 的入门门槛比 Nginx 的 C、或 Envoy 的 C++低很多,而选择尝试基于 Golang 的网关方案。如葑认为这类方案可能比较适合的场景是,规模不是特别大,且对性能的要求没有那么高,同时又希望有一个能够快速上手的开源网关产品或者商业化产品。但一些对性能或延时要求比较高的场景,比如电商或游戏场景,可能还是选择基于 C 或者 C++的网关产品更好。因为基于 Golang 的网关方案,包括现在很流行的 Java 体系的 Spring Cloud Gateway,都避免不了 GC 抖动的问题。
国内如 APISIX 也正在云原生网关方向做一些探索。APISIX 基于 OpenResty 开发,主要采用的还是 Nginx+Lua 的方案,但对这套方案做了很多改造,使其能够更好地贴合目前云原生化的需求。如葑认为 APISIX 选择的切入点也很好,并且目前在国内确实算是做得比较成功的一个开源项目。
如葑表示,大家其实选择了不同的路线,现在很难明确地说哪一条路线一定会胜出。当然他自己还是更看好 Envoy,除了前文所述技术选型的考虑,和团队过去几年维护 Tengine 和 Envoy 的经验总结,还有一部分是出于对技术生态和技术影响力的考量。在他看来,目前 Nginx 生态已经成熟到有点固化,不管是社区活跃度还是增长其实都到了一定的瓶颈,这时候投入很多人力优化和扩展现有项目,对团队来说并不是一个特别好的选择,不如选择一个新方向。
另一方面团队更加看重的是 Envoy Gateway 与 Service Mesh 统一技术架构带来的长远价值。原来对中间件团队来说,有一个很大的痛点是,中间件架构演进无法独立于应用演进,而一定要依赖业务帮忙做升级。Service Mesh 架构提供了一个新的可能,可以把中间件所有的通用能力下沉到 Sidecar,更方便地为业务提供增量特性,缩短新业务上线的时间。这对团队来说有更大的意义。
今年 5 月份,新项目Envoy Gateway正式开源,在业内引发了一波讨论。
在如葑看来,Envoy Gateway 的开源,相当于从社区官方角度明确认可了使用 Envoy 作为网关这件事。以前大家可能更熟悉 Envoy 用作 Sidecar 的场景,一提到 Envoy,第一个想到的就是 Service Mesh 里的 Sidecar。Envoy Gateway 这个项目发起之后,大家可能慢慢会改变认知并逐步接受,Envoy 也可以用作网关并且是网关场景一个比较好的选择。
如葑补充道,新开源的 Envoy Gateway 也可能对现有的格局造成一些冲击。他认为,其实在 Istio+Envoy 这个组合里,话语权更大的是 Envoy。现在国内外使用 Envoy 作为网关主要有两个分支,一个是使用 Istio+Envoy 这套基础架构,另一个是使用自建的控制面+Envoy 组成一套架构。刚开源的 Envoy Gateway 背后两家创始企业都选择的是自建控制面+Envoy 这种方式,并没有使用 Istio。目前社区围绕新建一个能够完全贴合网关的控制面这个话题也在做一些讨论。随之而来还有更多问题引发社区讨论,比如:为什么 Envoy Gateway 不首选目前已经成型的 Istio,而是要再新建一个控制面?新的控制面以后跟 Istio 之间的关系会是什么样的?后续是否会支持 Istio 一键迁移?接下来 Envoy Gateway 社区走向值得我们长期关注。
回到 Envoy 本身,也有一些需要改进的地方。众所周知,Envoy 并不是一个容易上手使用的软件,它的复杂性劝退了很多开发者。虽然如葑所在团队因为有了前期的技术沉淀,复杂性并没有给他们造成明显困扰,但他也坦言,对于从未接触过 Envoy 或者对 C/C++不熟悉的开发者来说,Envoy 确实上手门槛比较高。
对于想要尝试 Envoy 的技术团队,团队中最好能有一定的 Envoy 技术储备,如果团队中完全没有熟悉 Envoy 或 C++的人,想要很简单地把 Envoy 用起来,或者平稳地把 Envoy 放到生产环境上使用,会面临比较大的挑战。在易用性和上手门槛方面,Envoy 确实做得没有 Nginx 好。
好的一面是,Envoy 的技术架构,包括多线程模型等,都设计得比较优雅和规范。如葑建议,开发者在上手之前可以先到 Envoy 官方博客上看一看它的技术架构和设计思想,了解完这些之后再去读代码,可能会觉得容易一些。另外,得益于 Envoy 的 Filter 扩展机制,开发者其实不需要对 Envoy 里面所有的细节都了解得非常清楚,如果想快速上手,重点了解一下它的 Filter 扩展机制大概是什么样子,然后参照社区里的 Example,就可以快速写出一个 Demo 的 Filter 并运行起来,这跟基于 Tengine 开发一个 module 的难易度是差不多的。
当然,如葑还是希望 Envoy 社区能够做一些尝试,适当地降低入门门槛,从而更好地把 Envoy 推广出去,让更多人能够把 Envoy 应用到业务中。此外,随着 Envoy 社区活跃度越来越高,参与的人越来越多,如葑觉得 Envoy 整体架构的复杂度其实是在不断膨胀的,后续社区也需要考虑如何在控制架构复杂度和新增功能两个方向上取得一定平衡。
采访嘉宾介绍:
耿蕾蕾(如葑),阿里云研发工程师,从 2020 年 5 月负责 Envoy Gateway 的构建到推出 3.0,作为技术负责人主导了整个演进过程,在云原生网关领域有着丰富的实践。