阿里云云原生架构实践
上QQ阅读APP看书,第一时间看更新

3.2.1 Service Mesh之Sidecar模式

Sidecar模式最典型的方案是Istio+Envoy的结构,其中Istio主要负责控制面(Control Plane)的管控,而Envoy则负责数据面(Data Plane)的网络流量转发。两者的结合实现了Istio的4大目标:连接(Connect)、安全(Security)、控制(Control)和观测(Observe),如图3-3所示。

图3-4所示是Istio+Envoy最典型的点架构方案。

下面就来详细阐述Sidecar模式。我们先从服务之间的通信开始。假设Service A要与Service B通信,与传统的Service A和Service B直接通信(如最典型的HTTP REST服务调用)不同的是,Sidecar模式要求通信双方首先与应用侧的Envoy连接,在发起服务间调用时,服务消费者Service A首先将服务调用请求发送给自己的Envoy代理人,然后Service A的Envoy代理人将请求转发给服务提供方Service B的Envoy代理人。接下来,Service B的Envoy代理人再将服务请求转发给正式服务提供者Service B,完成服务的调用。服务调用的响应结果会顺着原路返回,也就是服务提供者Service B将响应结果发给自己的Envoy代理人,然后由Service B的Envoy代理人将响应结果发给服务消费者Service A的Envoy代理人,最后由Service A的Envoy代理人转发给Service A,最终完成整个服务调用流程。

图3-3 Istio的4大目标

图3-4 Istio+Envoy典型的点架构方案

很多开发人员可能会产生疑问,既然服务之间可以相互通信并进行服务调用,为什么还要各自找一个代理人来做这件事情?下面就来解释通过代理人通信的好处。

1.服务路由和可靠性保证

如今,服务之间的调用通常是指网络调用,如果要发起网络调用,那么至少需要知道目标IP地址和端口号;如果是由应用发起连接创建,那么应用就需要了解创建连接的详细信息;如果涉及网络变更和调整、目标服务上/下线、网络抖动和服务短暂不可用等问题,那么应用就需要感知并做出对应的调整。虽然只是一次简单的远程服务调用,但是其中涉及的工作量并不小。如果有了代理人的介入,应用只需要与附近(127.0.0.1)的代理人创建连接,然后代理人与目标服务创建连接和路由等。也就是说,有了代理人,应用就不用关心与网络相关的工作了。

2.隔离性和安全性

当发起网络I/O请求时,如果采用同步阻塞的方式,通常要设置连接池和请求超时,以保证应用的快速响应。代理人可以承担起这部分责任,处理连接池和超时等工作。另外,连接的创建还会涉及安全问题,例如,需要为数据连接提供用户名和密码。如果由应用来保存这些信息,那么当开发包出现安全问题而导致应用被入侵时,有可能使数据泄露。如果调整为由代理人来管理与服务提供者的连接,那么应用就不再需要保存这些用户名、密码和密钥等信息,安全性就会因此而得到提升。

3.为应用减负

前文解释了代理人在处理网络和安全问题时的作用,可以看出代理人已经为应用减负不少。实际上代理人还能做更多事,如协议转换。网络通信除了网络连接的创建和管理之外,还涉及协议解析、数据序列化和反序列化等,这些都需要有对应的SDK支持。代理人的介入在一定程度上可以帮助应用简化这些工作。如果采用代理人模式,我们只需要通过HTTP REST/gRPC这些通用SDK将请求发送给代理人,代理人就可以连接Kafka并完成消息的发送,这种协议转换能够很大程度地为应用减负。如果一些编程语言还没有对应协议的SDK开发包,那么这种代理人协议转换的方式将会提供更多方便。

4.服务调用的可观测性

传统方式下,如果要监测服务调用,我们需要在SDK中做大量工作(如日志记录、链路跟踪、Metrics埋点等),这些工作将导致SDK变得非常庞大和复杂。代理人介入后,服务请求的转发都是通过代理人完成的,相当于有了统一的入口。在这里,我们可以进行可观测性数据埋点,如使用Logging、Tracing和Metrics,使数据采集工作简单很多。数据采集将为后续的服务治理提供分析数据。基于这些数据,代理人可实现诸如熔断保护(Circuit Breaker)、重试(Retry)等工作,不仅实现方便,而且能很好地保证系统的稳定性和可靠性。

当然,Envoy代理还有其他方面的优势,这里就不一一列举了。至此,读者可能会发出新的疑问,那就是谁负责管理这些代理人。这些代理人可做不到完全自我管理。下面将要讲解的Istio控制面可用于解决代理人的管理问题。

Envoy代理主要负责处理网络请求的转发和接收、协议转换、数据采集等工作,这些基本集中在数据面,而如何指挥并协调这些代理人一起工作,就会牵涉控制面的工作。此外,代理人承担的网络连接创建、安全、断路保护等,还涉及相关元信息来自哪里的问题。在Istio+Envoy的架构设计中,存在一个数据面和控制面的通信协议,即xDS协议(xDS Protocol)。该协议可以实现对Envoy代理的管控,涉及的内容非常多,如LDS(Listener Discovery Service,监听器发现服务)、RDS(Route Discovery Service,路由发现服务)、CDS(Cluster Discovery Service,集群发现服务)、EDS(Endpoint Discovery Service,端点发现服务)和SDS(Secret Discovery Service,密钥发现服务)等。限于篇幅,这里就不详细介绍xDS了,协议的具体内容可以参考https://www.envoyproxy.io/docs/envoy/latest/api docs/xds_protocol。我们只需要明白在Istio+Envoy架构体系中,控制面应用istiod通过xDS协议管理着众多Envoy代理。

那么如何部署众多的Envoy代理程序呢?上文提到过,代理人应用部署在真实应用的旁侧,我们可以将真实应用和代理人应用理解为同一个虚拟主机或容器内的两个进程——一个为正式应用的进程,一个为Envoy代理进程。那么,这种方式会不会增加运维的成本?当然会!但是,我们在前面也解释过,Service Mesh属于基础设施层同时也要依赖其他基础设施层,所以部署Service Mesh或多或少会对基础设施做一些改变。好消息是,如果基础设施层已经在使用Kubernetes,那么这里的调整并不会很大,因为Kubernetes已经能够很好地支持Istio,几乎不需要再做太多工作,我们只需要按照Istio官方文档完成Istio在Kubernetes上的安装即可。同时,Istio还提供了功能丰富的Dashboard控制台。可以说,Istio与Kubernetes集成下的用户体验非常好,完全能够满足运维的需求。

那么,Istio+Envoy是不是最完美的Service Mesh架构呢?众所周知,软件架构设计中并不存在完美的架构设计,都是综合各种因素和折中考量后的结果。下面就来列举Istio+Envoy模式中的一些问题,以供我们选择架构时考量。

1)对Kubernetes的依赖。虽然Istio+Envoy这一Sidecar模式可以运行在非Kubernetes系统之上,但是对应的开发和运维的工作量还是不小的。因此如果基础设施层还没有使用Kubernetes,则不建议使用该模式。

2)性能损失和资源浪费。对比传统的直连模式,Envoy代理介入后增加了网络请求的跳数(Network Jump)。Envoy代理同时也是一个独立进程,需要使用到内存和CPU等。另外,转发网络请求涉及协议解析等工作,这些都需要花费额外的计算资源。当然,对于中小规模系统,这种性能损失和资源浪费的影响并不大。但如果系统规模比较大,对资源成本比较敏感,对网络调用的性能损失比较在意,那么Istio+Envoy模式可能就不太合适了。当然,我们可以在Istio+Envoy的基础上对性能进行优化,以达到资源和性能的要求,但显然这又会增加一定的开发成本。

3)开发成本增加。代理的介入使得整个系统变得更为复杂。例如,应用开发时连接数据库,如果是直连的方式,那么设置一下IP、用户名和密码就可以了。而如果是Istio+Envoy模式,就需要通过代理连接数据库。那么,是否需要在计算机上安装Envoy代理进行本机开发呢?如何快速部署到不同的环境进行测试,如本机测试、项目环境测试和日常环境测试等?这些都需要对应的开发工具或管理系统来提供支持。

目前,Service Mesh架构典型的技术方案还是基于Istio+Envoy的Sidecar模式。随着Kubernetes在基础设施层的日益普及,大家已逐渐接受和采纳该模式。目前,各大云厂商(如Google、阿里云等)都提供了基于Kubernetes一键初始化Istio服务的能力,大大降低了使用门槛。