1

不懂Istio 架构原理,我被同事Diss了。

 3 years ago
source link: https://mp.weixin.qq.com/s?__biz=MzU0OTk3ODQ3Ng%3D%3D&%3Bmid=2247493784&%3Bidx=1&%3Bsn=048dbd09ca458ae63cd33a043bf63d68
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

m2u67z2.jpg!mobile

我的新课 《C2C 电商系统微服务架构120天实战训练营》 在公众号 儒猿技术窝 上线了,感兴趣的同学,可以长按扫描下方二维码了解课程详情:

课程大纲请参见文末

YBrIfiJ.png!mobile

开篇 

在云环境下,技术栈可谓是多种多样,通过不同的技术生成不同的应用。如何能将这些异构的服务或者应用有机地串联起来,成为了服务治理的重大课题,在这样的大背景下 Istio架构为这样应用场景提供了 服务治理的功能, Istio提供的流量治理、策略、遥测、访问安全等功能至今都被人津津乐道。

今天就围绕Istio架构的实现原理为大家介绍如下内容:

  • 为什么选择 Istio

  • 什么是 Istio

  • Istio架构原理

  • Istio服务治理功能介绍

为什么选择Istio 

随着业务的复杂度提高,为了应对高并发、大流量,系统架构对服务/应用进行拆分。拆分以后的服务/应用可以进行分布式部署,来应对高并发带来的系统压力以及处理复杂的业务逻辑。

这样的做法会造成系统中存在大量独立的服务或者应用,它们分布在不同的进程、主机上面,在它们之间互相调用的时候就存在服务治理的问题。 微服务就是一个典型的例子,微服务的开发和运维对程序员来说是一个挑战。

分而治之的思想使得业务本身的规模和复杂度不降反增。

在分布式系统中,网络可靠性、通信安全、网络时延、网络拓扑变化等都成了关注的焦点,同时服务注册、服务发现、负载均衡、服务间通讯、分布式调用链追踪都是要解决的问题。

为了解决这个问题,把服务治理部分抽象成公共库,让所有微服务都使用这个公共库。如图1所示,在Node 1 和 Node 2 上分别用Service 1 和Service 2两个服务,它们分别针对自己的业务逻辑都有对应的服务治理的SDK,通过这个SDK完成服务治理的服务发现、服务注册等功能。

ZrIzuqQ.png!mobile

图1

将服务治理的逻辑抽象成公共库

如果将图1中的SDK包含到开发框架中(例如:Spring Cloud),当运用这种开发框架后就拥有服务治理的能力了。SDK的模式虽然解耦了业务逻辑和服务治理,由于在一个开发框架中,因此业务逻辑需要和 服务治理的SDK一起编译,发布以后业务逻辑和服务治理的代码在一个进程中运行。这会导致业务代码和 SDK 基于同一种语言,无法兼容其他语言开发的服务。同时,在服务治理升级时,需要升级整个服务,即使业务逻辑没有改变。如果说图1的模式,SDK和业务代码在同一进程,因此需要对其进行解耦,把服务治理从业务代码中剥离出来。如图2所示,红色的部分代替了原来的SDK,其使用了Sidecar模式。在这种形态下,业务逻辑和服务治理在独立的进程下运行。

3EzMren.png!mobile

图2 

Sidecar解耦业务逻辑和服务治理

Sidecar的模式使两者代码和运行无耦合。如图3所示,业务逻辑就好像绿色的方块,再其右边的蓝色方块就是Istio提供的Sidecar(边车),也就是通过这个Sidecar与网络中其他服务的Sidecar进行链接,从而实现服务之间的通信。

这样业务逻辑可以使用不同的语言进行开发,升级也相互独立,而其他的服务治理的工作,例如:服务注册、服务发现、负载均衡、通讯等都由Sidecar来完成。

QriquiQ.png!mobile

图3 

Istio的Sidecar模式

这里通过业务逻辑与服务治理的角度,将使用Istio之前和之后的微服务做区分,从以下三个维度进行对比。

业务逻辑与服务治理

使用Istio之前

使用Istio之后

运行进程

两者在同一进程内

两者在不同的进程

技术栈

两者使用相同技术栈

两者使用不同技术栈

服务升级

两者同时升级

两者分别升级

因此在使用Istio架构以后,会将业务逻辑与服务治理在运行进程、技术栈和服务升级三个方面进行完全解耦,通过Sidecar模式打造分布式系统的最佳实践,接下来就来看看Istio包括哪些内容。

什么是Istio 

众所周知 Istio 是一个 Service Mesh 形态的,用于服务治理的开放平台。这里的服务 “治理”不仅限于“微服务”,可以推广到任何服务。只要存在服务或者应用,在它们之间存在访问,也存在对服务与应用的管理,都可以使用到 Istio

如图 4 所示,在 Istio 官方介绍中,其功能包括:连接( Connect )、安全( Secure)、控制(Control)和观察(Observe)

UJziyy2.png!mobile

图4 

Istio 官方功能介绍

将上面四项功能总结如下:

  • 连接: 通过流量规则控制服务间的流量和调用,实现负载均衡、熔断、故障注入、重试、重定向等功能。

  • 安全: 提供认证机制、通道加密、服务访问授权等安全能力,增强访问的安全性。

  • 控制: 通过可动态插拔、可扩展的策略实现访问控制、速率限制、配额管理、服务计费等能力。

  • 观察:获取服务运行数据和输出,提供调用链监控和日志收集能力。

在微服务时代, Kubernetes 提供了服务的部署、升级、扩容等运行管理能力,但在服务治理方面,如服务的熔断、限流、动态路由、调用链追踪显得能力不足。

Istio作为服务治理的架构刚好在这一点上弥补了Kubernetes的不足,成为了Kubernetes的好搭档。

既然把 Istio 吹上了天,就来看看 Istio 在服务访问的过程中 有哪些建树吧。如图 5 所示,有两个 Pod容器,分别存放两个不同的服务,Service A和Service B。其中Service A Java进行开发,而Service B由Python进行开发。

  • Service A通过 服务发现获取 Service B 服务实例列表,如果 Service B存在多个水平扩展(Service B集群),还需要根 据负载均衡策略选择一个具体的 Service B 实例。

  • 为了保证安全性,服务之间的请求和响应需要启用双向认证和通道加密。

  • 在一段时间内, Service A在访问Service B不断出现错误,需要进行熔断处理,停止对Service B的请求动作。

  • 针对 Service B的处理能力, 设置最大连接的请求数、访问超时等参数,从而对其进行服务保护。

  • 如果有需要可以将 Service A对Service B发起的请求重定向到其他服务上。

  • 如果 Service B  有新、老两个版本,在执行灰度发布的时候,将 Service A请求的部分流量(20% )导入到 Service B的新版本中,其他的流量(80% )导入到 Service B的老版本上。随着Service B 新版本的逐步稳定,再将剩下的 80% 流量导入到新版本上。

  • Service A调用 Service B  的调用链进行追踪,为提升服务之间的调用效率提供数据依据。

yuINbyv.png!mobile

图5 

Istio 针对服务治理的功能

Istio架构原理 

在上一节中介绍了什么是Istio,是针对其功能进行的描述,看上去比较抽象,这里从Istio的工作机制和架构进一步进行描述。如图4所示,Istio整个架构可以分为控制面和数据面两部分,控制面主要包括Pilot、Mixer、Galley、Citadel等组件;数据面由伴随服务部署的代理Envoy组成,Envoy针对服务完成服务治理的逻辑。这里我们按照Istio的运行机制将每个步骤标上序号,逐个介绍。序号并不表示执行的顺序,只是为了方便标注,为的是讲解功能。在数据面中的交互通过带箭头的实线表示,数据面和控制面的交互通过虚线标注。其资源是通过Kubernetes进行部署的,在Node 1 和Node 2 通过Pod容器部署了服务A和服务B,其中服务B有两个版本V1 和V2,分别部署在Node 2 的两个Pod中。通过描述服务A调用服务B不同的版本,以及外部请求访问服务A的过程给大家讲述Istio各个组件的工作流程。

Z7Rnuir.png!mobile

图4 

Istio的控制面和数据面

1. 自动注入 

由于 Istio使用了Sidecar代理的模式,将业务逻辑和服务治理进行了解耦。因此在 Kubernetes 场景下创建 Pod 时,同时创建 Sidecar 容器。实际上是注入并创建了 istio-proxy和istio-init两个容器。其中istio-proxy包含了Pilot-agent和Envoy两个进程。Envoy作为处理服务之间请求流量的进程在服务调用中起到重要的作用,因此在图4中特别标注出来。

2.服务发现 

在注入Envoy以后,假设服务A调用服务B,因此需要通过Envoy向服务B发起请求。服务A如何得知服务B的访问地址能,就需要通过服务发现的方式完成。此时,Envoy 需要调用管理面组件 Pilot 的服务发现接口,获取服务B的实例列表。Pilot 直接从运行平台提取数据并将其转换成 Istio 的服务发现模型,这种服务发现的方式还支持Kubernetes、Consul等平台。

3.流量拦截  

当服务A得知服务B的地址以后,就会通过服务A向Envoy发送请求流量。发出的流量成为Outbound,在服务B端会接收到这个流量成为Inbound。图4中从服务A流出的流量(Outbound)会被服务A侧的 Envoy拦截,而当流量作为流入的流量(Inbound)到达服务B时,会被服务B侧的Envoy拦截。这里拦截的目的是对流量进行控制,特别是在高并发的情况下会对某些服务进行流量的限制。

4. 负载均衡

服务A作为请求的发起方,Envoy根据配置的负载均衡策略选择服务实例,并连接对应的实例地址。这些负载均衡的策略是通过Pilot以配置文件的形式下发到Envoy上实现的,具体策略如RANDOM和ROUND_ROBIN。图4中访问服务B,V2版本的时候,发现该版本有多个服务B,此时就需要使用负载均衡策略访问其中某个服务B了。

5. 流量治理 

Envoy 从 Pilot 中获取配置的流量规则,在拦截到 Inbound 流量和Outbound 流量时执行治理逻辑。和流量拦截不同的是,其目的是为了访问同一服务的不同版本。服务A通过Envoy获取规则,通过规则判断将流量分发到服务B的V1或V2版本。

6. 访问安全 

在服务A和服务B之间建立双向认证和通道加密,并基于服务的身份进行授权管理。同样由Pilot下发安全配置,在服务A和服务B对应的Envoy上加载证书和密钥来实现双向认证,证书和密钥由管理面的Citadel组件维护。

7. 服务遥测  

在服务间通信时,通信双方的Envoy会连接管理面的Mixer组件上报访问数据。例如:监控指标、日志和调用链都可以通过这种方式进行收集。

7. 外部访问  

在左下角有个“外部请求访问”,其作为这个网格之外的请求访问网格内的服务A。因此在入口处有一个Envoy扮演入口网关的角色。外部服务通过Gateway访问服务A。如果需要负载均衡以及流量治理的策略,都在这个Gateway的Envoy进行设置。

9.  管理配置  

最后是管理面的galley组件。它不面向数据面提供服务,而是在控制面上向其他组件提供支持。主要负责验证控制面的配置信息格式和内容的正确性,并将配置信息提供给 Pilot和 Mixer组件使用。

Istoio服务治理功能介绍 

通过上面Istio架构原理的介绍,把控制面和数据面的组件给大家过了一遍。由于篇幅问题不能在这里逐个展开介绍,由于 Istio 的主要功能是服务治理,这里选取几个服务治理中经常使用的功能给大家介绍,也算是窥豹一斑吧。

服务路由

服务路由在实际场景中比较常见,如图 5 所示 Service   A 根据不同的路由 :Test .com/ServiceB,  Test .com/ServiceC , Test .com/ServiceD ,分别访问 Service   B C D

iYB3A3A.png!mobile

5  

服务路由

正如在Istio 架构原理”章节中提到的, Istio 配置规则从 Pilot 发起传送到 Envoy 上执行。其配置文件格式基本与 Kubernetes 相似。具体到图 5 的配置文件会使用到 VirtualService 类型的配置。

VirtualService 定义了对特定目标服务的流量规则。它在表示一个虚拟服务,功能是将满足条件的流量转发到对应的服务(一个或者多个)。

如代码段 1 所示,在 Istio 的配置文件中 按照红色数字描述如下

  1. kind中定义VirtualService的类型

  2. 定义要访问的入口服务的名称,这里 ServiceA作为入口服务,通过它访问后面的三个服务。

  3. hosts中定义主机的url地址作为路由的一部分,因为这里的地址访问按照“Test.com/ServiceB”的方式进行访问,因此定义为“Test.com”。

  4. 这里针对 http请求进行路由,因此在http下面的match(匹配)中的uri中定义prefix,显然如果要访问“Test.com/ServiceB”,这里的prefix需要定义为“/ServiceB”。实际上就是具体服务路由的地址。

  5. 最后,针对 uri地址制定对应的route,在destination(目标)的host中定义服务的名称:“ServiceB”。ServiceC、D的定义和B的基本一致,不再赘述。

yaue2uB.png!mobile

代码段1  

流量切分

上面描述了简单路由的规则设置,如果遇到需要更具访问内容进行流量切分的情况,或者需要按照比例切分流量的情况配置文件的内容就需要修改了。如图 6   所示, Service   A 要访问 Service   B 的三个不同版本 V 1 V 2 V 3 。当 URI ”Test.com/status” ”Test.com/ data 的时候会请求 Service   B V 2 V 3 版本,导入的流量分别是 2 0% 8 0% (红线标注的部分)。其他 URI 路由到 Service   B V 1 版本(绿线标注的部分)。

Z3ummeN.png!mobile

图6   流量切分

照旧看看配置文件的每个配置项的内容,按照红色数字描述如下:

  1. http - match 的部分用来匹配 URI ,这里有两个 prefix   分别是:data ”和“ status ”,当请求 URI 满足这个两个条件中的一个时进入下面的路由选择。

  2. 在路由选择 route destination 中对应了 ServiceB 服务的, subset V 2 也就是 V 2 版本。 W eight 设置是 2 0 ,意思是 2 0% 的流量,流入 ServiceB V 2 版本。

  3. 在路由选择 route destination 中对应了 ServiceB 服务的, subset V 3 也就是 V 3 版本。 W eight 设置是 80 ,意思是 80% 的流量,流入 ServiceB V 3 版本。

  4. 最后,如果在没有命中上述两个 prefix 的情况下,流量会流入 ServiceB V 1 版本。

zuiuay.png!mobile

代码段 2

负载均衡

负载均衡是服务治理中经常遇到的功能,来看看在 Istio 中是如何实现的。如图 7   所示, Service   A 会访问 Service   B   V 2 版本的集群以及 Service   B   V 1 版本的集群。针对同一个服务的两个不同版本的集群,需要使用两种不同的负载均衡策略,分别是 ROUND_ROBIN RANDOM

A32uYzB.png!mobile

7  

负载均衡

在看完负载均衡的需求之后再来看看如何通过配置文件实现它,在介绍配置文件之前先来介绍一下 DestinationRule 的规则描述。

如果说 VirtualService 是一个虚拟 Service 其描述的 内容是 “从服务流出的请求 被哪个服务处理 ”, 那么  DestinationRule 描述的是 “流入的 请求到达 服务之后如何处理 ,从字面意思理解就是 目标规则, 如果落到负载均衡的这个例子上来说,也就是流量到达 Service   B 的两个版本( V 1 V 2 )以后如何进行访问。

如代码段 3 所示,按照红色数字的顺序如下:

  1. 规则配置定义为 DestinationRule ,表示处理服务流入的请求。

  2. 这里请求流入的服务是 Service   B ,其从在两个版本,每个版本都是以集群的方式存在的。

  3. 针对 Service   B   版本 V 2 的情况,在 trafficPolicy (流量规则)的 loadBalancer (负载均衡)中使用了 ROUND _ROBIN 的策略。

  4. 同样,针对 Service   B   版本 V 1   的情况,在 trafficPolicy (流量规则)的 loadBalancer (负载均衡)中使用了 RANDOM 的策略。

77n6vuA.png!mobile

代码段3

上面Istio服务治理的功能介绍,主要围绕服务之间的关系展开的,通过配置文件中节点数据的调整定义服务之间的关系,获取这种方式对于开发者理解其工作原理有些抽象,为了方便理清服务之间的关系并且对其进行有效管理, Istio 提供了可视化的服务网格工具 -Kiali ,针对服务 拓扑图、全链路跟踪、指标遥测、配置校验、健康检查等功能提供可视化的界面。

这里着重介绍服务拓扑图 的功能,由于篇幅的关系这里不介绍Kiali的安装,有兴趣的同学可以去 Istio 的官网查看。如图 8   所示,登陆Kiali以后可以看到其 Overview 界面,其中包括网格里面所有命名空间的服务。

rMvymij.png!mobile

8  

Kiali   overview   界面

如果要查看对应的服务,例如: Bookinfo ,可以点击 Bookinfo 命名空间卡片, 显示如图9所示的内容。这里展示了该命名空间下服务的调用情况。注意看上方红色框出的部分: Graph   Type,这里可以选择服务显示的类型,也就是说通过不同形式展示服务之间的关系。目前有四种可以选择 App Versioned App Workload  以及  Service

iqymue2.png!mobile

9  

Bookinfo命名空间下的服务关系图

选择 App  类型会将同一应用的所有版本聚合 到单点上, 如图 1 0 所示,网格外部的请求通过 istio - ingressgateway 调用 productpage 服务, productpage 分别会调用 details 服务和 reviews 服务。其中 reviews 会依次调用 ratings 服务和 mongedb App 类型的服务关系展示,通过简洁的方式描述了服务之间的依赖(调用)关系,没有涉及到服务的具体版本。

2A7nUff.png!mobile

1

App   类型调用

Versioned App  类型会 App 类型的基础上,将每个服务的版本显示出来。如图 1 1 所示,可以看出 productpage 服务只有一个版本 v 1 ,但是 reviews 服务有 v 1 v 2 v 3 三个版本, ratings 有两个版本。这种方式的现实让服务调用的版本更加清晰。

YBZj6rn.png!mobile

图11 

Versioned App 类型

Workload  类型 又在 Versioned App  类型 的基础上,针对每个服务的 workload 进行了显示上的转换。如图 1 2 所示,将每个服务的版本作为一个 workload ,通过圆形的方式显示,实际上每个圆形的 workload 在实际调用中也是一个实体。

a2MNRzF.png!mobile

图12 

Workload 类型

最后是 Service  类型 ,如图 1 3 所示,它为网格中的每个服务生成一个节点,但是会排除所有的应用和工作负载。

qMfuqum.png!mobile

图13 

Service 类型

总结 

本文从服务治理作为切入点,描述了在分布式、微服务的环境下为什么需要Istio提供服务治理的功能。Istio能够将业务逻辑与服务治理的SDK进行解耦,能够支持不同技术开发的分布式服务/应用的服务治理。同时指出Istio是包含的连接(Connect)、安全(Secure)、控制(Control)和观察(Observe)等功能。以及在这些功能的支撑下,Istio的基本架构是如何工作的。在架构原理中通过九个步骤,将控制面的Pilot、Mixer、Galley和Citadel,以及数据面的Envoy的工作流程给大家梳理了一遍。最后针对使用频度较高的服务治理功能:服务路由、流量切分、负载均衡进行了展开描述

征 稿

有酬投稿

愿意技术分享的朋友,欢迎投稿,每篇文章提供 800 ~ 1000 元的稿酬,投稿请扫描下方二维码, 添加微信 :jeversoncui

AZZVzqe.png!mobile

iQVbE3a.jpg!mobile

V3U3Ezv.jpg!mobile


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK