service mesh技术总结
1、为什么需要Service Mesh
微服务治理主要有远程Proxy方式、智能客户端方式以及本地Proxy 3种主要承载方式
1)远程Proxy方式
客户端和服务端通信,客户端和服务端都需要有不少服务治理相关的考虑,比如客户端访问服务端时需要考虑服务发现、流量路由、负载均衡、调用熔断、请求降级、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
本地网关,又称为Sidecar, 通过在每个服务实例对应的本地机器上部署实现服务治理功能的代理,来实现服务治理能力的快速落地。最有代表性的是Netfilx的微服务中间件Prana, 初衷是将Netfilx OSS微服务治理套件的能力,通过HTTP API接口的方式,赋能给非Java语言使用,以很小的开销获得Netfilx OSS体系强大的服务治理能力。受到Netflix Prana的启发,Spring Cloud也推出了Spring Cloud Netflix Sidecar。
和API网关相比,本地网关的访问方式更为简单,事先给本地网关绑定固定的端口号,业务服务通过localhost:本地端口号的方式即可访问,和直接访问服务端相比,虽然也多了一跳,由于是本地访问,比API网关的性能损耗要小;同时由于本地网关每个机器上都会有部署,因此API网关单个节点故障对系统稳定性的影响相对较小;最后本地网关和服务部署在一起,具有感知本地部署环境的能力,方便一些业务或者环境相关的服务治理特性的落地,比如机房级别的动态路由调整等。
缺点:运维上的复杂度比较高,本地网关节点很多,并且业务服务对本地网关也是强依赖,因此需要对本地网关的部署、监控、升级、高可用保障等,都需要有一套完善的机制来保障。由于本地网关对运维的要求比较高,需要有一套完善的运维工具体系支撑。
2、Service Mesh解决了哪些问题
1)完善的微服务基础设施
Service Mesh通过将微服务通信下沉到基础设施层,屏蔽了微服务处理各种通信问题的复杂度,可以看成是微服务之间的抽象协议层,抽象层面可以看成是TCP/IP协议栈的一部分。对于微服务的开发者来说,比如当前使用HTTP或者Thrift进行RPC通信时,你不需要关注TCP/IP这一层的具体实现;有了Service Mesh之后,微服务也不再需要关注RPC通信(包含服务发现、负载均衡、流量调度、限流降级、监控统计等)的一切细节,真正像本地调用一样使用微服务,通信相关的一切工作直接交给Service Mesh。
2)语言无关的通信和链路治理
3)通信和服务治理的标准化
3、Service Mesh发展和现状
Envoy是一个用 C++ 编写的云原生高性能边缘代理、中间代理和服务代理,作为专门为微服务架构设计的通信总线,定位是作为Service Mesh的数据平面,接管微服务通信的全部流量,对应用程序屏蔽网络和通信的复杂性。
Envoy作为一个独立进程,设计为和每个应用程序一块运行,所有的 Envoy 形成一个透明的通信网格,每个应用程序发送消息到本地Envoy代理或从本地Envoy代理接收消息,但不需要知道具体的网络拓扑。
Envoy接收到Downstream客户端发过来的请求时,一般先经过类似Iptables的透明拦截机制,然后将流量交给Envoy,Envoy获取请求对应的原目的地址,根据目的地址信息获取对应的网络过滤链信息,根据网络过滤链配置建立新的连接,并通过网络过滤链对应的协议对请求进行解码和路由,选择合适的Upstream节点,将请求发送出去,同时建立Downstream连接和Upstream连接的对应关系,将Upstream返回的响应消息发送给Downstream客户端。
4、Nginx与Envoy对比
1)功能和定位
Nginx最核心的功能是web服务器和反向代理服务器,web服务器完成对 http请求协议的解析和以http协议格式响应请求、缓存、日志处理这些基本web服务器功能;反向代理服务器完成对请求的转发、负载均衡、鉴权、限流、缓存、日志处理等代理常用功能。除了对Nginx协议的支持外,Nginx还支持普通的tcp、udp反向代理功能,同时以stream方式支持通用的基于4层协议的反向代理,比如mysql代理、memcached代理等。Envoy的目标比较远大,定位是透明接管微服务之间的通信流量,将通信和服务治理功能从微服务中解耦,通过Envoy,可以方便的增加对自定义协议的支持。
2)网络模型
Nginx采用的是经典的多进程架构,由master进程和worker进程组成,其中,master进程负责对worker进程进行管理,具体包含监控worker进程的运行状态、根据外部输入的一些管理命令向worker进程发送处理信号以及worker进程退出时启动新的worker进程。worker进程负责处理各种网络事件,各个worker进程之间相互独立,一块竞争来自客户端的新的连接和请求,为了保证请求处理的高效,一个请求处理的全部过程在同一个worker进程中。Nginx从1.7.11版本开始引入了线程池的概念,如果遇到耗时特别长的逻辑,可以增加线程池配置,放到线程池中进行处理。
Envoy采用了多线程的网络架构,Envoy一般会根据当前CPU核数创建相同个数的worker线程,所有worker线程同时对Envoy配置的监听器进行监听,接受新的连接,为每个新连接实例化相应的过滤器处理链,处理该连接上的所有请求。和Nginx类似,Envoy的每个请求的处理全流程都在同一个线程下进行。对于阻塞问题,具体的解决方式是,为每个worker线程分别设置一个看门狗,并通过定时器定期更新本线程看门狗的最新更新时间,主线程会监控各个worker线程看门狗一段时间内是否有更新,如果超过一段时间没有更新,可以认为该线程的看门狗定时更新操作得不到执行的机会,可以推断出这个线程当前已经夯住,无法处理请求消息。Envoy通过这种机制可以检测出worker线程是否被长时间阻塞住,在此机制的基础上,后续可以增加相应的处理(比如将待处理请求移到其他线程,然后把该线程杀掉),可以从机制上解决工作线程被阻塞的问题。
3)连接管理
Nginx采取的方式是各工作进程根据自身的忙闲程度,动态调整获取新连接的时机,具体实现是,当本进程当前连接数达到最大worker_connections的7/8时,本worker进程不会去试图拿accept锁,也不会去处理新连接,这样其他worker进程就更有机会去处理监听句柄,建立新连接。
4)插件机制
Nginx主要提供如下几种形式的插件扩展:1) 通过stream机制进行协议扩展,比如增加memcached协议代理和负载均衡等;2) Handler方式处理HTTP请求;3) 对HTTP请求和响应消息进行过滤,比如可以修改和定制消息内容等;4) 访问Upstream时的负载均衡,可以提供自定义的负载均衡机制。
Envoy也提供了强大的插件扩展机制,当前使用最多的地方是监听过滤插件和网络处理过滤插件,和Nginx相比,Envoy网络插件定位在协议层面,以HTTP协议为例,Envoy并没有那么细粒度的插件扩展机制,如果想对Envoy的HTTP协议处理进行扩展,当前并没有提供特别多的扩展点。
5)配置管理
Nginx采用层层嵌套的方式,最外层是核心模块的配置,主要包括events事件模块、http模块和stream模块,对于最复杂的http模块来说,下面会嵌套着server子模块,负责监听和管理http请求,server子模块下还会嵌套着一到多个location,用于描述具体的路由规则。静态配置。
Envoy的配置管理部分设计的就比较优雅,配置格式直接使用了Protobuf3,复用了Protobuf3的数据描述能力和自动代码生成机制,完全省去了配置解析的过程,并且也非常方便对配置格式的有效性进行验证。动态配置。
6)内存管理
Nginx内存管理通过Nginx内存池实现
Envoy在内存管理方面提供的支持不多,完全依赖智能指针机制
7)部署和运维
Nginx采用多进程的通信架构,主进程负责维护工作进程的状态,一方面监控工作进程的状态,状态异常时会对工作进程进行重启,同时主进程也可以接收外界的管理信号,通知工作进程完成相应的操作,比如通过kill信号通知Nginx优雅重启,主进程在接收到重启信号后,会先重新加载配置,然后启动新进程开始接收新的请求,并向所有工作线程发送信号,通知它们不再接收新的请求,并在处理完所有pending请求后自动退出。
Envoy是通过控制平面组件PilotAgent和Sidecar-injection进行管理,Pilot Agent负责管理Envoy的运行状态,当Envoy状态有问题时,Pilot Agent会将Envoy重启,如果重启仍然不能解决问题,会尝试将Envoy调度到其他环境下;Sidecar-injection负责Envoy的自动注入。
5、Istio
Istio是Google、IBM和Lyft联合推出的开源微服务ServiceMesh框架,旨在解决大量微服务的发现、连接、管理、监控以及安全等问题,Istio综合了Google、IBM和Lyft在微服务领域的强大积累和经验,以Envoy为基础,将Envoy作为默认的数据平面,同时提供强大的控制平面能力。
6、Service Mesh分析和展望
1)性能和架构的博弈
2)非Kubernetes平台的支持
3)标准化
参考:https://mp.weixin.qq.com/s/CExQyIOXmFsKzBxOE5f6xA