服务网格基础
服务网格的概念
指的是第三代服务网格,将服务治理能力归一到服务网格中,以 sidecar 方式,也就是服务治理能力通过统一的容器:运行于对应的 Pod 业务容器所在的 Pod 周边的方式去解决。
服务网格概念源于 Buoyant 公司的 CEO Willian Morgan 的文章“What’s a service mesh? And do I need one?”
指专注于处理服务间通信的基础设施,它负载在现代云原生应用组成的复杂拓扑中可靠地传递请求
治理模式:除了处理业务逻辑的相关功能之外,每个微服务还必须实现此前单体应用模型中用于网络间通信的基础功能,甚至还包括分布式应用程序之间的通信环境中应该实现的其他网络功能,例如熔断、限流、应用跟踪、指标采集、服务发现和负载均衡等
也就是说,服务网格本身提供的是服务治理模式,业务应用负责处理业务逻辑的相关功能,而治理功能则是由 sidecar 通过服务网格的基础设施层处理。
服务网格基本功能
控制服务间通信:熔断、重试、超时、故障注入、负载均衡和故障转移等
服务发现:通过专用的服务总线发现服务端点
可观测:指标数据采集、监控、分布式日志记录和分布式追踪
安全性:TLS/SSL 通信和密钥管理
身份认证和授权检查:身份认证,以及基于黑白名单或 RBAC 的访问控制功能
部署:对容器技术的原生支持,例如 Docker 和 k8s
服务间的通信协议:HTTP1.1、HTTP2.0、gRPC
健康状态检测:检测上游服务的健康状态
控制平面与数据平面
数据平面:触及系统中的每个数据包或请求,负责服务发现、健康状态、路由、负载均衡、身份验证/授权和可观测性等
控制平面:为网格中的所有正在运行的数据平面提供策略和配置,从而将所有数据平面联合构建为分布式系统,它不接触系统中的任何数据包或请求。
例如确定两个服务 Service X 到 Service Y 之间路由,Service Y 相关集群的负载均衡机制、断路策略、流量转移机制等,并将决策下发给 Service X 和 Service Y 的 Sidecar
控制平面组件:
工作负载调度程序:借助与底层的基础设施(例如 kubernetes)完成服务及其 Sidecar 运行位置的调度策略
服务发现:服务网格中的服务发现
Sidecar 代理配置 API:各 Sidecar 代理以最终一致的方式从各种系统组件获取配置
控制平面 UI:管理人员的操作接口,用于配置全局级别的设置,例如部署、身份认证和授权、路由及负载均衡等
Service Mesh 解决方案极大降低了业务逻辑与网络功能之间的耦合度,能够快捷、方便地集成到现有的业务环境中,并提供了多语言、多协议支持,运维和管理成本被大大压缩,且开发人员能够将精力集中于业务逻辑本身,而无须再灌注业务代码以外的其它功能。
一旦启用 Service Mesh,服务间的通信将遵循一下通信逻辑:
● 微服务彼此间不会直接进行通信,而是由各服务前端的称为 Service Mesh 的代理程序进行;
● Service Mesh 内置支持服务发现、熔断、负载均衡等网络相关的用于控制服务间通信的各种高级功能
● Service Mesh 与编程语言无关,开发人员可以使用任何编程语言编写微服务的业务逻辑,各服务之间也可以使用不同的编程语言开发
● 服务间的通信的局部故障可由 Service Mesh 自动处理
● Service Mesh 中的各服务的代理程序由控制平面(Control Plane)集中管理;各代理程序之间的通信网络也称为数据平面(Data Plane)
● 部署于容器编排平台时,各代理程序会以微服务容器的 Sidecar 模式运行
在 istio 的语境当中,工作在业务容器周边,负责为业务容器提供代理功能的 sidecar Proxy 组成的基础设施网络称为数据平面,而负责统一管控数据平面工作比如下发配置,下发控制指令以控制其工作逻辑的组件,称为控制平面。
而 istio 本身,就是由控制平面和数据平面两部分构成,不过控制平面是它自身:istio,数据平面则是 envoy。并且,它所使用的 envoy 也不是独立的完全的原生 envoy,而是在其基础上二次开发后更好与 istio 整合以作为数据平面用的 envoy,因此实际上数据平面在 istio 中,称之为 istio-proxy。
容器+服务网格快速实现灰度发布与治理
微服务治理体系一共有三代,而我们如今大多数处于第二代,也就是传统的,基于 spring-cloud 的微服务治理体系。此时如果没有使用 Kubernetes 治理也是可以的,只不过应用运行在传统的裸服务器或者虚拟机环境之上,基于 jvm 环境独立运行每个应用。它们可以在 spring-cloud 框架当中的相关组件上完成服务治理所依赖的功能。
因此,运维工程师充当 DevOps 当中的 CICD 工程师,应用的发布、交付和部署都遵循传统运维时代的各种框架和工具。
我们也可以完全把 spring-cloud 的微服务体系运行于 Kubernetes 之上,不过需要把 Nacos 各种组件做成独立的服务,将业务代码部署在 Kubernetes 之上以容器方式运行,它们彼此间能够互相访问的同时,也能注册到服务治理总线上去。如果迁移到新的治理体系中,早期使用 spring-cloud 开发的应用,转为使用 spring-boot 开发即可。我们可以完全遵循 spring-boot 而无需考虑 spring-cloud 当中提供的 sdk 容纳的各种治理能力,仅需遵循 spring-boot 研发 java 应用,并遵循服务间的接口契约。它本身无需考虑分布式的问题。
因为,分布式能力交给 istio 和 envoy 去解决。不过,从传统的 spring-cloud 时代的微服务,迁移到 sitio 的微服务网格中,这不是运维工程师或开发工程师能做到的,而是需要依靠团队将系统的完整业务逻辑重构,需要在架构师组织下完成这些功能。很显然,这将产生巨大的研发成本,此时就需要考虑投资收益比是否合理。
很可能出现的情况是,将 spring-cloud 的应用运行在 Kubernetes 之上,依然使用 spring-cloud 的微服务治理能力,而不使用 istio 去治理。特别是早期的 istio 非常消耗系统的资源。
注意:istio 在 1.4 及之前的版本当中,数据平面的代理程序非常消耗系统资源,可能额外多占据 30%。所以 sito 从 1.5 之后的版本,做了架构改进。
服务网格和 Kubernetes 间的关系
Kubernetes
解决容器编排与调度的问题
本质是应用的生命周期管理工具
为服务网格提供基础支撑
Service Mesh
解决分布式应用间的通信问题
本质上是服务通信治理工具
是对 Kubernetes 在网络功能方面的扩展和延伸
以 istio 为例,它在 Kubernetes 基础上,利用 CRD 接口,结合自己的 Operator 和 Controller,扩展了 Kubernetes 的功能。Service Mesh 需要建构在 Kubernetes 平台之上,我们可以把应用托管在 Service Mesh。
新一代的服务治理体系当中,有两个标准:
数据平面标准:UDPA 统一数据平面 API 接口,典型实现 envoy
控制平面标准:SMI 市面上大多数控制平面都遵循 SMI 规范
云原生时代的微服务分布式体系
生命周期
容器和 Kubernetes 将打包、分发和部署应用程序的方法演化成了同编程语言无关的格式
对 Kubernetes 来说,需要管理的最小原子单元是容器,并且,它专注于在容器级别和流程模型上交付分布式原子单元
Kubernetes 在管理应用程序的生命周期、健康检查、恢复、部署和扩展等方面都做得很出色,但是在运行于容器内的分布式应用的其他方面却没有做得很好,例如灵活的网络,状态管理和绑定
尽管 Kubernetes 拥有有状态的工作负载、服务发现、 cron 作业及其他功能,但是所有这些原语都是在容器级别的,并且在容器内部,开发人员仍然必须使用特定于语言的库实现更高级的功能
这其实就是推动诸如 Envoy、 Linkerd、 Consul、 Knative、 Dapr 和 Camel-K 等项目的原因
网络 (Service Mesh)
Kubernetes 提供的围绕服务发现的基本网络功能打下了良好的基础,但这对于现代应用程序来说却仍嫌不足
随着微服务数量的增加和部署的加快,在不改动服务的情况下,对更高级的发布策略,管理安全性,指标,跟踪,从错误中恢复,模拟错误等等方面的需求变得越来越具有吸引力,并产生了一种新的软件类别,称为服务网格
服务网格将网络相关的关注点从包含业务逻辑的服务转移出来,放到一个单独的运行时中,该运行时可能是 Sidecar,也可能是节点级代理
服务网格可以执行高级路由、协助完成测试、处理某些方面的安全性问题,甚至可以支持特定于应用的协议(例如, Envoy 支持 Kafka、 MongoDB、 Redis 和 MySQL 等)
除了典型的服务网格外,还有其它项目,例如Skupper等,它们证实了将网络能力放入外部运行时代理的趋势
Skupper 通过第 7 层虚拟网络解决了多集群通信的难题,并提供了高级路由及连接能力
但是,它没有将 Skupper 嵌入到业务服务运行时中,而是在每个 Kubernetes 名称空间中运行一个共享的 Sidecar 实例
状态 (Dapr)
状态的管理比较困难,因而应该将其委派给专门的存储软件和托管服务
缓存、工作流管理、单例、幂等、事务管理、 cron 作业触发器和状态化错误处理等都隶属状态管理范畴
对那些建立在云环境上的服务来讲,状态化工作流的管理是必备功能,例如 AWS 的 Step 函数、Azure 的 Durable 函数等
在容器化的部署中, CloudState 和 Dapr 都依赖 Sidecar 模型以提供分布式应用程序中状态化抽象更好的解耦
未来的发展趋势中,状态管理应该会通过一个专门的 Sidecar 应用来完成
绑定 (Knative)
微服务体系下,从应用程序中解耦分布式需求同样也会伴随着“绑定”
尽管,连接器、协议转换、消息转换、错误处理和安全相关的中间层都可以从应用中转移出来,但目前尚未实现,但 Knative 和 Dapr 等项目正朝着这个方向努力
Apache Camel-K 项目采用了另一种有趣的方法
它借助于一个智能的 Kubernetes Operator 利用来自 Kubernetes 和 Knative 附加的平台能力来构建应用程序运行时,而非在主应用程序周边运行一个 Sidecar 形式的代理
Operator 成了惟一的代理程序,它负责提供应用所需的各种分布式系统原语
不同之处在于,有些分布式原语添加到了应用程序运行时中,而有些则是在平台中实现(也可能包括 Sidecar)
未来的架构趋势
除了生命周期之外,现在我们已然可以直接使用网络监测、状态抽象、声明性事件以及端点绑定等功能,而 EIP(企业集成模式)则是该列表中的下一个元素
如果我们把不同领域进行创新的各种云原生项目进行叠加,那么最终将得到类似下图的组合形式
需要注意的是,上图只是用于说明,它有目的地选择了具有代表性的项目,并把它们映射为分布式原语的一种
实际上,我们不会同时使用所有这些项目,因为它们中的一些是重叠的,并且工作负载模型也并 不兼容
构建分布式应用是一项非常复杂的工程,需要解决四个维度的问题:
解决应用程序生命周期的管理:部署、发布、上线、运行、下线等
解决各个分布式应用在不可靠网络上可靠通信的问题
解决状态的问题,状态管理
解决绑定的问题
早期的 SOA、ESB 这样的框架,spring-cloud 这样的代表产品无非都是解决这些维度的问题,但也仅解决上面部分维度问题而非全部。即便如此也能让世人趋之若鹜,因为当时能够满足的产品实在太少了。迄今为止,如果对微服务的运行逻辑所面临的需求加以明确后,可能出现如今这样一个局面:
Kubernetes 负责解决应用程序生命周期管理的问题:部署,运行,健康状态检测,滚动更新等
高级网络功能:分布式服务之间通信的流量治理问题,早期建构在 spring-cloud 之上,现代则由服务网格管理;
状态管理问题:应用如何保存状态?从灾难中恢复,如何将自己的状态通知给其他组件等等,目前有 dapr(微软主导研发和开源);
绑定:应用路由的问题。
当一个应用的规模在 Kubernetes 之下编排和运行时,比如基于 deployment 的编排,这个应用是不能缩容至零的,因为 service 不支持后端 Pod 个数为 0 个,它仅支持把客户端的请求访问路由到上游端点正常运行且是 ready 状态,才能返回给客户端。(而不是 deployment 不支持至 0)如果缩容至 0,service 就没有任何可用的后端端点,客户端请求直接被返回错误信息。而 knative 可解决此类问题,它允许应用缩容至 0,一旦前端服务接收到请求后,可暂存下来,而后通知扩展程序比如 HPA,或者 knative 的 KPA,将 Pod 扩容至其他数量,再把请求接入。这可以算得上是请求的路由机制。此时,可以把特定请求转变格式后交给后端服务,这就是绑定。比如像 MySQL 中的连接器,协议适配。knative 是其中一种代表性的产品。
如果能把上述结合起来作为运行时同时配置的话,类似运行铠甲,此时业务人员才能真正把精力集中到业务功能本身。
虽然说 istio 出现后声称业务人员可以集中到业务本身, 但依然要解决如编码问题:服务之间协议适配的问题(服务之间的 rpc,restful 适配),服务通信编码等,当出现 status,bangding 出现后就无需对此做过多关注了,理解好遵循好规范即可。
版权声明: 本文为 InfoQ 作者【蝉翼2u】的原创文章。
原文链接:【http://xie.infoq.cn/article/c10f7031e462532ba3ad69fad】。文章转载请联系作者。
评论