diss了,因为我不懂Istio的架构原理。转载本文请联系石山架构笔记公众号。一开始,在云环境中,技术栈可谓是五花八门,通过不同的技术产生不同的应用。如何将这些异构的服务或应用有机地连接起来,成为服务治理的一个重大问题。在此背景下,Istio架构为此类应用场景提供了服务治理功能。Istio提供了流量治理、策略、遥测和访问安全等功能,时至今日仍被津津乐道。今天围绕Istio架构的实现原理介绍如下内容:为什么选择Istio什么是IstioIstio架构原理Istio服务治理功能介绍服务/应用拆分。拆分后的服务/应用可以分布式部署,应对高并发带来的系统压力,处理复杂的业务逻辑。这样的做法会造成系统中存在大量独立的服务或应用,分布在不同的进程和主机上,相互调用时会出现服务治理的问题。微服务就是一个典型的例子。微服务的开发和运维对程序员来说是一个挑战。分而治之的思想使得业务本身的规模和复杂性不减反增。在分布式系统中,网络可靠性、通信安全、网络延迟、网络拓扑变化等都成为人们关注的焦点。同时,服务注册、服务发现、负载均衡、服务间通信、分布式调用链跟踪等都是重要解决的问题。为了解决这个问题,将服务治理部分抽象成一个公共库,让所有的微服务都可以使用这个公共库。如图1所示,在Node1和Node2上分别使用了Service1和Service2这两个服务。它们各自针对自己的业务逻辑有相应的服务管理SDK。服务管理的服务发现和服务管理都是通过这个SDK完成的。服务注册等功能。图1.将服务治理的逻辑抽象为公共图书馆。如果将图1中的SDK包含在开发框架中(例如:SpringCloud),使用该开发框架后,将具备服务治理的能力。SDK模型虽然解耦了业务逻辑和服务治理,但由于是在开发框架中,业务逻辑需要和服务治理SDK一起编译。发布后,业务逻辑和服务治理代码合一运行。这会导致业务代码和SDK基于同一种语言,无法兼容其他语言开发的服务。同时,当服务治理升级时,即使业务逻辑没有变化,也需要升级整个服务。如果说图1的模型,SDK和业务代码在同一个进程,所以需要解耦,将服务治理和业务代码分开。如图2所示,红色部分替换了原来的SDK,使用的是Sidecar模式。在这种形式下,业务逻辑和服务治理在不同的流程中运行。图2.Sidecar解耦业务逻辑和服务治理Sidecar模式使得两者的代码和运行解耦。如图3所示,业务逻辑就像一个绿色的方框,右边的蓝色方框是Istio提供的Sidecar(边车),也就是通过这个Sidecar,链接到其他服务的Sidecar网络,从而实现服务。之间的沟通。这样,业务逻辑可以用不同的语言开发,升级之间相互独立。其他服务管理工作,如服务注册、服务发现、负载均衡、通信等,均由Sidecar完成。图3.Istio的Sidecar模型这里,我们将从业务逻辑和服务治理的角度,对使用Istio前后的微服务进行区分,从以下三个维度进行比较。业务逻辑和服务治理在使用Istio之前使用Istio然后运行流程都在同一个进程都在不同的流程技术栈都使用相同的技术栈都使用不同的技术栈服务升级两个同时升级两个分别升级因此使用Istio架构后,业务逻辑和服务治理将在运行流程、技术栈和服务升级三个方面完全解耦,通过Sidecar模型打造分布式系统的最佳实践。接下来我们看看Istio包括哪些内容。什么是Istio?众所周知,Istio是以ServiceMesh的形式进行服务治理的开放平台。这里的服务“治理”并不局限于“微服务”,可以扩展到任何服务。只要有服务或应用,它们之间的访问,以及服务和应用的管理,都可以使用Istio。如图4所示,在Istio的官方介绍中,其功能包括:连接(Connect)、安全(Secure)、控制(Control)和观察(Observe)。图4.Istio官方功能介绍将以上四个功能总结如下:连接:通过流量规则控制服务之间的流量和调用,实现负载均衡、熔断、故障注入、重试、重定向等功能。安全:提供认证机制、通道加密、服务访问授权等安全能力,增强访问安全性。控制:通过动态可插拔、可扩展的策略实现访问控制、限速、配额管理、服务计费等能力。观察:获取服务运行数据和输出,提供调用链监控和日志收集能力。在微服务时代,Kubernetes提供服务部署、升级、扩容等运维管理能力。但在服务的熔断、限流、动态路由、调用链跟踪等服务治理方面还存在不足。Istio作为服务治理的架构恰好弥补了Kubernetes在这一点上的不足,成为Kubernetes的好搭档。既然Istio已经被吹上天了,那我们就来看看Istio在服务接入的过程中都实现了什么。如图5所示,有两个Pod容器,分别存储了两个不同的服务,ServiceA和ServiceB。其中,ServiceA是Java开发的,ServiceB是Python开发的。服务A通过服务发现获取服务B的服务实例列表。如果ServiceB有多个水平扩展(ServiceB集群),需要根据负载均衡策略选择具体的ServiceB实例。为了保证安全,服务之间的请求和响应需要开启相互认证和通道加密。一段时间内,ServiceA在访问ServiceB时不断出错,需要进行熔断处理,停止对ServiceB的请求。根据ServiceB的处理能力,设置最大连接请求数、访问超时时间和其他参数,以保护其服务。如果需要,可以将服务A向服务B发起的请求重定向到其他服务。如果ServiceB有新旧版本两个版本,灰度发布时,将ServiceA请求的部分流量(20%)导入到新版本ServiceB中,导入其他流量(80%)%)到旧版本的服务B。随着B服务新版本的逐步稳定,剩余80%的流量将导入新版本。跟踪服务A调用服务B的调用链,为提高服务间调用效率提供数据依据。图5Istio服务治理的功能Istio架构原理上一节介绍了什么是Istio,是对其功能的描述,看起来比较抽象。这里从Istio的工作机制和架构上做进一步说明。如图4所示,Istio的整个架构可以分为控制平面和数据平面两部分。控制面主要包括Pilot、Mixer、Galley、Citadel等组件;数据平面由随服务部署的代理Envoy组成,Envoy为服务完成服务。治理逻辑。这里我们根据Istio的运行机制,给每一步都打上序号,并一一介绍。序号不表示执行顺序,只是为了方便标注和说明功能。数据平面中的交互由带箭头的实线表示,数据平面和控制平面之间的交互由虚线标记。它的资源是通过Kubernetes部署的。ServiceA和ServiceB通过Pod容器分别部署在Node1和Node2上。ServiceB有两个版本V1和V2,分别部署在Node2的两个Pod中。通过描述服务A调用服务B的不同版本以及外部请求访问服务A的过程来描述Istio各个组件的工作流程图6.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中,从ServiceA出来的流量(Outbound)会被ServiceA端的Envoy拦截,当流量作为入站流量(Inbound)到达ServiceB时,会被ServiceB端的Envoy拦截。这里拦截的目的是为了控制流量,尤其是在高并发的情况下,会限制某些服务的流量。4.负载均衡服务A作为请求的发起者,Envoy根据配置的负载均衡策略选择一个服务实例,并连接到对应的实例地址。这些负载均衡策略是通过RANDOM、ROUND_ROBIN等配置文件的形式将Pilot发送给Envoy来实现的。访问服务B,图4中的V2版本,发现该版本有多个服务B。这时候就需要使用负载均衡策略来访问其中一个服务B。5.流量治理Envoy从Pilot获取配置好的流量规则,在拦截入站流量和出站流量时执行治理逻辑。与流量拦截不同,其目的是访问同一服务的不同版本。ServiceA通过Envoy获取规则,根据规则将流量分发给ServiceB的V1或V2版本。6.访问安全在服务A和服务B之间建立双向认证和通道加密,并根据服务的身份进行授权管理。并且通过Pilot下发安全配置,在服务A和服务B对应的Envoy上加载证书和密钥,实现双向认证。证书和密钥由管理平面上的Citadel组件维护。7.ServiceTelemetry服务之间通信时,通信双方的Envoy会连接到管理面的Mixer组件上报访问数据。比如:监控指标、日志、调用链都可以通过这种方式收集。8、外部访问左下角有一个“外部请求访问”,作为网格外的请求访问网格内的服务A。所以在入口处有一个Envoy作为入口网关。外部服务通过Gateway访问服务A。如果需要负载均衡和流量管理策略,可以在这个Gateway的Envoy中设置。9.管理配置最后是管理平面的厨房组件。它不为数据平面提供服务,而是为控制平面上的其他组件提供支持。主要负责验证控制面配置信息格式和内容的正确性,并将配置信息提供给Pilot和Mixer组件。Istoio服务治理功能介绍通过以上Istio架构原理的介绍,我已经为大家传递了控制平面和数据平面的组件。限于篇幅,这里无法一一介绍。由于Istio的主要功能是服务治理,这里给大家介绍几个服务治理中经常用到的功能,也算是一窥究竟。服务路由服务路由在实际场景中比较常见。如图5所示,ServiceA按照不同的路由访问ServiceB、C、D:Test.com/ServiceB、Test.com/ServiceC、Test.com/ServiceD。图7.服务路由如“Istio架构原理”部分所述,Istio配置规则从Pilot传输到Envoy以执行。它的配置文件格式与Kubernetes基本相似。图5特有的配置文件将使用VirtualService类型的配置。VirtualService定义特定目标服务的流量规则。它代表一个虚拟服务,其作用是将满足条件的流量转发给相应的服务(一个或多个)。如CodeSegment1所示,在Istio配置文件中,红色数字说明如下:定义VirtualService的类型inkind定义要访问的入口服务名称,其中ServiceA作为入口服务,通过其中访问以下三个服务。在hosts中定义host的url地址作为路由的一部分,因为这里的地址访问是以“Test.com/ServiceB”的方式访问的,所以定义为“Test.com”。这里对http请求进行路由,所以在http下match(匹配)中的uri中定义了前缀。显然,如果要访问“Test.com/ServiceB”,这里的前缀需要定义为“/ServiceB”。其实就是具体服务路由的地址。最后,为uri地址制定对应的路由,在目的地(target)的主机中定义服务的名称:“ServiceB”。ServiceC和D的定义与B基本相同,这里不再赘述。CodeSegment1TrafficSegmentation上面介绍了简单路由的规则设置。如果访问内容较多,需要分流,或者需要按比例分流,则需要修改配置文件的内容。如图6所示,ServiceA需要访问ServiceB的三个不同版本V1、V2、V3,当URI为“Test.com/status”和“Test.com/data”时,ServiceB的V2和V3版本会请求ServiceB,导入流量分别为20%和80%(红线部分)。其他URI路由到ServiceB的V1版本(绿线标记的部分)。图8.流量切分照例看配置文件中各个配置项的内容,按照红色数字描述如下:在http-match部分,用于匹配URI。有两个前缀:“data”和“status”,当请求URI满足这两个条件之一时,进入下面的路由选择。路由选择路由的目的地对应ServiceB服务,子集:V2为V2version.Weight设置为20,表示有20%的流量流入ServiceB的V2版本,路由选择路由的目的地对应ServiceB服务,subset:V3为V3版本Weight设置为80,也就是说80%的流量都流向V3版本的ServiceB,最后如果上面两个前缀不匹配,流量就会流向V1版本的ServiceBCodeSegment2LoadBalancing负载均衡是一个经常出现的功能服务治理中遇到的,我们看看在Istio中是如何实现的,如图7,ServiceA会访问ServiceBV2的集群和ServiceBV1的集群,对于同一个服务的两个不同版本的集群,两个不同的需要使用负载均衡策略,即ROUND_ROBIN和RANDOM。图9.负载均衡看完了负载均衡的需求,我们来看看如何通过配置文件来实现。在介绍配置文件之前,先介绍一下DestinationRule的规则说明。如果VirtualService是一个虚拟Service,它的描述是“哪个服务处理从该服务流出的请求”,那么DestinationRule描述的是“到达该服务后如何处理传入的请求”,从字面上理解就是目的地规则,如果落在负载均衡的例子上,即流量到达两个版本的ServiceB(V1,V2)后如何访问。如代码段3所示,红色数字顺序如下:规则配置定义为DestinationRule,表示处理服务传入的请求。这里请求流入的服务是ServiceB,它存在两个版本,每个版本以集群的形式存在。对于ServiceBV2版本,在trafficPolicy(流量规则)的loadBalancer(负载均衡)中使用了ROUND_ROBIN策略。同样,对于ServiceB版本V1的情况,在trafficPolicy(流量规则)的loadBalancer(负载均衡)中使用了RANDOM策略。CodeSegment3上面Istio服务治理的功能介绍主要围绕服务之间的关系展开。服务之间的关系是通过调整配置文件中的节点数据来定义的。该方法对于开发者理解其工作原理来说有些抽象。为了理清服务之间的关系并对其进行有效管理,Istio提供了一个可视化的服务网格工具——Kiali,它提供了服务拓扑图、全链路跟踪、指标遥测、配置验证、健康检查等功能。视觉界面。这里重点介绍服务拓扑图的功能。限于篇幅,这里不介绍Kiali的安装。有兴趣的同学可以去Istio官网查看。如图8所示,登录Kiali后,可以看到它的Overview界面,里面包含了网格中所有命名空间下的服务。图10.Kiali概览界面如果想查看对应的服务,例如:Bookinfo,可以点击Bookinfo命名空间卡片,显示内容如图9所示。这里显示了该命名空间下的服务调用。注意上图红框中的部分:GraphType,这里可以选择服务展示的类型,也就是以不同的形式展示服务之间的关系。当前有四个选项:App、VersionedApp、Workload和Service。图11.Bookinfo命名空间下的服务关系图。选择App类型会将同一个应用的所有版本聚合到一个点,如图10所示。来自网格外部的请求通过istio-ingressgateway调用productpage服务,productpage将单独调用该服务。详情服务和评论服务。其中reviews会依次调用ratingsservice和mongedb。App类型的服务关系展示,简洁的描述了服务之间的依赖(调用)关系,不涉及服务的具体版本。图12.App类型调用VersionedApp类型将根据App类型显示每个服务的版本。如图11所示,可以看出productpage服务只有一个版本v1,而reviews服务有v1、v2、v3三个版本,ratings服务有两个版本。这种方法的现实使服务调用的版本更加清晰。图13.VersionedApp类型的Workload类型以VersionedApp类型为基础,对各个服务的工作负载进行显示转换。如图12所示,将每个服务的版本作为一个工作负载,循环展示。实际上,每个循环工作负载也是实际调用中的一个实体。图14.Workload类型以Service类型结尾,如图13所示,它为网格中的每个服务生成一个节点,但不包括所有应用程序和工作负载。图15.服务类型总结本文从服务治理出发,阐述了为什么需要Istio在分布式和微服务环境下提供服务治理功能。Istio可以将业务逻辑与服务治理SDK解耦,可以支持不同技术开发的分布式服务/应用的服务治理。同时指出Istio包括连接(Connect)、安全(Secure)、控制(Control)和观察(Observe)等功能。以及在这些功能的支持下,Istio的基本架构是如何工作的。通过架构原理上的九个步骤,梳理了控制面Pilot、Mixer、Galley、Citadel,数据面Envoy的工作流程。最后介绍了常用的服务治理功能:服务路由、流量切分、负载均衡。
