4

作者:刘俊海

  • Service Mesh技术作为新一代微服务架构,有效的解决了当前微服务架构和治理过程中的痛点问题,一经推出便引起很大的反响,近两年持续成为架构领域的热点。特别是Google联合Lyft等公司推出的Istio,架构优雅,功能强大,迅速成为Service Mesh领域的明星项目。为了避免陷入技术细节中,本文不会对Service Mesh的具体技术细节进行详细分析,会从Service Mesh的缘起、现状、当前问题和后续展望这几个维度进行展开,尽量让大家对ServiceMesh有一个整体的认识。

为什么需要Service Mesh

微服务架构解决了业务的诸多问题的同时也带来了很多挑战,需要通过完善的微服务治理体系逐一进行解决。微服务治理主要有远程Proxy方式、智能客户端方式以及本地Proxy 3种主要承载方式,下面分别讨论这几种方式的优缺点。

  • 1)远程Proxy方式

微服务下的服务框架基本解决了微服务开发和测试的效率问题,业务同学可以把精力聚焦投入到业务需求上面。多语言服务化背景下,服务治理的基础设施的每一次改动和升级,需要多语言框架的同时升级,这里多语言服务框架的开发、测试和维护的开销有很大的工作量。
由于服务框架以lib的形式存在,和业务代码存在于一个服务里面,会导致做业务需求的业务同学和负责服务治理的基础同学之间仍然会有很多沟通和交互,随着组织和团队的扩大,受康威定律的影响,这个沟通成本会变得不可控。
如何减少多语言接入场景下服务治理基础设施的维护开销,同时减少服务治理基础设施升级对业务的影响,尽量将服务治理和业务解耦,是微服务架构面前的一道课题。
客户端和服务端通信,客户端和服务端都需要有不少服务治理相关的考虑,比如客户端访问服务端时需要考虑服务发现、流量路由、负载均衡、调用熔断、请求降级、mock支持、请求跟踪等诸多特性,服务端也需要考虑限流、降级、安全、统计等;随着业务迭代发展,客户端和服务端需要支持的服务治理特性越来越多,影响业务迭代效率。架构设计上有个不成文的说法,任何软件工程遇到的问题都可以通过增加一个中间层来解决。按照这个说法,可以很自然的想到,微服务架构下,是否可以在客户端和服务端中间增加一个中间层,避免两者直接通信,同时把服务治理相关功能从客户端和服务端代码解耦,移到中间层来,这样服务治理特性的变化收敛在中间代理层,对客户端和服务端透明。
API网关就是用来解决上述微服务治理的效率问题,API网关封装了服务访问和服务治理相关的具体逻辑,客户端只需要使用简单的访问方式,统一访问API网关,由API网关来代理对后端服务的访问,同时由于服务治理特性统一放到API网关上面,服务治理特性的变更可以做到对客户端透明,一定程度上实现了服务治理等基础特性和业务服务的解耦,服务治理特性的升级也比较容易实现。
为了简化客户端的访问方式,对调用方屏蔽集群访问的复杂度,API网关一般会提供一个VIP,调用方直接使用VIP进行访问,由负载均衡设备负责VIP到API网关地址的映射。
API网关和直接使用服务框架相比,优点是业务使用起来很简单,没有什么入门成本,非常容易上手,对业务来说,简单和效率往往是第一位的;同时API网关也可以屏蔽多语言调用方使用方式的差异,避免了微服务框架语言级别的限制,多语言调用方均可以使用简单一致的调用方式访问后端服务,基本解决了多语言的服务治理问题。
当然API网关在提供便捷的服务访问和服务治理能力的同时,相应的也会有一些问题。
首先,引入API网关,通信层面会增加一跳;如果是采用简单易用的VIP访问方式,还需要加上用于VIP解析的负载均衡服务这一跳,通信层面会比直接访问后端服务增加二跳,性能上肯定会有一定的损耗。
其次,通信链路上多一跳就会多一个故障点,会对系统的整体稳定性和可用性有一定的影响。
最后,API网关简单易用的同时,灵活性和定制化支持不太好,很难支持复杂的服务治理定制化需求,比如服务如果想支持动态路由切换,API网关支持起来就有点力不从心。
因此,在业务相对简单,或业务线上部署结构不太复杂时,使用API网关是一个很好的选择,可以简化微服务的开发和运维,提高业务迭代的效率。但业务如果发展到比较复杂时,比如生产环境有多个机房,或者同一个机房内部有全流量环境、小流量环境等多套环境,就会有比较多的路由策略需求和动态路由切换需求,这种情况下就需要探索服务层面是否可以有一种对效率和扩展性更好的平衡方式。

  • 2)基于智能客户端的方式

和远程Proxy不同,基于智能客户端的服务框架采用和服务端直连的方式,客户端和服务端直接通信,中间不经过任何节点,不仅性能提升,同时增强了稳定性。
服务框架需要支持完善的流量调度和容错设计,同时需要支持常见的服务治理策略,对技术的要求相对较高,对于中小公司来说,开发或维护一款完善的服务框架的开销都是不小的。
除了开发维护成本高之外,服务框架作为Lib和客户端服务绑定在一起,因此是语言相关的,每个语言均需要相应的服务框架,这会带来很大的多语言服务治理成本。
另外,由于和客户端服务绑定在一起部署,服务框架的迭代升级相对麻烦,当服务框架进行升级时,需要使用框架的服务均进行升级,对于广泛使用的服务框架来说,这是笔不小的开销,框架和微服务的绑定和耦合,会影响框架自身的迭代和创新。

  • 3)本地Proxy

API网关把服务治理相关特性从服务框架中解耦出来,可以提高效率,但灵活性和扩展性稍差;服务框架可以支持自如的支持各种服务治理需求,但多语言服务治理支持方面会有很大的开销,同时服务治理特性的升级和维护比较困难,因此,能否有一种机制或方式,兼顾API网关和服务框架各自的优点,在提高业务开发效率的同时,也能很好的支持微服务治理的扩展性和定制化需求,本地网关应运而生。
本地网关,又称为Sidecar, 通过在每个服务实例对应的本地机器上部署实现服务治理功能的代理,来实现服务治理能力的快速落地。最有代表性的是Netfilx的微服务中间件Prana, 初衷是将Netfilx OSS微服务治理套件的能力,通过HTTP API接口的方式,赋能给非Java语言使用,以很小的开销获得Netfilx OSS体系强大的服务治理能力。受到Netflix Prana的启发,Spring Cloud也推出了Spring Cloud Netflix Sidecar。
和API网关相比,本地网关的访问方式更为简单,事先给本地网关绑定固定的端口号,业务服务通过localhost:本地端口号的方式即可访问,和直接访问服务端相比,虽然也多了一跳,由于是本地访问,比API网关的性能损耗要小;同时由于本地网关每个机器上都会有部署,因此API网关单个节点故障对系统稳定性的影响相对较小;最后本地网关和服务部署在一起,具有感知本地部署环境的能力,方便一些业务或者环境相关的服务治理特性的落地,比如机房级别的动态路由调整等。
从效率和扩展性上看,本地网关和API网关相比,都有着不少优势。那么是否意味着本地网关就是一个没有问题的完美方案呢,其实本地网关最大的问题是运维上的复杂度比较高,本地网关节点很多,并且业务服务对本地网关也是强依赖,因此需要对本地网关的部署、监控、升级、高可用保障等,都需要有一套完善的机制来保障。由于本地网关对运维的要求比较高,需要有一套完善的运维工具体系支撑。
这个时期的本地网关一般是为了解决业务当前面临的特定问题,比如业务多语言接入,业务基础库升级困难等,一般会和公司特定基础设施进行绑定,不太通用,这些公司一般也没有太多的动力对它进行扩展性和通用性改造和升级,同时本地网关模式运维上的复杂度比较高,本地网关节点很多,并且业务服务对本地网关也是强依赖,因此需要对本地网关的部署、监控、升级、高可用保障等,都需要有一套完善的机制来保障。需要有一套完善的运维工具体系支撑,很少有公司具备这样的技术实力,因此这种模式在一些中大型互联网公司中得到采用,如Netfilx、Airbnb等,很难赋能给更多的企业和业务使用,并没有大规模应用起来。
当前微服务容器化、云化的趋势越来越明显,为了最大程度的利用云技术基础设施,应用自身的架构也需要升级,持续轻量化,将业务需求和非业务需求解耦,业务只需要关注业务相关的功能,这样业务迭代效率可以大大提高。为了支撑云原生时代下的微服务架构,提高微服务迭代效率,对微服务治理提出了如下要求:
(1)标准化
标准化的微服务基础设施,保证了微服务架构的通用性、可维护性和可移植性,同时基于标准化的微服务基础设施,可以更方便的实现微服务自身的标准化。
(2)配置化
配置化是保障微服务治理和微服务稳定性敏捷性的关键,理想的微服务基础设施,需要可以通过统一的治理平台,对服务治理的效果进行可视化度量,同时可以通过可视化界面方便的调整服务治理的策略,即时生效。通过配置化,可以建立服务治理策略调整和反馈的闭环机制,支撑服务治理特性的快速迭代。
(3)服务化
如果可以将微服务基础设施服务化,微服务像访问其他微服务一样,通过标准化接口获取服务访问和服务治理能力,可以真正做到服务治理对业务的解耦和透明,实现服务治理和微服务的并行开发和升级。
(4)平台化、产品化
平台化、产品化的微服务基础设施,可以将服务治理能力通过开放平台,赋能给更多的微服务用户,通过微服务基础设施的产品化,可以加快微服务基础设施的创新。
Service Mesh解决了哪些问题
Service Mesh就是为了解决上述微服务治理当前问题而生,作为Service Mesh技术探索和实践的先行者,全球第一个真正的Service Mesh项目Linkerd负责人、Buoyant公司创始人兼CEO William Morgan第一次完整的阐述了Service Mesh,按照William Morgan的定义,Service Mesh 是一个致力于解决服务间通信的基础设施层,他负责在现代云原生应用的复杂服务拓扑下实现请求的可靠传递,在实践中,服务网格通常被实现为一组轻量级网络代理,这些代理与应用程序部署在一起,并且对应用程序透明。
从上述Service Mesh的定义看,基础设施层是Service Mesh的定位,致力于解决本书第1章提出的微服务基础设施标准化、配置化、服务化和产品化问题;服务间通信,这个是Service Mesh技术面对的问题域,对微服务屏蔽通信的复杂度,解决微服务的通信治理问题;请求的可靠传递是Service Mesh的目标;轻量级网络代理是Service Mesh的部署方式;对应用程序透明是Service Mesh的亮点和特色,Service Mesh接入对业务无侵入,可以非常方便的获取Service Mesh带来的便捷性,算是Service Mesh的一大优势。
综合来看,Service Mesh主要解决用户如下3个维度的痛点需求。

  • (1)完善的微服务基础设施

Service Mesh通过将微服务通信下沉到基础设施层,屏蔽了微服务处理各种通信问题的复杂度,可以看成是微服务之间的抽象协议层,抽象层面可以看成是TCP/IP协议栈的一部分。对于微服务的开发者来说,比如当前使用HTTP或者Thrift进行RPC通信时,你不需要关注TCP/IP这一层的具体实现;有了Service Mesh之后,微服务也不再需要关注RPC通信(包含服务发现、负载均衡、流量调度、限流降级、监控统计等)的一切细节,真正像本地调用一样使用微服务,通信相关的一切工作直接交给Service Mesh。
因此,对于一些需要通过微服务改造提升业务敏捷性,但没有相应技术能力的中小团队来说,可以借助Service Mesh提供的完善的微服务基础设施,加速微服务的落地。

  • (2)语言无关的通信和链路治理

功能上,Service Mesh并没有提供任何新的特性和能力,Service Mesh提供的所有通信和服务治理能力在Service Mesh之前的技术中均能找到,比如Spring Cloud就实现完善了微服务RPC通信和服务治理支持,Service Mesh改变的是通信和服务治理能力提供的方式,通过将这些能力实现从各语言业务实现中解耦,下沉到基础设施层面,以一种更加通用和标准化的方式提供,屏蔽不同语言、不同平台的差异性,这样不仅有利于通信和服务治理能力的迭代和创新,业务使用的时候也会更加方便。
Service Mesh避免了多语言服务治理上的重复建设,通过Service Mesh语言无关的通信和服务治理能力,助力多语言技术栈的效率提升。

  • (3)通信和服务治理的标准化

微服务治理层面,Service Mesh是标准化、体系化、无侵入的分布式服务治理平台,标准化方面,Sidecar成为所有微服务流量通信的约束标准,同时Service Mesh的数据平面和控制平面也通过标准协议进行交互;体系化方面,从全局考虑,提供多维度立体的微服务Observability能力(metric、trace、logging),并且提供体系化的服务治理能力,比如限流、熔断、安全、灰度等;最为重要的是,Service Mesh通过透明无侵入的方式提供全面的服务治理能力,对微服务本身不会带来直接影响。
通过标准化,带来一致的服务治理体验,减少多业务之间由于服务治理标准不一带来的沟通和转换成本,提升全局服务治理的效率。
根据Service Mesh的发展历程和使用方式,我们可以把Service Mesh划分为两个模式。

  • (1)Sidecar模式

在Service Mesh的发展早期,Service Mesh以Sidecar的形态存在。Sidecar,中文上一般被译为“挎斗”或“边车”,类似于三轮摩托车上的挎斗,Sidecar模式下,网络代理服务附近在微服务旁边,为微服务提供通信和链路治理功能。因此,数据平面代理服务也经常被简称为Sidecar。
此时,只有数据平面的网络代理服务,没有控制平面,和外部基础设施服务的交互直接在网络代理服务中进行。
Sidecar模式可以看作是第一代ServiceMesh,代表有早期的Linkerd和Envoy。
第一代Service Mesh采用Sidecar模式,只有数据平面代理,没有控制平面,数据平面代理直接负责和其他外部系统进行交互,通过Sidecar模式,通过将通信和通信链路治理功能从微服务中剥离出来,实现了通信基础设施的下沉和服务化,这里也体现了架构解耦的思想,通过解耦减少了微服务的负担。

  • (2)第二代Service Mesh模式

Sidecar模式的ServiceMesh有一个突出的问题,将通信和通信链路治理的所有功能都放到这个代理服务中,导致数据平面代理很重,并且由于承载了太多的特性和功能,会使得数据平面代理的更新和修改会特别频繁,频繁的更新和升级会导致代理服务出问题的概率增大,影响代理服务的稳定性。同时,Service Mesh模式下,数据平面代理承载了微服务通信的全部流量,对稳定性要求极高,这个服务的任何故障都会对整个系统的稳定性产生很大的影响。为了解决上述频繁升级和稳定性之间的矛盾,将策略和配置决策逻辑从代理服务中脱离出来,形成了独立的控制平面,这就是第二代Service Mesh。
第二代Service Mesh最重要的标志就是控制平面和数据平面分离,数据平面和控制平面并不是一个新的概念,路由器/交换机等数据通信产品架构上,就有运行于专门处理器上的控制平面和多个独立运行、用于路由或交换功能的数据平面。SDN(Software Defined Network,软件定义网络)正是通过数据平面和控制平面分离,控制平面的可编程性,使得网络更加智能、灵活和易扩展,激发了网络技术的又一次革命。
第二代Service Mesh借鉴了SDN的思路,基于控制平面和数据平面分离,有了完善的控制平面,所有的代理服务都由控制平面掌控,通过控制平面可以控制整个系统,提供了强大的控制能力和策略能力;同时将具体的控制逻辑从数据平面移除,简化了数据平面的设计,同时数据平面不需要和外部系统进行交互,数据平面完全聚焦在变更频率很低的流量路由和转发逻辑上,提升了数据平面的稳定性。第二代Service Mesh架构上分为数据平面和控制平面两个部分。

  经典Service Mesh的基本架构
  • (1)数据平面

数据平面负责代理微服务之间的通信,具体包含RPC通信、服务发现、负载均衡、降级熔断、限流容错等,数据平面可以认为是将SpringCloud、Dubbo等语言相关的微服务框架的通信和服务治理能力独立而成的一个单独的语言无关的进程,并且更注重通用性和扩展性,在ServiceMesh中,不再将数据平面代理视为一个个孤立的组件,而是将这些代理连接在一起形成一个全局的分布式网络。

  • (2)控制平面

控制平面负责对数据平面进行管理,定义服务发现、路由、流量控制、遥测统计等策略,这些策略可以是全局的,也可以通过配置某个数据平面节点单独指定,控制平面通过一定的机制将策略下发到各个数据平面节点,数据平面节点在通信时会使用这些策略。
Service Mesh发展和现状
2016年1月,Twitter前基础设施工程师William Morgan和Oliver Gould组建了一个名为Buoyant的公司,同时在GitHub上提交了第一个Linkerd版本Linkerd 0.0.7。这是业界第一个Service Mesh项目,标志着Service Mesh的诞生;2016年9月,开发Linkerd的Buoyant公司第一次提出了Service Mesh的概念;2017年5月,Istio0.1版本发布,Istio一发布,就对Service Mesh届产生巨大影响,直接导致Service Mesh从此之后的发展路径发生一系列的变化。
下面就以ServiceMesh领域当前最有代表性的产品Istio为例,简要介绍Service Mesh的架构和现状。
Envoy是一个用 C++ 编写的云原生高性能边缘代理、中间代理和服务代理,作为专门为微服务架构设计的通信总线,定位是作为Service Mesh的数据平面,接管微服务通信的全部流量,对应用程序屏蔽网络和通信的复杂性。
Envoy作为一个独立进程,设计为和每个应用程序一块运行,所有的 Envoy 形成一个透明的通信网格,每个应用程序发送消息到本地Envoy代理或从本地Envoy代理接收消息,但不需要知道具体的网络拓扑。
Envoy的核心设计理念是网络应该对应用服务透明,职责划分上比较明确,当网络和应用程序出现故障时,可以很容易定位出问题的具体根源。
架构上Envoy内部可以分为数据平面、控制平面和管理平面3个部分,其中控制平面用于对流量路由和转发相关的策略和配置进行管理,Envoy和控制平面通过标准API获取最新的流量配置信息,数据平面的流量转发就是基于控制平面下发的配置规则进行。
为了方便对Envoy运行状态进行监控和管理,Envoy内置一个HTTP Server,作为Envoy的管理平面,HTTP Server会注册一系列的Handler,对外暴露管理平面的API,用于外界查询当前Envoy各个维度的状态,比如外界可以通过管理平面API查询Envoy当前的集群和路由配置、当前的统计信息等。

       Envoy的数据流和控制流
       

Envoy接收到Downstream客户端发过来的请求时,一般先经过类似Iptables的透明拦截机制,然后将流量交给Envoy,Envoy获取请求对应的原目的地址,根据目的地址信息获取对应的网络过滤链信息,根据网络过滤链配置建立新的连接,并通过网络过滤链对应的协议对请求进行解码和路由,选择合适的Upstream节点,将请求发送出去,同时建立Downstream连接和Upstream连接的对应关系,将Upstream返回的响应消息发送给Downstream客户端。
Envoy之所以在如此短的时间内,在Service Mesh数据平面中脱颖而出,是和它优雅的架构设计密切相关,主要体现在如下方面。

  • (1)扩展性

Envoy扩展性通过插件机制实现,Envoy内部当前已经支持众多扩展点,通过网络协议插件和HTTP处理扩展插件,分别从通信协议和链路治理两个层面进行扩展,Envoy插件机制是Service Mesh数据转发和数据处理的基石,基于插件扩展性机制进行扩展和定制开发非常方便,可以建立起强大的Service Mesh生态。

  • (2)配置动态化

配置动态化是Envoy架构层面最优雅的设计,基于配置动态化设计,Envoy集群管理和流量转发相关的所有配置均可以通过xDS协议动态下发和生效,不仅减少了运维复杂度,同时借助动态配置化能力,方便通过一定机制发现Envoy运行时的风险并快速调整,提高了Envoy的整体稳定性。

  • (3)性能

Envoy支持如此众多特性的同时,仍然可以提供优秀的性能指标,得益于良好的架构设计,Envoy架构设计方面对性能的考虑随处可见,比如数据转发层面,Envoy采用异步事件驱动的方式,并且保证一个请求只会在一个线程内处理,减少了请求在线程间切换的开销;此外通过数据平面和控制平面分离,配置变更时,通过无锁机制,保证数据转发的性能不受任何影响。
此外Envoy对Service Mesh的一大贡献是第一个提出了通用数据平面API的概念,通过通用数据平面API,建立了数据平面和控制平面之间交互的标准,实现了数据平面和控制平面通信的标准化。只要基于数据平面API实现,可以根据需要方便的对数据平面或控制平面进行替换,有利于Service Mesh生态体系的建设。
Nginx是Envoy出现之前网络通信中间件领域非常有代表性的开源系统,功能强大,同时性能表现也非常出色,同时扩展性很强,已经形成了强大的生态,已经成为HTTP流量管理领域事实上的标杆。Envoy作为后起之秀,虽然定位和目标上和Nginx有不少差异,但架构设计层面,Envoy和Nginx都有很多的可取之处,下面会从功能定位、整体网络模型、连接处理、请求解析、插件机制、配置管理、部署和运维、管理方式等诸多维度,对Envoy和Nginx进行详细剖析和比较,通过和Nginx功能和架构层面的全方位对比,大家也可以对Envoy的架构设计有着更立体的认识。

  • 1)功能和定位

Nginx最核心的功能是web服务器和反向代理服务器,web服务器完成对 http请求协议的解析和以http协议格式响应请求、缓存、日志处理这些基本web服务器功能;反向代理服务器完成对请求的转发、负载均衡、鉴权、限流、缓存、日志处理等代理常用功能。
除了对Nginx协议的支持外,Nginx还支持普通的tcp、udp反向代理功能,同时以stream方式支持通用的基于4层协议的反向代理,比如mysql代理、memcached代理等。
Envoy的目标比较远大,定位是透明接管微服务之间的通信流量,将通信和服务治理功能从微服务中解耦,通过Envoy,可以方便的增加对自定义协议的支持。
概括起来,Nginx的关键词是web服务器和反向代理,Envoy是透明接管流量,更加体现对流量的控制和掌控力。
另外,从使用方式上看,微服务对于Nginx是显式调用,通过Nginx完成负载均衡等相关功能,Envoy是隐式调用,业务微服务不需要感知到Envoy的存在,和使用Envoy使用相同的方式进行通信,只不过不再需要关注通信和链路治理的细节。

  • 2)网络模型

网络模型上,Nginx采用的是经典的多进程架构,由master进程和worker进程组成,其中,master进程负责对worker进程进行管理,具体包含监控worker进程的运行状态、根据外部输入的一些管理命令向worker进程发送处理信号以及worker进程退出时启动新的worker进程。worker进程负责处理各种网络事件,各个worker进程之间相互独立,一块竞争来自客户端的新的连接和请求,为了保证请求处理的高效,一个请求处理的全部过程在同一个worker进程中。
网络模型上,Nginx采用的是多进程架构,由master进程和worker进程组成,其中,master进程负责对worker进程进行管理,具体包含监控worker进程的运行状态、根据外部输入的一些管理命令向worker进程发送处理信号以及worker进程退出时启动新的worker进程。worker进程负责处理各种网络事件,各个worker进程之间相互独立,一块竞争来自客户端的新的连接和请求,为了保证请求处理的高效,一个请求处理的全部过程在同一个worker进程中。worker进程的个数推荐配置为和当前环境的CPU核数相同。
自从Nginx诞生以来,一直使用上述经典的多进程架构,这种架构下,请求处理过程中如果遇到特别耗时的操作,比如磁盘访问,第三方服务同步访问等,会导致处理该请求的进程被夯住,不仅CPU资源没有得到充分利用,夯住时间比较长时不仅会影响当前请求,严重时会导致本进程的待处理请求大量超时。为了解决这种问题,Nginx从1.7.11版本开始引入了线程池的概念,如果遇到耗时特别长的逻辑,可以增加线程池配置,放到线程池中进行处理。线程池机制的引入对Nginx架构上是个很好的补充,通过针对性的解决耗时特别长的一些阻塞场景,使得Nginx的性能达到一个新的高度。
和Nginx不同,Envoy采用了多线程的网络架构,Envoy一般会根据当前CPU核数创建相同个数的worker线程,所有worker线程同时对Envoy配置的监听器进行监听,接受新的连接,为每个新连接实例化相应的过滤器处理链,处理该连接上的所有请求。和Nginx类似,Envoy的每个请求的处理全流程都在同一个线程下进行。
从上面的分析看,Envoy和Nginx的网络处理方式大体类似,这两种方式都是全异步的编程模式,所有的操作都是异步进行,每个执行上下文使用一个单独的事件调度器,对该执行上下文的异步事件进行调度和触发,只是承载网络的执行上下文有差异,Nginx通过多进程的方式进行承载,Envoy使用的是多线程方式。
Nginx通过线程池的方式,从设计上解决异步编程中的阻塞问题,但仍然没有从根本上解决这个问题,如果遇到设计或者代码层面没有注意到这个问题的场景,仍然会出现因为当前请求阻塞导致后续等待的请求因为得不到处理而超时的现象。由于都是全异步的编程模式,Envoy也会遇到同样的问题,同时Envoy开始尝试着对这种现象进行解决,具体的解决方式是,为每个worker线程分别设置一个看门狗,并通过定时器定期更新本线程看门狗的最新更新时间,主线程会监控各个worker线程看门狗一段时间内是否有更新,如果超过一段时间没有更新,可以认为该线程的看门狗定时更新操作得不到执行的机会,可以推断出这个线程当前已经夯住,无法处理请求消息。Envoy通过这种机制可以检测出worker线程是否被长时间阻塞住,在此机制的基础上,后续可以增加相应的处理(比如将待处理请求移到其他线程,然后把该线程杀掉),可以从机制上解决工作线程被阻塞的问题。

  • 3)连接管理

Nginx通过worker_connections参数来控制每个worker能够建立的最大连接数,从Nginx网络模型可以看出,客户端连接到来时,所有空闲的进程都会去竞争这个新连接,这种竞争如果导致某个进程得到的新连接比较多,同时该进程的空闲连接也会很快用完,如果不进行控制,后续该进程获取新连接时会遇到没有空闲连接而丢弃,同时有的进程有空闲连接而获取不到新连接的不公平现象。那么直接按照均等的方式将连接分配给各个进程是否可行呢,这种方式其实也是有问题的,不同连接上可能承载的请求QPS差异很大,可能会出现两个进程处理相同连接数,但一个特别忙另外一个特别闲的现象,因此为了保证各个工作进程都能够最大限度的提供自己的计算能力,需要对对连接进行精细化管理,Nginx采取的方式是各工作进程根据自身的忙闲程度,动态调整获取新连接的时机,具体实现是,当本进程当前连接数达到最大worker_connections的7/8时,本worker进程不会去试图拿accept锁,也不会去处理新连接,这样其他worker进程就更有机会去处理监听句柄,建立新连接。而且,由于超时时间的设定,使得没有拿到锁的worker进程,去拿锁的频繁更高,通过这种方式,Nginx解决了worker进程之间的负载均衡问题。
Envoy也会遇到和Nginx类似的负载不均问题,Envoy当前发展很快,同时需要解决的问题很多,Envoy社区的同学觉得这个问题当前的优先级还不够高,后续会根据具体情况对这个问题进行讨论和解决。

  • 4)插件机制

Nginx拥有强大的插件扩展能力,基于Nginx的插件扩展机制,业务可以非常方便的完成差异化和个性化定制,Nginx 插件通过模块的方式提供,具体来说,Nginx主要提供如下几种形式的插件扩展:

  • 1) 通过stream机制进行协议扩展,比如增加memcached协议代理和负载均衡等;
  • 2) Handler方式处理HTTP请求;
  • 3) 对HTTP请求和响应消息进行过滤,比如可以修改和定制消息内容等;
  • 4) 访问Upstream时的负载均衡,可以提供自定义的负载均衡机制。

对于最成熟的HTTP协议来说,Nginx把整个请求处理过程划分为多个阶段,当前一共有包含读取请求内容、请求地址改写等一共11个处理阶段,业务需要在某个阶段进行扩展和定制处理时,只需要挂载该阶段对应的回调函数,Nginx核心处理HTTP请求到这个阶段时,会回调之前注册的回调函数进行处理。
Nginx对模块的支持总体来说不算灵活,Nginx模块必须和Nginx自身源码一块编译,并且只能在编译期间选择当前支持的模块,不支持运行时进行模块动态选取和加载,大家一直以来吐槽比较多,为了解决这个问题,Nginx在1.9.11版本引入了模块动态加载支持,从此不再需要替换Nginx文件即可增加第三方模块扩展。
Nginx也支持Lua扩展,利用Lua语言的简单易用和强大的协程机制,可以非常方便地实现很多扩展机制,并且性能也能够基本满足需求。
Envoy也提供了强大的插件扩展机制,当前使用最多的地方是监听过滤插件和网络处理过滤插件,和Nginx相比,Envoy网络插件定位在协议层面,以HTTP协议为例,Envoy并没有那么细粒度的插件扩展机制,如果想对Envoy的HTTP协议处理进行扩展,当前并没有提供特别多的扩展点。
Envoy的插件当前采用的是静态注册的方式,插件代码和Envoy代码一块进行编译,和Nginx不同,Envoy从最开始就支持插件的动态加载,Envoy通过独特的xDS API设计,可以随时对Envoy的xDS插件进行定制修改,Istio将修改后的xDS配置通过Grpc的方式推送给Envoy动态加载和生效。
此外,当前Envoy社区和Cilium社区一块探索利用,利用eBPF提供的用户态网络定制能力,对Envoy的流量进行精细化的管理和扩展定制。Cilium从1.3版本开始,引入了Envoy的Go扩展,通过Go扩展实现Filter插件向Envoy注册,主要实现的还是OnData()函数,当Envoy接受到流量时,就会调用插件的OnData函数进行处理。
Envoy在Lua扩展支持方面也做进行一些探索性的工作,当前已经试验性的支持使用Lua脚步对HTTP请求进行过滤和调整,Lua脚步HTTP过滤器当前仍处于实验阶段,不建议直接在生产环境下使用,后续待验证成熟后才能生产就绪。这种机制成熟后可以在更多的场景下通过Lua脚步机制,增强Envoy的扩展性。

  • 5)配置管理

Nginx的配置格式使用自定义的方式,配置结构和配置解析过程都非常复杂。
配置组织上,Nginx采用层层嵌套的方式,最外层是核心模块的配置,主要包括events事件模块、http模块和stream模块,对于最复杂的http模块来说,下面会嵌套着server子模块,负责监听和管理http请求,server子模块下还会嵌套着一到多个location,用于描述具体的路由规则。
Nginx的配置解析代码可以说是Nginx整个源码体系中最晦涩难懂的,配置解析的核心代码在
ngx_conf_file.c中,通过层层嵌套解析,形成了一颗树状的配置信息结构。
和Nginx相比,Envoy的配置管理部分设计的就比较优雅,配置格式直接使用了Protobuf3,复用了Protobuf3的数据描述能力和自动代码生成机制,完全省去了配置解析的过程,并且也非常方便对配置格式的有效性进行验证。
Nginx的配置都是静态配置,不支持任何形式的动态配置能力。
动态配置能力是Envoy相比Nginx最核心的竞争力,通过动态配置,可以在线修改流量路由和链路治理策略,实现策略配置修改的即时生效。

  • 6)内存管理

Nginx内存管理通过Nginx内存池实现,通过内存池的良好设计,使用内存池进行内存管理时,不需要关注内存什么时候释放,连接销毁时,会回收连接对应的内存资源;同时通过内存池可以减少内存碎片,通过内存对齐、内存分页等机制,可以有效减少Cache Miss,提高内存访问的效率。
Envoy在内存管理方面的支持还很粗糙,直接基于原生的内存管理lib,内存释放时机管理上,通过智能指针管理内存的生命周期。
和Nginx相比,Envoy在内存管理方面提供的支持不多,完全依赖智能指针机制,对使用者的要求比较高,同时无法满足对性能的极致要求。

  • 7)部署和运维

运维上,Nginx采用多进程的通信架构,主进程负责维护工作进程的状态,一方面监控工作进程的状态,状态异常时会对工作进程进行重启,同时主进程也可以接收外界的管理信号,通知工作进程完成相应的操作,比如通过kill信号通知Nginx优雅重启,主进程在接收到重启信号后,会先重新加载配置,然后启动新进程开始接收新的请求,并向所有工作线程发送信号,通知它们不再接收新的请求,并在处理完所有pending请求后自动退出。
Envoy是通过控制平面组件PilotAgent和Sidecar-injection进行管理,Pilot Agent负责管理Envoy的运行状态,当Envoy状态有问题时,Pilot Agent会将Envoy重启,如果重启仍然不能解决问题,会尝试将Envoy调度到其他环境下;Sidecar-injection负责Envoy的自动注入。
因此,从架构上看Nginx是自运维的,Envoy是借助控制平面来完成Envoy运行状态的管理, 运维上比Nginx方便。

  • 8)观测和诊断

服务的可观测以及诊断上,Envoy投入了大量的精力,当前已经全面支持Log、Metric、Trace等可观测机制,并且每种观测方式均提供相应的扩展机制,Nginx在这方面相对逊色很多,可观测以及诊断支持上相对弱一些,当前可能是为了和商业版进行区分,Nginx商业版有完善的运维和问题诊断支持。
Istio是Google、IBM和Lyft联合推出的开源微服务ServiceMesh框架,旨在解决大量微服务的发现、连接、管理、监控以及安全等问题,Istio综合了Google、IBM和Lyft在微服务领域的强大积累和经验,以Envoy为基础,将Envoy作为默认的数据平面,同时提供强大的控制平面能力。一经推出在Service Mesh领域就引起强大的反响,当前已成为Service Mesh事实上的平台和标准。
Envoy已经可以很出色的完成流量路由和转发工作,Istio在Envoy的基础上,提供如下几方面的核心能力:

  • (1)动态配置管理和下发

Istio通过提供通用的配置管理能力,保证不同平台、不同环境下的配置均能够通过一致的方式对Envoy进行配置和下方,对Envoy屏蔽了配置管理的复杂性。这个工作具体由Istio的Pilot组件负责完成。

  • (2)Envoy生命周期管理和运行状态监控
    Istio负责Envoy的生命周期管理,启动Envoy,然后监控Envoy的运行状态,如果运行有异常,Istio会尝试对Envoy进行重启,重启仍然不能成功时,Istio会将当前Envoy实例调度到其他节点上运行。这个工作具体由Istio的Pilot组件负责完成。
  • (3)通信安全

通信安全对于微服务来说是一个非常重要的基础能力,Istio通过托管身份验证、授权和服务之间通信的双向TLS加密, 保障通信的安全性,这个工作具体由Istio的security组件负责完成。

  • (4)策略控制

对于一些核心资源,需要通过一定的策略,在不同消费服务以及服务的不同实例中进行分配,保证资源能够按照预期进行管理,这个工作具体由Istio的mixer组件负责完成。

  • (5)遥测统计

Envoy自身也能进行一些遥测统计相关的工作,但如果需要支持不同的遥测统计后端基础设施,可以将这部分工作移到控制平面上,保证Envoy自身架构的简洁性和稳定性,通过收集遥测统计相关的数据和指标,可以对服务进行全方位的监控。

Service Mesh分析和展望

Service Mesh以其优雅的设计理念,良好的架构设计和生态布局,被业界广泛看好,但 ServiceMesh技术毕竟从诞生到现在才不到4年的时间,在稳定性和成熟度上还有很多需要加强和改进的地方,当前主要有如下几个突出问题:

  • 1)性能和架构的博弈

    Service Mesh架构上的最大亮点就是数据平面和控制平面分离,不仅简化了数据平面的设计,提高数据平面代理的稳定性,同时控制平面基于数据平面全局网格强大的可观测能力,提供强大的全局治理视角和能力,架构上几乎完美,但Service Mesh透明拦截带来的通信消耗,控制平面Mixer交互带来的性能损耗,Service Mesh当前过分偏重架构,而导致性能问题一直没有得到很好的解决,这也很大程度上制约了Service Mesh的落地。

  • 2)非Kubernetes平台的支持

    Service Mesh和Kubernetes是一对完美的组合,Service Mesh在Kubernetes平台下充分利用Kubernetes基础设施的优势,可以最大程度上释放Service Mesh的能量。当前不少Service Mesh主要针对Kubernetes进行设计,主要着眼于云原生应用的前景和未来,对非Kubernetes平台的支持不太友好,现实情况下大量业务仍然部署在非Kubernetes平台上,会导致Service Mesh落地起来非常艰难,业界至今未能看到Service Mesh在生产环境下的大规模落地。

  • 3)标准化

当前市场了已经涌现了不少Service Mesh,这些Service Mesh各自为政,相互不兼容,不同Service Mesh之间迁移的成本非常高,严重影响Service Mesh生态的繁荣和发展。

为了实现Service Mesh生态的健康持续发展,需要建立一套标准,大家遵照相同的标准互联互通,扩展实现。

Service Mesh带来的下一代微服务革命浪潮已经到来,虽然当前仍然有不少现实性问题,但只有紧跟技术的方向,才能充分利用技术带来的核心价值,最后一句话展望,Service Mesh前途是光明的,道路是曲折的。
原文:学而思网校技术团队-一文读懂Service Mesh技术


AI及LNMPRG研究
7.2k 声望12.8k 粉丝

一群热爱代码的人 研究Nginx PHP Redis Memcache Beanstalk 等源码 以及一群热爱前端的人