本文要点
服务网格管理分布式(一般是基于微服务的)软件系统中所有的服务与服务间的通信。一般来讲,它是通过使用名为“sidecar”代理实现的,sidecar 代理会和每个服务一起部署,所有的流量都会通过它来进行透明地路由。
服务网格中使用的代理通常是“应用层”可感知的(运维在 OSI 网络栈中的第七层)。这意味着流量路由决策和度量指标标记可以利用 HTTP 头信息或其他应用层协议元数据中的数据来实现。
服务网格提供了动态服务发现和流量管理的功能,包括用于测试的流量 shadowing(复制)以及用于金丝雀发布、增量发布以及 A/B 类型体验的流量分割。
服务网格还支持横切性需求的实现和实施,比如安全性(提供服务标识和 TLS)以及可靠性(限速、断路器)。
服务网格处于系统中每个请求处理的关键路径上,所以它也可以提供额外的“可观察性”,比如请求的分布式跟踪、HTTP 错误码的频率、全局以及服务与服务之间的延迟。
使用服务网格会有明显的收益,但是有一些权衡也需要进行分析,比如增加复杂性以及额外的运行时资源。
服务网格技术正在快速成为(云原生)应用平台“管道”的一部分。这个领域中有趣的创新是与高层次的抽象和以人为中心的控制平面息息相关的。
流行的服务网格包括 Linkerd、Istio、Consul、Kuma 和 Maesh。在这个领域中,支撑技术包括:七层感知的代理(如 Envoy、HAProxy、NGINX 和 MOSN)以及服务网格编排、可视化以及有助于理解的工具,如 SuperGloo、Kiali 和 Dive。
大约在 2016 年,“服务网格”(service mesh)这个术语突然间在微服务、云计算和 DevOps 等领域冒了出来。但是,与计算机行业中的很多概念一样,相关的模式和技术其实有着很长的历史。
服务网格的出现在很大程度上源于 IT 领域的一场完美风暴。开发人员开始使用多语言(polyglot)的方式编写分布式系统,因此需要动态的服务发现功能。运维领域则开始使用短暂存活的基础设施,他们希望能够优雅地处理难以避免的通信故障并执行网络策略。平台团队开始使用像 Kubernetes 这样的容器编排平台,他们希望能够使用现代 API 驱动的网络代理(如 Envoy)来动态路由系统内和系统周边的流量。
本文旨在回答软件架构师和技术领导者所关切的问题,比如:服务网格是什么?我需要服务网格吗?我该如何评估不同的服务网格方案?
服务网格模式
服务网格模式的焦点在于管理分布式软件系统中所有的服务与服务间的通信。
背景(Context)
该模式有双重背景:首先,工程师已经采用了微服务架构模式并且通过将多个服务(理想情况下,服务是单一职责的,并且是可独立部署的)组合在一起的方式来构建应用程序。其次,组织开始采用云原生平台技术,如容器(如 Docker)、编排器(如 Kubernetes)和代理/网关(如 Envoy)。
意图(Intent)
服务网格模式试图解决的问题包括:
消除将特定语言的通信库编译到每个服务的必要性,这些通信库一般会用来处理服务发现、路由和应用层(第 7 层)的非功能性通信需求。
将服务通信的配置外部化,包括外部服务的网络位置、安全凭证和服务的质量目标。
提供对其他服务的被动和主动监控。
在整个分布式系统中,实现策略实施的去中心化。
提供默认的可观察性并标准化相关数据的收集。
支持请求日志
配置分布式跟踪
收集度量指标
结构(Structure)
服务网格模式主要关注传统上的“东-西(east-west)流量”,也就是基于远程过程调用(remote procedure call,RPC)的流量:起源于数据中心内部并且会跨服务的请求/响应类型的通信。这与 API 网关或边缘代理是不同的,后者旨在处理“南-北(north-south)流量”:起源于外部的通信并且要进入(ingress)数据中心中的一个端点或服务。
服务网格的特性
服务网格的实现一般会提供如下特性中的一项或多项:
规范化命名并添加逻辑路由(如将代码级别的名字“user-service”映射至平台中的特定地址“user-service”)。
提供路由重塑(traffic shaping)和路由转移(traffic shifting)功能。
维护负载均衡,通常会通过可配置的算法实现。
提供服务发布控制(如金丝雀发布和流量切分)
提供针对每个请求的路由(如流量 shadowing、故障注入和调试重路由)。
添加基线可靠性,比如健康检查、超时/截止期限、断路器和重试。
增加安全性,这是通过透明的双向传输层安全(Transport Level Security,TLS)和像访问控制列表(Access Control List,ACL)这样的策略实现的。
提供额外的可观察性和监控,比如最重要的指标(请求量、成功率和延迟),支持分布式跟踪,以及“捕获”和实时检查服务与服务之间通信的能力。
支持平台团队配置“sane defaults(一组能够让程序运行地更好、更快的 Linux/Unix 配置,参见该地址——译者注)”,保护系统免受不良通信的影响。
服务网格的架构:直探本质
服务网格有两个高层级的组件所组成:数据平面和控制平面。Envoy Proxy的创建者 Matt Klein 曾经就服务网格的数据平面和控制平面这一话题写过一篇非常精彩的深入介绍文章。
一般来讲,数据平面“完成真正的工作”,负责“有条件地翻译、转发和观察流入和流出某个[网络端点]的网络包”。在现代系统中,数据平面一般会以代理的方式来实现(比如 Envoy、HAProxy或MOSN),代理会作为“sidecar”在每个服务的进程之外运行。
Klein 指出,在服务网格中,数据平面“会接触系统中的每个包/请求,它要负责服务发现、健康检查、路由、负载均衡、认证/授权和可观察性。”CNCF 正在根据 Klein 之前题为The Universal Data Plane API的博客文章创建一个统一的Data Plane API。这个提议扩展了由 Envoy 定义和实现的xDS API,并且在其他的代理中得到了支持,比如 MOSN。
控制平面则“监督工作的执行”,它会获取所有的数据平面实例(即一组隔离的无状态 sidecar 代理)并将它们转换成一个分布式系统。控制平面不会接触系统中的包/请求,它允许运维人员为网格中所有运行的数据平面提供策略和配置。控制平面还能够收集和集中数据平面的遥测数据,供运维人员使用。Red Hat 为这个场景专门研发了Kiali。
下图出自 Istio 的架构文档,尽管所标记的技术是 Istio 特有的,但是组件是对所有的服务网格实现通用的。
Istio 架构,阐述了控制平面和代理数据平面是如何交互的(图片来源于 Istio 文档)
使用场景
服务网格能够适用于或支持各种使用场景。
动态服务发现和路由
服务网格提供了动态服务发现和流量管理的功能,包括针对测试的流量 shadowing(duplicating),以及针对金丝雀发布和 A/B 类型体验的流量切分。
服务网格中所使用的代理一般是“应用层”可感知的(运维在 OSI 网络栈中的第七层)。这意味着流量路由的决策和度量指标的标记可以利用 HTTP 头信息或其他应用层协议元数据中的数据。
服务与服务之间通信的可靠性
服务网格支持横切的可靠性需求的实现和实施,比如请求重试、超时、限速和断路器。服务网格通常用于补偿(或封装)分布式计算八大谬误的处理。应该注意的是,服务网格只能提供线路级别的可靠性支持(如重试 HTTP 请求),最终应该由服务来处理相关的业务影响,比如多次(非幂等)的 HTTP POST 请求。
流量的可观察性
由于服务网格位于系统中每个请求处理的关键路径上,所以它能够提供额外的“可观察性”,比如分布式跟踪请求、HTTP 错误码的频率、全局以及服务与服务之间的延迟。尽管“单面板(single pane of glass)”视图这个术语在企业级领域已经被滥用了,但是服务网格被认为是一种能够捕获所有必要数据,从而实现整个系统中“单面板”流量视图的方法。
通信的安全性
服务网格还支持横切安全性需求的实现和实施,比如提供服务识别(通过 x509 证书)、启用应用层的服务/网络分段(segmentation)(例如,“服务 A”可以与“服务 B”通信,但是不能与“服务 C”通信)、确保所有的通信都是加密的(通过 TLS)并确保存在有效的用户级身份 token 或“passports”。
反模式
当使用某项技术的反模式出现时,这通常是该技术成熟的标志。服务网格也不能例外。
过多的流量管理层(就像海龟一样,一层驼一层)
当开发人员无法与平台或运维团队协作时,就会出现这种反模式,并且会在代码中复制服务网格已经实现的通信处理逻辑。例如,除了服务网格配置所提供的线路级别的重试策略之外,应用程序还在代码中实现了重试策略。这种反模式还可能会导致重复事务的问题。
服务网格银弹
在 IT 行业,并不存在所谓的“银弹”,但是供应商有时候会忍不住给某项新技术打上这样的标签。服务网格不能解决微服务、容器编排器(如 Kubernetes)或云网络中所有的通信问题。服务网格只致力于解决服务与服务(东-西)通信的问题,部署和运行服务网格有很明显的运维成本。
企业级服务总线 2.0
在微服务面向服务架构(service-oriented architecture,SOA)时代之前,企业服务总线(Enterprise Service Bus,ESB)实现了软件组件之间的通信系统。有些人担心,ESB 时代的很多错误会在服务网格的使用过程中重复出现。
ESB 所提供的通信中心化控制显然是很有价值的。但是,这些技术的开发是由供应商驱动的,这会带来很多问题,比如:ESB 之间缺少互操作性、行业标准的定制扩展(如向 WS-*兼容模式添加供应商特定的配置)以及高昂的成本。ESB 供应商也无法阻止将业务逻辑集成和紧耦合到通信总线中。
大爆炸式的部署
IT 界普遍存在这样一种误解,即认为大爆炸式的部署方法最易于管理,但根据来自Accelerate的研究和DevOps的状态报告,情况并非如此。随着服务网格的全面推出,这意味着该技术正处于处理所有终端用户请求的关键路径上,因此大爆炸式的部署具有很高的风险。
服务网格实现和产品
以下是当前服务网格实现的非详尽列表:
服务网格的对比:该采用哪个服务网格?
服务网格领域发展非常快,因此对它们进行对比很快就会过时。但是,依然还是有很多对比可供参考。请注意,这里面可能会有一些来源相关的偏见,并且要注意对比的日期。
https://kubedex.com/istio-vs-linkerd-vs-linkerd2-vs-consul/ (2019 年 5 月修正)
https://platform9.com/blog/kubernetes-service-mesh-a-comparison-of-istio-linkerd-and-consul/ (截止到 2019 年 10 月)
https://servicemesh.es/ (最后发布于 2020 年 2 月)
InfoQ 始终建议服务网格采用者对每个产品都要进行详尽调查和试验。
服务网格教程
想要尝试各种服务网格的工程师或架构师可以参考如下的教程、实验和工具:
Layer 5 Meshery:一个多服务网格管理面板*
Solo’s SuperGloo:服务网格编排平台
服务网格的历史
自从 2013 年 Airbnb 发布SmartStack以来,InfoQ 就一直在跟踪我们称为服务网格的话题,SmartStack 为新兴的“微服务”风格架构提供了进程外的服务发现机制(借助HAProxy)。在此之前,很多之前被称为“独角兽”的组织都在研究类似的技术。从 2000 年代初开始,谷歌就在开发其Stubby RPC 框架,后来该框架演化成了gRPC,另外,Google Frontend (GFE)和 Global Software Load Balancer(GSLB)的特征在Istio中都可以看到。在 2010 年代早期,Twitter 开始开发基于 Scala 的Finagle,而Linkerd服务网格就是基于它出现的。
2014 年底,Netflix 发布了基于JVM的完整工具套件,其中包括Prana,这是一个“sidecar”进程,任何语言编写的应用服务都能通过 HTTP 与独立的库实例进行通信。在 2016 年,NGINX 团队开始讨论所谓的“Fabric模型”,它非常类似于服务网格,但是需要使用商业的 NGINX Plus 产品来实现。
在服务网格历史上,其他值得关注的还有 2017 年 5 月发布的Istio、2018 年 7 月发布的Linkerd 2.0、2018 年 11 月发布的Consul Connect和SuperGloo、2019 年 5 月发布的服务网格接口(service mesh interface,SMI)以及 2019 年 9 月发布的 Maesh 和 Kuma。
甚至还有在独角兽组织之外出现的服务网格,比如 HashiCorp 的Consul,其灵感来源于上述的技术,通常致力于实现CoreOS创造的“GIFEE”理念,即:适用于所有人的谷歌基础设施。
关于现代服务网格理念如何演化的深入历史,Phil Calçado曾经写过一篇综合性的文章“模式:服务网格”。
探索服务网格的未来
因为服务网格依然处于早期采用阶段,还有许多工作需要未来完成。广泛地来讲,有四个特别有趣的领域:在 RPC 之外,添加对其他使用场景的支持、标准化接口和运维、将服务网格进一步推送至平台 fabric 中以及为服务网格技术构建有效的人工控制平面。
Kasun Indrasiri探索了“将服务网格用于事件驱动消息的潜力”,在他的探索中,讨论了在服务网格中实现消息支持的两种新兴架构模式:协议代理 sidecar 以及 HTTP 桥接 sidecar。在服务网格社区,这是一个很活跃的开发领域,在Envoy中支持Apache Kafka得到了很多的关注。
Christian Posta 曾经写过一篇文章“以统一、标准的API来整合服务网格”,试图将服务网格的使用标准化。这篇文章也讨论了最近微软和 KubeCon EU 的合作伙伴所发布的服务网格接口(Service Mesh Interface,SMI)。SMI 定义了一组通用且可移植的 API,旨在提供一种方式允许在不同的服务网格技术(包括 Istio、Linkerd 和 Consul Connect)之间实现互操作性。
关于如何将服务网格集成至平台 fabric 又可以分为两个子话题。
首先,需要有些工作来减少服务网格数据平面所带来的网络开销。这包括数据平面开发工具包(data plane development kit,DPDK),这是一个用户空间应用,它“绕过了 Linux 内核网络栈厚重的分层,直接与网络硬件对话”,
Cilium团队的工作利用了 Linux 内核中扩展的Berkley包过滤(extended Berkley Packet Filter,eBPF)功能 ,它适用于“非常高效的网络、策略执行和负载均衡功能”。另外一个团队正在借助网络服务网格(Network Service Mesh)将服务网格的理念映射到 L2/L3 载荷中,致力于“以云原生的方式重新想象网络功能虚拟化(network function virtualization,NFV)”。
其次,有很多举措正在试图将服务网格与公有云平台更紧密地集成在一起,比如AWS App Mesh、GCP Traffic Director和Azure Service Fabric Mesh。
Buoyant 团队正在开发针对服务网格技术的以人为中心的控制平面。他们最近发布了Dive,这是一个基于 SaaS 的“团队控制平面”,适用于运维 Kubernetes 的平台团队。Dive 在 Linkerd 服务网格之上添加了更高层级的、以人为中心的功能,并提供了服务目录、应用程序发布的审计日志、全局服务拓扑等功能。
FAQ
什么是服务网格?
服务网格技术管理分布式(可能是基于微服务的)软件系统中所有的服务与服务(即“东-西”方向)之间的流量。它提供了以业务为中心的功能性操作,比如路由,也提供了非功能性支持,比如实施安全策略、服务质量以及速度限制。它通常会以 sidecar 代理的形式来实现(尽管不是唯一方案),所有的服务都会通过 sidecar 代理通信。
服务网格与 API 网关的区别是什么?
服务网格技术管理分布式(可能是基于微服务的)软件系统中所有的服务与服务(即“东-西”方向)之间的流量。它提供了以业务为中心的功能性操作,比如路由,也提供了非功能性支持,比如实施安全策略、服务质量以及速度限制。
API 网关管理所有进入(ingress)集群的“南-北”流量,并对跨功能性的通信需求提供额外的支持。它作为系统的唯一入口,使多个 API 或服务具有内聚性,为用户提供一致的体验。
如果我正在部署微服务的话,那么我需要服务网格吗?
不一定。服务网格会给技术栈带来运维复杂性,因此只有当组织在扩展服务与服务之间的通信时遇到问题或者有特定的使用场景需要解决时,才应该考虑部署。
我需要服务网格来实现微服务的服务发现功能吗?
并非如此。服务网格确实提供了一种实现服务发现的方式。但是,还有其他方案,包括特定语言的库(如Ribbon和Eureka,或者Finagle)。
服务网格会增加服务与服务间通信的开销/延迟吗?
是的,当一个服务与另一个服务通信时,服务网格至少会增加两次额外的网络跃点(第一个来自处理源的出站连接的代理,第二个来自处理目标的入站连接的代理)。然而,这种额外的网络跳跃通常发生在本地主机或环回网络接口上,并且只会增加很少量的延迟(以毫秒为单位)。对目标使用场景进行试验并确定是否是一个问题,这应该是服务网格分析和评估工作的一部分。
服务网格不应该是应用程序部署到 Kubernetes 或“云原生平台”的一部分吗?
有这种可能。在云原生平台组件中,在维持关注点分离方面还有争论(例如,Kubernetes 负责提供容器编排,服务网格负责服务与服务之间的通信)。但是,将类似服务网格这样的功能引入到现代平台即服务(PaaS)的工作也在进行中。
我该如何实现、部署和采用服务网格?
最佳方式就是分析各种服务网格产品(参见上文),并遵循所选服务网格的实现指南。总体而言,最好与所有的利益相关者一起工作,并逐步将新技术部署到生产环境中。
我可以构建自己的服务网格吗?
可以,但是更该问的问题是你应该这样做吗?构建服务网格是组织的核心竞争力吗?你能以更有效的方式为客户提供价值吗?你是否承诺要维护自己的服务网格,修补它的安全问题,并不断更新它,难道只有这样才能利用新技术?随着开源和商业服务网格产品的出现,使用现有的解决方案可能更有效。
在软件交付组织中,哪个团队要负责服务网格?
一般来讲,平台或运维团队负责服务网格,以及 Kubernetes 和持续交付管道基础设施。但是,开发人员会配置服务网格的属性,因此两个团队要紧密合作。很多组织在跟随云先驱(如 Netflix、Spotify 和谷歌)的脚步,创建内部的平台团队,该团队负责为 全周期以产品为核心的开发团队提供工具和服务。
Envoy 是服务网格吗?
不是,Envoy 是一个云原生代理,它最初是由 Lyft 团队设计和构建的。在服务网格中,Envoy 通常被用作数据平面。但是,要成为服务网格,Envoy 必须与控制平面联合使用,这样技术组合起来才能成为服务网格。控制平面可以是简单的中心化配置文件仓库和指标收集器,也可以是综合、复杂的方案,如 Istio。
“Istio”和“服务网格”这两个词是一回事儿吗?
不是。Istio 是一种服务网格。鉴于服务网格刚出现时,Istio 的流行程度,有些地方将 Istio 与服务网格混为一谈。这种问题并不是服务网格特有的,相同的挑战也出现在 Docker 和容器技术中。
我该使用哪个服务网格?
这个问题没有唯一的答案。工程师必须了解他们当前的需求,以及实现团队的技能、资源和时间。上文中关于服务网格对比的链接是一个很好的探索起点,但是我们强烈建议组织至少尝试两个服务网格,以便了解哪些产品、技术和工作流最适合它们。
我可以在 Kubernetes 之外使用服务网格吗?
是的。很多服务网格允许在各种基础设施上安装和管理数据平面代理和相关的控制平面。HashiCorp的Consul是这方面最著名的例子,Istio 也被实验性地用在Cloud Foundry中。
补充材料
术语表
API 网关:管理集群中所有的进入(ingress)流量,即南-北流量,并提供额外的功能。它作为系统的唯一入口点,使多个 API 或服务具有内聚性,为用户提供统一的体验。
Consul:来自 HashiCorp 的基于 Go 的服务网格。
控制平面:获取数据平面(代理)的所有实例并将它们转换成运维人员可以进行可视化和控制的分布式系统。
数据平面:一个代理,负责有条件地翻译、转发和观察流入和流出服务网络端点的每个网络包。
东-西流量:数据中心、网络或 Kubernetes 集群内部的网络流量。传统的网络图在绘制服务到服务(数据中心间)的流量时是从左到右(从东到西)绘制的。
Envoy 代理:开源的边缘和服务代理,为云原生应用而设计。Envoy 通常用作服务网格实现中的数据平面。
进入(Ingress)流量:来自数据中心、网络或 Kubernetes 集群外部的网络流量。
Istio:基于 C++(数据平面)和 Go(控制平面)的服务网格,最初由谷歌和 IBM 与来自 Lyft 的 Envoy 团队合作创建。
Kubernetes:CNCF 托管的容器编排和调度框架,起源于谷歌。
Kuma:来自 Kong 的基于 Go 的服务网格。
Linkerd:一个基于 Rust(数据平面)和 Go(控制平面)的服务网格,源自 Twitter 早期基于 JVM 的通信框架。
Maesh:来自 Containous 的基于 Go 的服务网格,Containous 是 Traefik API 网关的维护者。
MOSN:来自 Ant Financial 团队的基于 Go 的代理,实现了(Envoy)xDS API。
南-北流量:进入(ingress)数据中心、网络或 Kubernetes 集群的流量。在传统的网络图中,进入数据中心的流量会绘制在页面顶部并(从北向南)流经网络。
代理:充当端点组件之间中介的软件系统。
分区(Segmentation):将网络或集群切分为多个子网络。
服务网格:管理分布式(可能是基于微服务的)软件系统中所有的服务与服务(即“东-西”方向)之间的流量。它提供了功能性操作,比如路由,也提供了非功能性支持,比如实施安全策略、服务质量以及速度限制。
服务网格接口(Service Mesh Interface,SMI):一个正在制定中的标准接口,用于将服务网格部署到 Kubernetes。
服务网格策略:服务/端点集合之间以及和其他网络端点之间如何通信的规范。
Sidecar:一种部署模式,在这种模式中,附加的进程、服务或容器会与现有的服务(参考摩托车的挎斗)一起部署。
单面板(Single pane of glass):在一个 UI 或管理控制台中统一展示多个源的数据。
流量重塑(Traffic shaping):修改网络中的流量,例如,速率限制或负载削减。
流量转移(Traffic shifting):将流量从一个位置迁移到另一个位置。
作者简介:
Daniel Bryant 一直在组织内和技术方面引领变化。Daniel 现在的技术专长是“DevOps”工具、云/容器平台和微服务实现。他还是伦敦 Java 社区(LJC)的领导者,参与多个开源项目,为 InfoQ、DZone 和 Voxxed 技术网站撰写文章,并且经常在 QCon、JavaOne 和 Devoxx 这样的国际会议上发表演讲。
原文链接:
Service Mesh Ultimate Guide: Managing Service-to-Service Communications in the Era of Microservices
评论 1 条评论