会员业务出口网关的设计与实现
出口网关(Egress Gateway)是一种部署在云或企业网络中的网络组件,它控制着从内部网络(如企业内网、内部微服务网络)流出到外部网络(如公共互联网或其他外部服务)的流量。一般来说,出口网关是内部服务与外界交互的一个流量出口,实现对外请求的协议转换、流控、监控等通用功能。
相比于传统的入口网关(Ingress Gateway),出口网关侧重于对出站流量进行集中管理与安全控制。例如在爱奇艺对外合作业务中,用户通过入口网关访问爱奇艺内部服务,爱奇艺内部服务再通过出口网关去调用第三方的服务接口,来实现对出站流量的统一管理。
1、在爱奇艺会员对外合作业务中,需要访问合作方的 API 接口,随着安全要求的提升,慢慢的变多的合作方对调用方的IP地址实行白名单策略,并且爱奇艺的服务都是在爱奇艺云服务平台做的部署,业务更新比较频繁,每次更新都会更改IP地址,不可能在每次更新时让第三方进行IP白名单的同步,因此就需要实现调用外部接口的统一出口网关。
2、在传统的网络架构下,需为每台应用服务器实例分别申请外网访问权限。实际运维中,这种方法因涉及到服务扩容或迁移操作时的访问权限更新问题,易造成疏漏,因此导致故障,因此就需要通过给出口网关配置外网访问权限,内部服务统一通过出口网关访问外网,来规避此问题。
最开始设计出口网关的时候是使用的 Nginx 正向代理来实现此功能,这个方案的问题就在于每次新增一个接口都需要调整 Nginx 的路由配置,并且 Nginx 的路由分发只支持静态配置,不能动态增减路由,这就需要在每次配置之后进行 reload,这会增加人工运维的成本,同时 Nginx 正向代理也没办法实现流量隔离。
因此,经过调研我们采用 APISIX 作为网关服务的核心,通过 APISIX 插件实现安全防护、流量管控、协议适配等功能,并接入监控系统,同时通过安全插件接入安全团队提供的安全控制管理系统,并且实现了一个界面化的地址转换服务来实现从 Origin URL 到 APISIX URL 的转换,以便研发人员使用。
1、使用网关的开发人员不要关注出口网关怎么来实现具体的路由规则,也不有必要了解 APISIX 的实现原理,只需要在出口网关管理系统界面中使用地址转换服务,将原本的请求地址转换为网关请求地址,再使用网关请求地址发送请求,就可以完成从原始的直接请求方式到网关代理请求方式的转变,全程自助化。
2、通过现有的 APISIX 插件实现安全防护、流量管控、协议适配等功能,避免重复造轮子。
3、APISIX 支持研发人员通过开发自定义组件的方式扩展API网关能力。
使用出口网关可以为合作方提供固定的公网IP地址,而无需关注内部服务的具体部署方式,避免大量无效沟通。
在出口网关中接入了安全团队提供的安全控制管理系统,可以对访问外部服务的请求进行更细粒度的安全审计和控制,防止敏感数据泄漏。
出口网关的控制面主要由管理界面、管理接口与监控系统组成,管理界面提供极简接入与配置界面功能,并且基于 APISIX 的网关配置服务完成配置分发功能,监控系统完成 API 请求监控数据的收集和业务告警功能。
出口网关的数据面主要是由基于 APISIX 的网关核心构成,基于 APISIX 的插件式结构,可以更方便地进行功能扩展,并且支持无状态部署,可在横向上任意扩展,从而提升系统承载能力。同时,对接安全控制管理系统能有效拦截潜在的不安全请求,提升系统的安全防护能力。
通过管理界面与管理接口,研发人员可以获取访问出口网关的请求地址,并轻松地完成出口网关的配置。APISIX 通过 admin API 或者 dashboard 可以在毫秒级别内通知到所有的数据面节点,它依赖于 etcd 来作为其配置中心,并且依靠 etcd 集群来确保系统的高可用性。管理接口其实就是对 APISIX admin API 的封装,为了进一步提升系统的易用性,我们并没有直接用 dashboard 做可视化界面,而是在管理接口的基础上做了一个可视化界面。
在系统一期中,只提供了通过管理接口进行配置的方法,在二期中为提升易用性,新增了管理界面,管理界面实际是对管理接口的调用与可视化。
数据面功能的实现主要是基于 APISIX 本身的功能。APISIX 以 Nginx 的网络库为基础,(弃用 Nginx 的路由匹配、静态配置和 C 模块),使用 Lua 和 Nginx 动态控制请求流量,通过插件机制来实现各种流量处理和分发的功能:限流限速、日志记录、安全检测、故障注入等,同时支持用户编写自定义插件来对数据面进行扩充。
APISIX 的路由复杂度是 O (k),K 指 URI 长度,和路由数量无关,例如有一百万条路由,APISIX 路由的时间复杂度都是一样的;
出口网关的功能组件是基于 APISIX 插件完成的。主要使用了安全防护、流量管控与协议适配相关功能的插件,并自定义了一个安全插件以接入安全团队提供的安全控制系统。
ip-restriction:IP 限制插件,能够最终靠将 IP 地址列入白名单或黑名单来限制对服务或路由的访问。
ua-restriction:能够最终靠将指定User-Agent列入白名单或黑名单的方式来限制对服务或路由的访问。。
referer-restriction:允许用户将Referer请求头中的域名列入白名单或黑名单来限制该域名对服务或路由的访问。
limit-conn:用于限制客户端对单个服务的并发请求数。当客户端对路由的并发请求数达到限制时,可以返回自定义的状态码和响应信息。
limit-count:使用固定时间窗口算法,大多数都用在限制单个客户端在指定的时间范围内对服务的总请求数,并且会在 HTTP 响应头中返回剩余能请求的个数。
原生的 APISIX admin API 入参很复杂,配置难度比较高,难以快速上手,我们基于 APISIX admin API 实现了一系列管理接口,简化了入参的复杂性,可以自助化配置。通过配置接口配置只需要请求地址及相应的校验参数,所用插件都是默认化配置,接入出口网关的研发人员只要关注于请求地址的转换就可以了。原始 APISIX admin API 配置请求参数如下,可以注意到其配置过程是很复杂的,不了解 APISIX 插件的研发人员难以了解具体插件配置参数的含义是什么。
出口网关采用多实例、多机房、多地域部署的方式,通过故障自动切换机制,保证服务不中断。同时也可通过自动化弹性应对突发流量。
在实际应用中,由于各业务的流量不一致,某些高流量业务可能会抢占大量资源,进而影响其他应用。出口网关通过令牌方式,将不同业务的流量进行区分和隔离,并针对不一样业务设定限流,最大限度保障各业务正常运行。
出口网关提供了一个集中点来监控所有出站流量,可通过出口网关更好地实施监控和记录对外请求日志。这对于跟踪数据流向、检测异常行为等非常有帮助。实际做法中,我们将请求日志通过安全团队的安全控制管理系统进行分析判断请求是否存在异常,以及触发后续流程。
出口网关将运行数据实时上报到监控系统,可以从请求成功率、平均响应时间、最大响应时间等多重维度去监控对外的请求情况,发现请求异常,第一时间进行告警。
一个设计良好的基础组件,除了能提供强大的基础能力,还需要有良好的扩展能力。出口网关系统的可扩展性大多数表现在 APISIX 本身的可扩展性上,也就是服务节点的无状态部署与 APISIX 插件的可扩展性。
由于服务节点无状态,可以在内部服务对外请求激增时,简单地通过增加节点数量来扩展系统整体的吞吐量,而不用担心状态同步的问题,这使得出口网关很容易适应流量的变化,保持高适应性,简化运维管理。
由于不依赖本地状态,当节点出现故障时,能够迅速替换受影响的节点,无需繁琐的状态迁移,保证了服务的迅速恢复和高可用性。此外,无状态节点更容易实现跨云、多区域部署,增强了服务的灾备能力,并且结合K8s能轻松实现横向弹性自动扩缩容。
APISIX 目前已发布了大量插件,并且支持自定义插件,同时支持插件的热加载。
APISIX 插件的实现主要依赖于 OpenResty 对 Nginx 的各个生命周期的钩子函数,允许其在请求生命周期的不同点进行干预或增加额外的功能。并能通过自定义插件的方式接入现有的系统,避免二次开发,极大地提升了系统的可扩展性。自定义插件方式:
此外,相比于 Nginx 在修改配置后,只有reload之后才会生效的做法,APISIX提供了热加载方式。APISIX 热加载主要依赖于 APISIX 的机制和 OpenResty 的特性:由于 APISIX 服务节点是无状态的,这在某种程度上预示着业务处理不依赖于具体的工作进程(worker process),插件的配置都存储在共享内存与外部数据存储中(如 etcd),因此新请求会根据最新的配置来运行插件逻辑,而不依赖于特定的worker进程状态(正在运行的请求还是老配置)。此外,APISIX 的插件系统是模块化的,允许单独加载和卸载 Lua 模块(即插件),当插件本身发生明显的变化,APISIX 可以仅重新加载有变化的插件模块,而无需重载总系统。