服务网格的现状和未来
服务网格(Service Mesh)是一种微服务治理基础设施,用于控制、监测微服务之间的东西向流量。它通常由控制平面、数据平面两部分组成。其中数据平面就是伴随着业务应用部署的网络代理,控制平面则是一组独立的组件,和数据平面交互,发送控制网络流量的规则,接收各类监测指标。业务应用的开发人员对服务网格的存在并无感知,这是服务网格最关键的优势。
服务网格的概念出现于2010年代早期,2017年前后开始风行。从ServiceMesher社区在2020年2月发起的终端用户调研结果来看,在生产环境下使用该技术的公司占比不到15%,大部分公司仍然在观望:
是什么原因阻碍了服务网格的大面积应用,它的未来会如何?本文将从主要从技术角度来细化分析。
Kubernetes早已成为容器编排领域的事实标准,主流服务网格框架都选择构筑在Kubernetes之上。Kubernetes和服务网格是相辅相成的,尽管功能上有些许重叠。Kubernetes主要专注于应用的部署,服务网格更关注应用的运行时管理。
目前占据着领导地位的服务网格框架是Istio + Envoy的组合。早期的Linkerd运行在JVM之上,资源消耗较高,已经被Linkerd 2所取代。Linkerd 2的进展不尽如人意,支持的特性比Istio要少很多。国内的参与者,包括阿里的SOFAMesh、华为的ASM等,这些框架一部分没有开源,另一部分更新较为缓慢,SOFAMesh的代码库2020年尚未有新代码合并到主干。
从ServiceMesher社区在2020年2月发起的终端用户调研结果来看,Istio和Envoy是用户关注度最高的服务网格开源项目:
要打造自研服务网格产品,理性的方案是以一种成熟的社区技术为基础,这是因为服务网格牵涉到的技术面很广,从零开发的成本非常高。目前来看,Istio + Envoy是较好的选择,包括AWS App Mesh、F5 Aspen Mesh等商业方案都是在Istio / Envoy的基础上进行深入定制实现的。
2019年5月,微软联合一系列厂商发布了一个服务网格规范(Service Mesh Interface,SMI),它是一个基于Kubernetes的服务网格接口标准,致力于实现不同服务网格框架的互操作性。
巨头们早已看到了服务网格的价值,并且纷纷出手,支持或参与开源项目,推出自己的商业产品。百花齐放的服务网格产品,接口不一致,必然会导致供应商锁定问题,一旦选择了某个厂商的服务网格产品,你将很难切换到另一家。SMI需要解决的就是供应商锁定问题,微软、Vmware、HashiCorp、F5等都加入了SMI阵营。遗憾的是,社区的领头羊,Istio阵营的Google、IBM等却对SMI不感兴趣,个中利益纷争耐人寻味。
标准化的分歧,的确会导致技术选型相关的风险,因为我们难以准确判断中长期的技术方向。为了规避这类风险,自研服务网格产品应该面向上层应用暴露技术中立的API,避免在API上和某种服务网格实现耦合。
我已经在多个团队中目睹推行服务网格甚至是Kubernetes时遇到强大的阻力,原因是这些团队已经在使用“等位”技术,而且工作的不错。
这种阻力在以Java为单一技术栈的公司/团队中尤为明显。Java生态圈一直非常繁荣,自成体系。特别是Spring Cloud项目提供了服务发现、负载均衡、内容感知路由等特性,这些正和Kubernetes、Istio存在功能重叠,导致技术迁移的动力不足。
在决定引入服务网格技术之前,首先要确信自己的团队的确需要它。对于规模很小的公司/团队,答案往往是否。答案反转的一个重要的契机是,你提供的服务需要被别的团队所消费,且这个团队和你使用不一样的技术栈,例如使用Go而非Java。
另外需要注意一点,Spring Cloud和Kubernetes并非水火不容,它不但可以容器化部署在Kubernetes上,改用Kubernetes作为服务发现机制也非常简单。 事实上,Spring背后的VMware是云原生领域的重要参与者,Spring Cloud对Kubernetes的集成能力也在不断提高。服务网格属于PaaS层而非应用级的解决方案,它和Spring Cloud这类框架可以长期共同存在,平滑迁移。
服务网格的边缘代理,则又和API网关存在功能上的重叠。前些年在Kubernetes尚未普遍应用的时候,很多互联网开发团队就在自研API网关产品。我的建议是,现有的API网关产品可以继续使用,如果团队已经全面转向云原生,则不要新造轮子,可以基于Envoy构建API网关。
Istio的架构,在1.0版本之后已经经过多次重大调整,以平衡架构的优雅性和性能。1.1版本进一步微服务化,分离了 Pilot 的配置下发功能到新的 Galley 组件中,将 Mixer 组件中原本进程内插件改为进程外插件,这一版本加剧了性能问题。随后的版本又开始180度转弯,放弃架构之美,追求性能和实用。到1.5版本为止,Mixer已经废弃,遥测功能下沉到Envoy代理中,控制平面变成一个单体的istiod:
即使是在禁用Mixer,仅仅启用最基础的流量管理功能的情况下,Envoy引入的性能开销仍然需要关注。对于规模很大的命名空间,Envoy占用的内存会比较可观,甚至大于被代理的微服务本身。使用Istio提供的Sidecar CRD,可以对代理进行细粒度配置,很大程度上降低内存消耗。
在服务网格内部,每个请求都要经由一个客户端代理、一个服务端代理。在Istio 1.5版本的默认配置下的基准测试中,客户端代理的P99延迟大约为2.8ms,服务端代理的P99延迟大约为2.7ms,也就是一次微服务调用会可能会引入5.5ms的延迟。如果调用链比较复杂,引入的总延迟可能达到数十毫秒。大部分场景下,这样的延迟不是问题,但对于一些本身响应时间很短的HTTP服务,影响就难以忽略了。
Istio数据平面引入的延迟,主要有三个来源:
- 代理本身的逻辑:L7代理逻辑较为复杂,执行这些逻辑需要CPU时间。如果扩展了自定义的过滤器,这些过滤器的性能很关键
- 流量重定向:Istio使用iptables重定向拦截Pod的全部流量给Enovy处理,这种重定向需要多次遍历TCP/IP栈,单次拦截可能引入0.3ms左右的延迟。基于Socket感知的BPF程序,例如Cilium CNI,可以消除这一延迟,但是对内核版本有要求
- 网络传输:不管是否引入代理,网络传输导致的延迟都存在。但是代理给我们带来了降低延迟的契机。QUIC可以代替TCP作为HTTP的底层协议,它具有更好的拥塞控制、多路复用、前向纠错、链接迁移特性,在网格的边缘这些特性具有显著的优势。Envoy已经逐步加入对QUIC的支持,当实现了QUIC Termination后,就能透明的将业务应用流量的底层传输协议更换为QUIC,提升性能
Envoy基于C++开发,扩展它需要编写自定义的过滤器。2019年12月进入W3C推荐标准的WebAssembly(Wasm)改变了这一状况。Wasm是一套可移植的字节码格式,你可以将任何主流语言编写的代码编译为Wasm字节码。Envoy现在已经能够支持Wasm Filter,这意味着扩展Envoy,和团队现有的系统进行集成,不会再遇到编程语言上的障碍,也不需要重新部署新版本的Enovy二进制文件。
尽管尚未合并到主干,Istio 1.5版本附带的Envoy,已经包含了Alpha版本的Wasm Filter支持。
Istio的开发语言是Go,经典的扩展方式是Mixer插件,如今这种方式已经被废弃。 Mixer的两大功能,Check和Report,将分别由Proxy-Wasm plugins和Telemetry V2代替。Proxy-Wasm是一套ABI规范,规定了Envoy这样的L4/L7代理软件如何和它们的Wasm扩展进行交互。Istio 1.6将提供Proxy-Wasm plugins的统一配置API。
服务网格的可观察性有三个方面的内容:日志收集、分布式追踪、指标收集。
日志收集仍然是基于EFK/ELK这样的集中化日志解决方案。Envoy代理可以提供完善的访问日志,收集这些日志后,可以在ElasticSearch中检索和分析。
指标收集,粒度可以细致到微服务级别,这个从设计上来说是刻意的,因为服务网格中的服务,就是指微服务。遗憾的是,很多业务应用并没有按照微服务的理念进行设计,单个服务提供了太多的职责。这样的服务出现了问题,在网格拓扑图上只能进行模糊的定位。另一方面,Envoy支持的协议仍然很少,HTTP、WebSocket、gRPC被支持的很好,Redis、MySQL、ZooKeeper、Dubbo、Kafka目前获得了一定的支持,其它的协议目前Enovy都不能理解,只能看作是原始的L4流量。无法理解协议,也就不能收集有价值的指标,并展现在网格拓扑图上。
应用层协议过于繁多,每种协议还可能有多个版本,要支持这么多协议的确是个苦差。但是在自研服务网格的产品时,我们只需要关注团队经常用到的协议,针对它们进行解析就足够了。
对于分布式追踪,Istio能够自动添加必要的请求头,以便在微服务之间传递Trace ID、Span ID、Parent ID,并且,Istio会将这些信息上报给分布式追踪系统。 但是,Istio能做的也仅仅是这些了,对于单个微服务来说,还得依靠开发人员把入站请求中的Trace ID传递给出站请求。
通用的、零入侵的自动传递调用链上下文的解决方案,在技术上是不可能实现的。因为各种编程语言具有不同的线程模型、运行时架构,无法单纯的从网络流量中分析出足够的信息。某些语言,可以几乎没有入侵的自动传递调用链上下文,例如Java,可以通过Java Instrumentation来穷举式的拦截各种流行的客户端库,自动传递调用链信息。另外一些语言,则只能编写代码传递。
经过上文的分析,我们了解到服务网格技术仍然存在一定的不足。在标准化方面,云厂商巨头们竞争激烈,这为我们带来了技术选型的风险。由于功能类似的遗留技术的存在,导致服务网格技术推广起来遇到阻力。此外,在性能、可扩展性、可观察性等非功能因素方面,现有主流服务网格开源项目存在不尽如人意的地方。
不过,我们应当看到社区的繁荣发展,开源项目的不断进步,以及服务网格具有的,不可替代的技术优势。
以Istio为例,它的性能自发布以来已经有了长足的进步,代理的P99延迟从数十ms降为10ms,进一步降低到5ms级别,已经能满足绝大部分场景的需求。如果需要进一步降低延迟,可以考虑BPF和QUIC等技术。
零入侵是服务网格不可替代的技术优势,这种优势在大型企业中更加明显。大型企业会有很多开发团队,使用不同的技术栈,Spring Cloud这种入侵式、绑定到JVM语言的解决方案显然是不可取的。微服务甚至是无服务是可预见的趋势,相对笨重的JVM并不十分适合这种应用场景,将企业的技术栈锁死在JVM甚至是Spring Cloud不是明智的选择。
服务网格领域仍然有大量的事情等待人们去做,比如各种中间件协议的解析、提升边缘节点性能的QUIC Termination、智能化的灰度发布平台,等等。自研服务网格产品,对内提升服务治理水平,对外输出社区影响力,现在就是很好的契机。
Leave a Reply