eBay 基于 Istio 的统一流量管理实践

作者 孟凡杰 发布于 2021年2月12日 / 26 分钟阅读

作者:孟凡杰,eBay 资深架构师,负责 Kubernetes 在企业落地过程中的架构和开发工作,专注于网络、多集群、服务治理和服务网格等方向。Kubernetes 社区贡献者,曾参与社区集群联邦的开发和服务控制器重构等工作。

Kubernetes 作为 eBay 的统一云平台,统管了在线业务、大数据、搜索后台等多种异构应用。集群数量高达上百,其中的大型集群中,单个集群运行数千个微服务,数十万 Pod。不同类型的应用,针对流量管控的需求也各有不同,如何用一套统一的模型将各种流量管控需求统一起来是 eBay 多年来一直面临的挑战。

以云应用为例,为实现跨数据中心高可用的需求,生产应用的网络拓扑可以简要描述如下:

  • eBay 采用多活数据中心的网络拓扑,因此任何生产应用都需要完成跨三个数据中心的部署。
  • 为满足单集群的高可用,针对每个数据中心,任何应用都需进行多副本部署,并配置负载均衡。
  • 以实现全站微服务化,但为保证高可用,服务之间的调用仍以南北流量为主。
  • 针对核心应用,除集群本地负载均衡配置以外,还需配置跨数据中心负载均衡,并通过权重控制将 99% 的请求转入本地数据中心,将 1% 的流量转向跨地域的数据中心。该配置的主要目的是当某应用的所有本地服务实例失效时,运维可快速将跨数据中心负载均衡器上指向本地的 99% 流量的成员禁止掉,流量可在秒级转向其他数据中心从而保护业务不受影响。业务版本发布、硬件故障、防火墙、路由器等网络设备变更都有可能导致本地服务实例失效。

部署模式

eBay 有多个数据中心,每个数据中心包含多个有独立供电和制冷的可用区(Availability Zone),每个可用区部署多个 Kubernetes 集群。因每个可用区的网络延迟较小,因此我们当前以可用区为最小管理域搭建 Istio 控制面。在每个可用区内,选择一个 Kubernetes 集群作为网关集群,部署 Istio Primary,在同一可用区的其他集群安装 Istio Remote。在这样的配置下,同一可用区的多个集群内服务和服务之间的通信均转化为东西流量,跨可用区的通信需要经由 Istio 网关。

此种 Istio 部署模式主要依托于 Kubernetes 的运营模式,我们将不同可用区的计算节点搭建了不同的 Kubernetes 集群。这样的配置可实现同一网格内的服务访问低延迟,并且使得服务网格的规模可用,并对故障域做了很好的管控。

接入网关

作为互联网公司,流量管理中最重要的一环就是如何接收来自公网的用户请求。将集群外部客户端发起的请求转入集群内部,是流量管理需要解决的第一个问题。

在纯软件架构下,负载均衡组件被划分为基于四层的负载均衡器和基于七层的 API 网关。四层负载均衡器负责提供服务的虚拟 IP 地址,接收客户请求,并将客户请求转入上游实例。七层 API 网关负责基于应用层协议的高级路由功能,比如 TLS 卸载,基于访问路径的跳转,HTTP 协议包头的修改等等。

四层网关

四层网关的主要技术手段是通过网络地址转换(NAT) 或者隧道技术(Tunnel)等技术,将来自外部客户端发至虚拟 IP 地址的用户请求转发至集群内部。网络地址转换是最常用的方法,其优势是简单易用,排查问题简单。IP Tunnel 相较 NAT 技术配置更复杂,但是基于 IP Tunnel 技术通常能实现 DSR,既保留了原始 IP 地址,又能有比较高的数据转发效率,因此与 NAT 相比是更优的方案。

在 Kubernetes 架构下,这些四层负载均衡器的控制面板可以定义为 Kubernetes Pod 以实现故障转移,扩缩容等高级功能。而基于 Linux 自带组件比如 IPVS,即可实现基于四层的数据包转发。

四层网关的配置依赖于 Kubernetes Service Controller 完成以下配置:

  • 虚拟 IP 地址分配,当用户创建 Service 对象以后,Service Controller 需要从预先配置的公网 IP 中选择一个可用的虚拟 IP 地址分配给该服务。
  • 配置 IPVS 接口,完成负载均衡规则的配置。
  • 路由宣告,虚拟 IP 地址与物理设备的 IP 不一样,它没有绑定在任何物理设备上,但基于 BGP 协议和 ECMP,它能让多个设备配置同一个 IP 地址的路由信息。当 Service Controller 为 Service 分配虚拟 IP 地址并配置好 IPVS 规则以后,Controller 还需要将该虚拟 IP 地址从配置好的节点中宣告出去。基于 BGP 协议,数据中心中的其他路由器即可获知如何将虚拟 IP 地址转发至该网关节点。有了 ECMP 的支持,多个四层负载均衡组件行为一致,也就是他们配置一样的规则,宣告一样的 IP,每个实例都会承载该虚拟 IP 地址的流量。相比主备模式的硬件负载均衡器,此方案的所有负载均衡节点都是 Active 模式,没有 Standby 设备的额外硬件开销。

每个节点的核心功能是负载均衡规则配置,包括以下特性:

N 元组哈希

基于源 IP,源端口,目标 IP,目标端口,以及协议的 N 元组哈希,保证针对同一个连接,总是选择同一个上游实例。路由器的 ECMP 哈希算法与设备相关,同样的 N 元组有可能会被转发至多个目标,在本场景中是四层负载均衡。只要在 IPVS 主机上按照 N 元组重新做哈希,那么无论请求被转发至哪个 IPVS 实例,都会被转发至相同的上游服务器。所有实例计算的的哈希结果都一致,这样多个 IPVS 实例之间不用同步状态。当一个节点出现故障时,其他节点可将请求转发至同一个上游。

一致性哈希

基于 N 元组的哈希算法,会尽量将请求平分到多个上游服务器,在 Kubernetes 世界里,上游服务器以 Pod 的形式存在,扩缩容,Failover 是常见场景。在普通哈希算法中,目标的变动意味着大量的 rehash,采用一致性哈希算法后,只需要将变动的部分重新哈希即可,减少了大量哈希计算的 CPU 开销。

Connection Tracking

Connection Tracking 表用来记录最近连接的后端选择结果,当 IPVS 模块处理数据进行负载均衡操作时,首先查询该连接表,如果发现对应的 N 元组已经有了对应的目标实例且该实例依然健康,那么直接复用此结果。如果不存在或者对应的实例状态不正常则需要基于一致性哈希重新计算,计算结果会被保存在该连接表中供后面的请求数据复用。

数据包封包

选择好对应的上游服务器以后,IPVS 模块开始处理数据包。按照第五章的内容,内核协议栈在处理数据包是,可以基于 NAT 或者 Tunnel 两种模式,NAT 的问题是用户原始 IP 会丢失,这里选取更优的 Tunnel 模式,IPVS 模块会保持原始数据包不变,在原始数据包外面封装一层 IP 包头,数据包的内层包头源是客户端 IP,目标是服务虚拟 IP 地址,外层包头源是 IPVS PodIP,目标是上游服务器 PodIP,然后基于 IP over IP 协议发送数据给上游。

健康检查

健康检查是负载均衡的基本功能,在我们打造的软件负载均衡中也需要。Seasaw 库有 API 支持多种健康检查模式,只需在控制器中调用接口对所有上游目标做健康检查,如果某个上游服务器检查失败,需要将 IPVS 中对应的转发规则删除掉。

基于软件的四层负载均衡有多重实现方式,基于操作系统自带的 IPVS 模块是最直接,成本最低的方案。当然 IPVS 在处理数据的过程中需要依赖操作系统协议栈,转发效率并非最高。如果需要更大的流量处理能力,有很多数据平面加速技术可用,比如 DPDK 和 XDP。

七层应用网关

Istio 提供 Ingress Gateway,配合四层负载均衡,即可实现全站的入站流量高可用接入方案。

作为四层负载均衡的转发目标,七层 API 网关需要配合完成隧道技术的配置。因为四层负载均衡基于 IP Tunnel 配置转发规则,当它转发数据时,是以 IP Over IP 协议发送的数据包,作为目标,Envoy Pod 在接收到请求以后,需要将 IPIP 包拆解。这需要在 Enovy Pod 中创建类型为 IPIP 的设备并绑定虚拟 IP 地址。

微服务架构网站的主站通常是数十到数百上甚至千个微服务的集合,不同微服务以不同访问路径注册在同一主域名下。同时 API 网关会有一些通用的访问控制策略,比如外网 IP 不能访问以 /admin 结尾的路径等,这些访问控制在 Istio 有很好的支持。

Envoy 接收到请求后,会按照既定的七层转发规则将请求转发至对应的目标,对于边缘网关来说,这些目标通常是处于云端的服务虚拟 IP 地址。Envoy 在接受到云端处理结果以后,需要将该请求转发回给客户端,因为该请求抵达 Envoy Pod 时是 IPIP 包,在操作系统卸载了外层包头以后,内层数据包包头是客户端 IP 和服务虚拟 IP 地址,Envoy 在回包时,只需将源目标地址翻转再发送数据,该响应包即可走默认网关绕过 IPVS 而直接发送至客户端,此模式为大家熟知的 DSR 模式。

流量管理

协议升级

针对接入 Istio 的应用默认启用 mTLS,这样如果是东西流量,则服务和服务之间的通信天然加密,站内流量的安全等级得到了提升。

应对规模化挑战

Istio 的强大之处在于,通过一套模型将东西和南北流量统一管控,针对东西流量,无太多需要定制化的功能。我们生产化过程中主要的工作是持续集成和持续发布 Pipeline 的构建,以及大量的性能测试工作,并且基于规模性测试和性能测试结果,定义 Istio 运维模型。其中针对超大集群,Istio 则面对比较多的挑战。

Istiod 默认发现集群中所有的服务,并且每个服务的每个端口构建一个 Envoy Cluster,若模式开启了 sni-dnat 模式,则 Istiod 还构建一份符合域名规范的 Envoy Cluster。针对服务数量较多的超大规模集群,Envoy 配置会变的超大。在早期版本中,我们经历了很多 8000 多个服务导致 Istiod 生成的配置超出 Envoy 能承受的上限而引发的接入网关完全不可用的故障。

Istio 在后续的版本中,为 Istio 对象增加了 ExportTo 属性,以实现可见性控制。通过将接入的服务只 export 给需要的微服务,可控制 Envoy 的配置规模,降低 Envoy 的 footprint,并提升推送效率。

虽然通过 ExportTo 可精简 Envoy 的配置,但是 Istio 控制面板依然会将集群内的所有服务都发现出来。针对超大规模集群,Istiod 依然面临因为需要监控和处理的对象过多而导致的资源占用过大,处理效率过低的问题。社区 1.9 版本在推动 Istiod 基于 Namespace Labels 过滤监控对象的功能,这个功能有利于解决超大集群规模下,Istiod 控制面板本身的规模和性能问题。

接入网关证书自动化

Istio 基于 Envoy 的发现机制 SDS 实现了网站域名的证书管理,但是它要求管理员预先将证书放入 Istio 根 Namespace,并且在创建 Istio Gateway 对象时,通过定义 credentialName 来引用预先定义的证书信息。这适用于同一 Kubernetes 集群只提供一个域名的场景,但针对域名动态创建的场景,这种半自动的运维模式显然是不可能的。需要实现自定义的 SDS 以完成与企业证书签发中心的对接,其方案可简单理解为,通过自定义控制器监控 Istio Gateway 对象中的 hosts 属性完成证书的自动签发,并且通过 SDS 将证书推送给 Envoy。

接入域名自动化

同一应用网关可实现多个拥有不同域名的应用接入,针对不同域名的应用,需要完成域名配置的自动化。为实现该目标,定义了 NameService 对象,允许用户定义 FQDN,TTL,不同 DNS Provider,目标服务等等。在目标服务完成配置以后,域名配置可自动完成。

管理模型抽象和高级流量管控

Istio 的模型抽象非常灵活,通过 Istio 对象可为应用定义不同网络拓扑。但同时面临诸多挑战:

  • 针对数十个可用区,上百个 Kubernetes 集群,让用户面向每个集群做配置不现实。这样做的结果是管理混乱,客户需要关心太多基础架构细节,计算资源调控难度大,配置不统一,变更造成的故障可能性高。
  • Istio 对象无状态属性,很难直观获取配置是否正确、是否已推送完成等信息。
  • 多路径软件接入网关的健康检查机制。

Kubernetes 通过集群联邦实现多集群的管理,我们基于集群联邦实现了一套 Federated AccessPoint,其核心是将 Kubernetes 中描述负载均衡的 Service 对象和 Istio 中描述网络流量的 Gateway、VirtualService、DestinationRule、ServiceEntry、WorkloadEntry 等对象定义为模板,将 AvailabilityZone 或者 Kubernetes Cluster 作为部署目标,并且支持 Override 属性的集群联邦对象。

针对此流量模型,提供丰富的策略控制,包括:

  • PlacementPolicy 控制,用户可以选择目标集群来完成流量配置,甚至可以选择关联的 FederatedDeployment 对象,使得 AccessPoint 自动发现目标集群并完成配置。
  • 完成了状态上报,包括网关虚拟 IP 地址,网关 FQDN,证书安装状态以及版本信息,路由策略是否配置完成等。这补齐了 Istio 自身的短板,使得任何部署在 Istio 的应用的网络配置状态一目了然。
  • 发布策略控制,针对多集群的配置,可实现单集群的灰度发布,并且能够自动暂停发布,管理员验证单个集群的变更正确以后,再继续发布。通过此机制,避免因为全局流量变更产生的故障。
  • 不同域名的 AccessPoint 可拥有不同的四层网关虚拟 IP 地址,以实现基于 IP 地址的四层网络隔离。
  • 基于跨地域的流量管控,Istio 实现了基于 workload locality 的故障转移策略和权重策略管理,基于这些策略可实现跨地域的高可用流量管理。

Istio 面临的机遇和挑战

Istio 优势明显,它尝试将南北流量和东西流量作为一个统一命题管理起来,这使得基于同一套技术栈,将微服务架构从 API 网关演进到服务网格成为可能,其诸多特性使得 Istio 成为社区最活跃的开源服务网格项目。

  • 可移植性,不仅支持 Kubernetes,也支持虚拟平台 OpenStack 以及 Consul。
  • 跨语种的服务网格平台,统一 Java,Scala,Nodejs 等诸多语言。
  • Istio 将南北和东西流量统一管理,统一服务网格和 API 网关用户体验,降低运营成本。
  • 天然安全,自动化证书管理,认证授权的集成。
  • 充分的功能支持,能看到的 API 网关的所有功能都有支持。
  • 背后有强大的社区支持,谷歌将 Istio 作为下一代微服务治理平台,IBM,微软,华为,阿里等云计算巨头都积极参与 Istio 项目的推进和生产化。

同时作为新兴项目,用来管理分布式系统中最复杂的流量管理,Istio 同样面临众多挑战:

  • 规模和效率。Kubernetes 支持的集群规模越来越大,几千个计算节点,数十万 Pod,数千上万 Service 的生产集群越来越常见。Istio 在支持大规模集群场景还有很多挑战,代码需要做诸多优化。Istio 的多集群部署甚至还会让量级翻数倍,如何支持超大规模集群,是 Istio 面临的最大挑战之一。
  • 复杂性,无论从控制平面复杂性还是模型抽象看,Istio 都是一个复杂系统,更多的功能模块意味着运维的复杂度更高。
  • 与企业已存服务的整合,Istio 生产化需要与企业现有服务的整合,比如与企业 CA 的整合,与企业 Tracing 系统的整合,与企业监控平台的整合等等。
  • 存量业务的迁移,很多企业已经有基于 SpringCloud 等开源框架的微服务系统,此系统已经支持了诸多熔断限流,API 网关等功能,与 Istio 提供的功能重复。是否要将这些存量业务迁移到 Istio,如何迁移都是巨大挑战。

尽管如此,Istio 有社区的强大支持,有诸多巨头公司和大项目的背书,它能补充 Kubernetes 在流量管理层面的功能缺失,使其成为一个完整的微服务治理平台。总之,Istio 未来可期。

我们把更多基于 Kubernetes 和 Istio 的生产实践经验,写进了《Kubernetes 生产化实践之路》这本书里,目前京东正在五折热销。

推荐阅读