第14章 云原生架构设计理论与实践
定义不唯一。从技术的角度,云原生架构是基于云原生技术的一组架构原则和设计模式的集合,旨在将云应用中的非业务代码部分进行最大化的剥离,从而让云设施接管应用中原有的大量非功能特性(如弹性、韧性、安全、可观测性、灰度等),使业务不再有非功能性业务中断困扰的同时,具备轻量、敏捷、高度自动化的特点。基础设施即服务(IaaS)、平台即服务(PaaS)和软件即服务(SaaS)。业务代码、三方软件、处理非功能特性
我们的目的是啥,最大程度的复用资源,这样提升效率和生产力,降本增效啊,云原生的是在云上的,基于云的环境和软件,这样复用程度更高了,而且云上还有一些很牛的价值比如云计算等等。
14.1 云原生架构产生背景
14.2 云原生架构内涵
14.2.1 云原生架构定义
定义不唯一。
- "业务代码”指实现业务逻辑的代码;
- “三方软件”是业务代码中依赖的所有三方库,包括业务库和基础库;
- “处理非功能性的代码”指实现高可用、安全、可观测性等非功能性能力的代码。
1.代码结构发生巨大变化
目前的开发基本都需要考虑文件、网络、线程等等这些元素,这样可充分利用单机资源的好长,但同时也带来了分布式编程的复杂性,大量的问题都涌现出来(分布式环境种网络调用问题、高可用问题、CPU争用问题、分布式存储等等)。
在云环境种这些就考虑的元素升级成服务,在需要的直接调用即可。
2.非功能性特性大量委托
开发的时候,还有考虑一些非功能特性,比如相应时间,容灾能力,安全性,易于运维等等,这些在开发的时候需要加上大量代码来实现。
在云环境中,这些非功能特性尽最大限度的剥离,让云环境承载这些,开发只需要专注业务代码。
3.高度自动化的软件交付
软件开发完成需要部署,单个服务器的很容易,但是集群的这种有成千上万的节点的部署起来就很痛苦,而且先部署哪些,后部署哪些都是有顺序的,云环境提供自动化部署策略,自动部署,按照设定的规则部署等等。
14.2.2 云原生架构原则
云原生架构作为一种架构 ,也是遵循一些架构原则的。
1.服务化原则
2.弹性原则
3.可观测原则
单机软件可调试调试所有功能,根据日志打印、数据变化等等各种手段很简单的分析出问题原因影响了哪些数据等等,但是在云上分布式环境下需要对多个主机的信息关联才能明确问题原因,影响了哪些数据哪些用户等等,这时候就需要系统具备更强大的可观测能力了(这些都要求系统具备更强的可观测能力。可观测性与监控、业务探活、APM等系统提供的能力)。
比如主动通过日志、链路跟踪和度量等手段,使得一次点击背后的多次服务调用的耗时、返回值和参数都清晰可见,甚至可以下钻到每次三方软件调用、SQL请求、节点拓扑、网络响应等,
4.韧性原则
5.所有过程自动化原则
大量使用第三方组件,降低分布式复杂性和提升迭代速度的同时,因为整体增大了软件技术栈的复杂度和组件规模,所以不可避免地带来了软件交付的复杂性。
6.零信任原则
7.架构持续演进原则
14.2.3 主要架构模式
云原生架构有很多模式,以下是主要有价值的。
1.服务化架构模式
这是标准的云原生架构模式。要求以应用模块为颗粒度划分一个软件,以接口契约(如IDL)定义批次业务关系,以标准协议(如HTTP、gRPC等)确保彼此的互联互通,结合DDD(领域模型驱动)、TDD(测试驱动开发)、容器化部署提升每个接口的代码质量和迭代速度。
典型模式:微服务和小服务模式。
小服务:一组关系密切的服务的组合,这组服务共享数据。适用于非常大型的软件系统,避免接口颗粒度太细导致过多的调用损耗和治理复杂度。
意义:
1.通过服务化架构,把代码模块关系和部署关系进行分离,每个接口可以部署不同数量的实例,单独扩缩容,从而使得整体的部署更经济。
2.由于在进程级实现了模块的分离,每个接口可单独升级从而提升了整体的迭代效率。
需要匹配的能力:因为拆分导致要维护的模块数量增多,需要自动化能力和治理能力。
2. Mesh化架构模式
Mesh化架构是把中间件框架(如RPC、缓存、异步消息等)从业务进程中分离,让中间件SDK与业务代码进一步解耦,从而使中间件升级对业务进程没什么影响。
分离后,业务进程只保留clinet部分,它只负责与Mesh进程通信,原来的流量控制、安全等逻辑也由Mesh进程完成。当然实施了Mesh化后,大量分布式架构模式(熔断、限流、降级、重试、反压、隔仓....)都由Mesh进程完成,业务代码没第三方的软件包(主要是中间件);同时安全性(比如零信任框架能力)、按流量进行动态环境隔离、基于流量做冒烟/回归测试等等。
3.Serverless模式
- 如果应用是有状态的,由于Serverless的调度不会帮助应用做状态同步,因此云在进行调度时可能导致上下文丢失;
- 如果应用是长时间后台运行的密集型计算任务,会无法发挥Serverless的优势;
- 如果应用涉及频繁的外部I/O(网络或者存储,以及服务间调用),也因为繁重的I/O负担、时延大而不适合。
4.存储计算分离模式
C(一致性)、A(可用性)、P(分区容错性)
5.分布式事务模式
- (1)传统采用XA模式,虽然具备很强的一致性,但是性能差。
- (2)基于消息的最终一致性(BASE)通常有很高的性能,但是通用性有限。
- (3)TCC模式完全由应用层来控制事务,事务隔离性可控,也可以做到比较高效;但是对业务的侵入性非常强,设计开发维护等成本很高。
- (4)SAGA模式与TCC模式的优缺点类似但没有try这个阶段,而是每个正向事务都对应一个补偿事务,也是开发维护成本高。
- (5)开源项目SEATA的AT模式非常高性能且无代码开发工作量,且可以自动执行回滚操作,同时也存在一些使用场景限制。
https://blog.csdn.net/lxy1290439047/article/details/143556623
6.可观测架构
- 其中Logging提供多个级别(verbose/debug/warning/error/fatal)的详细信息跟踪,由应用开发者主动提供;
- Tracing提供一个请求从前端到后端的完整调用链路跟踪,对于分布式场景尤其有用;
- Metrics则提供对系统量化的多维度度量。
补充:服务级别指标(SLI) 服务级别目标(SLO)、服务级别协议(SLA)
7.事件驱动架构
事件驱动架构(EDA,Event Driven Architecture)本质上是一种应用/组件间的集成架构模式。
- (1)增强服务韧性:由于服务间是异步集成的,也就是下游的任何处理失败甚至宕机都不会被上游感知,自然也就不会对上游带来影响。
- (2)CQRS(Command Query Responsibility Segregation,命令查询职责分离):把对服务状态有影响的命令用事件来发起,而对服务状态没有影响的查询才使用同步调用的API接口;结合EDA中的EventSourcing机制可以用于维护数据变更的一致性,当需要重新构建服务状态时,把EDA中的事件重新“播放”一遍即可。
- (3)数据变化通知:在服务架构下,往往一个服务中的数据发生变化,另外的服务会感兴趣,比如用户订单完成后,积分服务、信用服务等都需要得到事件通知并更新用户积分和信用等级。
- (4)构建开放式接口:在EDA下,事件的提供者并不用关心有哪些订阅者,不像服务调用的场景——数据的产生者需要知道数据的消费者在哪里并调用它,因此保持了接口的开放性。
- (5)事件流处理:应用于大量事件流(而非离散事件)的数据分析场景,典型应用是基于Kafka的日志处理。
14.2.4 典型的云原生架构反模式
企业做云原生架构演进的时候需要充分考虑不同场景选择不同技术,否则会适得其反,反例:
1.庞大的单体应用
2.单体应用“硬拆”为微服务
- (1)小规模软件的服务拆分:软件规模不大,团队人数也少,但是为了微服务化,强行把耦合度高、代码量少的模块进行服务化拆分,一次性的发布需要拆分为多个模块分开发布和维护。
- (2)数据依赖:服务虽然拆分为多个,但是这些服务的数据是紧密耦合的,于是让这些服务共享数据库,导致数据的变化往往被扇出到多个服务中,造成服务间数据依赖。
- (3)性能降低:当耦合性很强的模块被拆分为多个微服务后,原来的本地调用变成了分布式调用,从而让响应时间变大了上千倍,导致整个服务链路性能急剧下降。
3.缺乏自动化能力的微服务
14.3 云原生架构相关技术
14.3.1 容器技术
1.容器技术的背景与价值

2.容器编排
- ●资源调度:根据应用请求的资源量CPU、Memory,或者GPU等设备资源,在集群中选择合适的节点来运行应用。
- ●应用部署与管理:支持应用的自动发布与应用的回滚,以及与应用相关的配置的管理;也可以自动化存储卷的编排,让存储卷与容器应用的生命周期相关联。
- ●自动修复:Kubernetes能监测这个集群中所有的宿主机,当宿主机或者OS出现故障,节点健康检查会自动进行应用迁移;K8s也支持应用的自愈,极大简化了运维管理的复杂性。
- ●服务发现与负载均衡:通过Service资源出现各种应用服务,结合DNS和多种负载均衡机制,支持容器化应用之间的相互通信。
- ●弹性伸缩:K8s可以监测业务上所承担的负载,如果这个业务本身的CPU利用率过高,或者响应时间过长,它可以对这个业务进行自动扩容。
- API Server,也就是常说的kube-API Server。它承担API 的网关职责,是用户请求及其他系统组件与集群交互的唯一入口。所有资源的创建、更新和删除都需要通过调用API Server 的API 接口来完成.
- 控制器是Kubernetes 集群的自动化管理控制中心,里面包含30 多个控制器,有Pod管理的(Replication 控制器、Deployment 控制器等)、有网络管理的(Endpoints 控制器、Service 控制器等)、有存储相关的(Attachdetach 控制器等),等等。在1.2.5 节的例子中,我们已经见识到部分控制器是如何工作的。大多数控制器的工作模式雷同,都是通过API Server 监听其相应的资源对象,根据对象的状态来决定接下来的动作,使其达到预期的状态.
- 集群中的调度器负责Pod 在集群节点中的调度分配。我们常说Kubernetes 是一个强大的编排工具,能够提高每台机器的资源利用率,将压力分摊到各个机器上,这主要归功于调度器。调度器是拓扑和负载感知的,通过调整单个和集体的资源需求、服务质量需求、硬件和软件的策略约束、亲和力和反亲和力规范、数据位置、工作负载间的干扰、期限等,来提升集群的可用性、性能和容量.
- etcd 是高可用的键值对的分布式安全存储系统,用于持久化存储集群中所有的资源对象.
●声明式API:开发者可以关注于应用自身,而非系统执行细节。比如Deployment(无状态应用)、StatefulSet(有状态应用)、Job(任务类应用)等不同资源类型,提供了对不同类型工作负载的抽象;对Kubernetes实现而言,基于声明式API的“level-triggered”实现比“edge-triggered”方式可以提供更加健壮的分布式系统实现。
●可扩展性架构:所有K8s组件都是基于一致的、开放的API实现和交互;三方开发者也可通过CRD(Custom Resource Definition)/Operator等方法提供领域相关的扩展实现,极大提升了K8s的能力。
●可移植性:K8s通过一系列抽象如Load Balance Service(负载均衡服务)、CNI(容器网络接口)、CSI(容器存储接口),帮助业务应用可以屏蔽底层基础设施的实现差异,实现容器灵活迁移的设计目标。
14.3.2 云原生微服务
1.微服务发展背景
以前开发个后端应用,最直接的方式就是通过单一后端应用提供并集成所有服务,即单体模式。
可这有个问题,项目小,参与人少还可以,庞大复杂的项目,参与人众多的时候,这种方式在开发、测试、发布、沟通等效率严重下滑,由此微服务诞生了。
微服务是根据业务逻辑相对独立性,把单体应用拆分成一个个的子功能,这些子功能就是微服务。这样在开发、测试、发布等等各方面效率提升了,同样的一件事有好的方面也就有不好的方面,微服务面临的挑战:如何高效调用远程方法、如何实现可靠的系统容量预估、如何建立负载均衡体系、如何面向松耦合系统进行集成测试、如何面向大规模复杂关联应用的部署与运维。
现在是云原生大行其道的时候,微服务+云原生就形成了云原生微服务体系。利用云上的各种资源开发微服务功能,这样系统更好的保障、安全、稳定、可观测、可控制。。。。
2.微服务设计约束
相较于单体应用,微服务架构提升了开发、部署等环节灵活性,但是也增加了运维、监控环节的复杂性,为了设计出一个优秀的微服务系统,应遵循以下设计约束:
1)微服务个体约束
业务域划分应是相互独立的,这样不同业务域可选择不同的技术去实现。还有微服务也应具备正交分解特性,即SOLID原则中单一职责原则(Single Responsibility Principle,SRP)。
2)微服务与微服务之间的横向关系
划分好微服务间边界后,主要从微服务的可发现性和可交互性处理服务间的横向关系。
可发现性:当服务A发布和扩容的时候,依赖服务A的服务B如何在不重新发布的情况下感知服务A的变化。
解决方式:引入第三方服务注册中心,来满足服务的可发现性。特别是大规模微服务集群,服务注册中心的推送和扩展能力尤为关键。
可交互性:服务A采用什么样的方式可以调用服务B。
解决方式:由于服务自治的约束,服务之间的调用需要采用与语言无关的远程调用协议,比如REST协议就满足,"与语言无关"和"标准化"两个重要因素;在高性能你场景下,基于IDL的二进制协议是更好的选择。
实践中大多没有达到HATEOAS启发式的REST调用,还是服务间事先约定来完成,为了进一步解耦,建立一个独立的元数据中心来存储服务的元数据信息,服务通过查询源数据中心来理解和发起服务。
3)微服务与数据层之间的纵向约束
- 在微服务领域,提倡数据存储隔离(Data Storage Segregation,DSS)原则,即数据是微服务的私有资产,对于该数据的访问都必须通过当前微服务提供的API来访问。
- 同时,出于性能考虑,通常采取读写分离 (CQRS)手段。
- 同样,由于容器调度对底层设施稳定性的不可预知影响,微服务的设计应当尽量遵循无状态设计原则。
- 对于有数据存取(即有状态)的微服务而言,通常使用计算与存储分离方式,将数据下沉到分布式存储,通过这个方式做到一定程度的无状态化。
4)全局视角下的微服务分布式约束
3.主要微服务技术
1.Apache Dubbo作为源自阿里巴巴的一款开源高性能RPC框架,特性包括基于透明接口的RPC、智能负载均衡、自动服务注册和发现、可扩展性高、运行时流量路由与可视化的服务治理。
14.3.3 无服务器技术
1.技术特点
2.技术关注点
1)计算资源弹性调度
2)负载均衡和流控
⼀个⼤的⾮常耗时的作业Job,⽐如:⼀次要处理⼀亿的数据,那这⼀亿的数据存储在数据库中,如果⽤⼀个作业节点处理⼀亿数据要很久,在互联⽹领域是不太能接受的,互联⽹领域更希望机器的增加去横向扩展处理能⼒。所以,ElasticJob可以把作业分为多个的task(每⼀个task就是⼀个任务分⽚),每⼀个task交给具体的⼀个机器实例去处理(⼀个机器实例是可以处理多个task的),但是具体每个task执⾏什么逻辑由我们⾃⼰来指定。比如有10台机器,每个task处理1000条记录。
3)安全性
14.3.4 服务网格
正确入门Service Mesh:起源、发展和现状-阿里云开发者社区
前面我们说过云架构可以把大量非功能性特性剥离,让开发聚焦于业务代码,服务网格就是这些剥离的技术之一。
先说说面临的问题:
1.治理难度大、技术门槛高
随着微服务实施水平的不断深化,除了基础的服务发现,配置中心和授权管理之外,在实施的过程中不可避免的需要在服务治理层面面临着各种新的挑战如分布式跟踪,熔断降级,灰度发布,故障切换等等治理需求。这些众多的非业务性需求,涉及到运维、运营管理层面,这使得整个项目在组织、分工、权责上变得交叉模糊,同时对相关人员提出了非常高的技术要求,然而我们开发的是业务程序,它的核心价值是业务逻辑的处理和实现,将越来越多的时间和精力花费在这些非业务功能上是非常不合理的。
2.多语言支持不足
对于稍具规模的团队,多语言的技术栈和跨语言调用是常态,然而目前开源社区上并没有一套统一的跨语言的微服务技术,那些没有框架支持的语言编写的服务很难融入面向微服务的已有架构体系中,想因地制宜的用多种语言实现架构体系中的不同模块在现实开发中很难做到。
3.代码侵入性强
主流的微服务实现框架或多或少都对业务代码有一定的侵入性,比如Spring Cloud框架中几乎每个微服务都需要集成Eureka、Feign等组件,这些组件框架替换成本高,复杂项目依赖时的库版本兼容问题也非常棘手,同时,框架库的升级也无法对服务透明,服务会因为和业务无关的依赖库升级而被迫升级,我们希望的是尽量将负责服务间通信的这种非业务代码从业务功能代码中剥离出来。
再来看看我们的解决方案:
1.Service Mesh架构思想
为解决上述微服务存在的问题,Service Mesh(服务网格)应运而生,它主要作为处理服务间通信的基础设施层,独立于具体的服务而存在,目的是从根本上解决了多语言支持不足以及代码侵入性的问题,并且凭借服务网格的独立性,使得业务团队不再需要关心复杂的服务治理工作,可以全权交给服务网格处理。
- 核心思想
服务网格的核心思想为Sidecar模式(边车模式),即将每个服务的负载、限流和服务发现等等通信功能和应用业务本身功能进行解耦分离,其负责服务间通信的部分称之为Sidecar代理,业务功能代码只和同机器下的不同进程的代理通信。如图2所示。
2.名称由来
由于每一个服务实例都会有一个Sidecar代理与之配对,服务之间的通信都是通Sidecar进行,在部署图表示为代理的交叉连接形成了一种网络网格,故称之为“服务网格”。目前所说的Service Mesh在若干服务的Sidercar代理基础上提供了统一集中式管理的运维入口即控制面平面, SideCar代理也称为数据平面 ,因此我们通常说Service Mesh由数据平台和控制平面组成,其结构如图3所示。
3.提供的功能
-
服务发现和负载均衡: 服务网格可以自动管理服务实例的位置,并将请求路由到可用的实例,实现负载均衡。
-
流量控制和超时处理: 通过服务网格,你可以设置流量控制策略,限制对某些服务的访问,并定义超时和重试机制。
-
安全性和认证: 服务网格可以处理服务之间的安全通信,确保请求和响应的机密性和完整性。
-
监控和跟踪: 服务网格可以收集有关请求和响应的数据,提供可观察性,帮助你分析和优化通信性能。
4.服务网格的组件和工作原理
服务网格通常由两个主要组件构成:
-
数据面(Data Plane): 数据面处理实际的请求和响应流量。它位于服务之间,负责请求的路由、负载均衡、流量控制等。
-
控制面(Control Plane): 控制面管理服务网格的配置和策略。它负责服务发现、路由规则、安全性设置等。
服务网格的工作原理:
客户端向服务网格发送请求。服务网格根据配置和策略,将请求路由到适当的服务实例。
服务实例处理请求并返回响应。服务网格可以收集有关请求和响应的数据,用于监控和跟踪。
5.服务网格的实现
-
Envoy: 由CNCF维护的高性能代理,支持负载均衡、流量控制、安全性等功能。
-
Istio: 基于Envoy的服务网格平台,提供丰富的策略配置和监控功能。
-
Linkerd: 轻量级服务网格,专注于简化通信和监控。
6.具体实例
Istio简介
- Istio是什么?
Service Mesh(服务网格)只是一种架构思想,主流的实现方案有Istio、Linkerd、Linkerd2、Consoul等等。其中Istio是目前最受欢迎且在实际生产中应用最为广泛的服务网格,它是由Google,IBM和Lyft这三家互联网巨头联合开发的一个基于服务网格的开源项目,功能丰富,成熟度高。下面将简单介绍Istio的框架及功能。
- Istio架构
Istio架构如下图所示,在逻辑上与Service Mesh框架思想保持一致,分为数据平面和控制平面两大部分,整体架构如图4所示。
①数据平面(Data Plane)
数据平面由一组以Sidecar方式部署的Envoy代理组成,所有进入和流出服务的流量都会被Envoy拦截,并与控制平面进行交互,根据配置执行相应的通信功能。
Envoy是用C++开发的高性能代理,Envoy代理作为唯一与数据平面流量交互的 Istio组件,相对于其他服务网格实现方案代理来说有着更丰富的治理能力和灵活的配置方式,并且支持各种插件可用于扩展流量治理能力,可生成遥测数据。
Envoy和Istio并不是强绑定关系,Envoy可以在其他框架中使用,Istio也可以采用其他代理。Envoy本身的内置功能有:负载均衡、TLS 终止、动态服务发现、HTTP/2&gRPC 代理,熔断器,健康检查,基于百分比流量拆分的分段推出,故障注入等。Envoy允许在不需要重新设计架构或重写代码条件下,启用或执行的一些Istio的功能和任务,比如:流量控制功能、网络弹性特性、安全性和身份认证特性基于WebAssembly的可插拔扩展模型等。
②控制平面
Istio的控制平面提供服务发现、配置和证书管理。由Pilot、Citadel、Galley三个组件整合成了一个单进程、多模块的istiod,极大的降低了部署的复杂度。在整个运行流程中,需要这些组件协同工作。
Pilot组件是控制面最重要的组件,负责提供服务发现、流量路由及服务治理功能,其架构如图5所示。
服务发现:Pilot通过插件的形式可以支持多种服务注册平台(K8s、Mesos等),通过平台适配器(Platform Adapter)将服务注册平台的服务数据填充为标准服务模型(Abstract Model),例如Pilot通过K8s适配器,将K8s中的Service及Pod实例等服务信息,转换为标准模型供Pilot使用。Pilot在得到统一的服务信息后,将服务信息通过Envoy API下发到数据面Envoy代理,实现服务发现功能。
流量路由及服务治理:运维人员可以通过Rules API指定各种高级流量管理规则(Gateway、VirtualService等),这些规则将被转换为数据面Envoy可以识别的格式,通过Envoy API下发给Envoy,Envoy在得到这些规则后,按照规则进行流量转发及安全认证
Gally是负责配置的验证和处理的组件,从底层平台获取配置,验证配置信息的格式和内容的正确性,并将这些配置信息提供给Pilot使用。
Citadel 是与安全相关的组件,主要负责密钥和证书的管理,可以实现强大的授权和认证等功能。
Istio总结:
任何一种方案都很难做到一劳永逸,Istio只是把原来分散在应用内部的复杂性统一抽象出来放到了统一的地方,且Istio的架构相对复杂,在具体生产中,必须做好清楚的规划,权衡它带来的好处是否远大于额外维护它的花费,选择合适的架构方案。
7.传统微服务调用和服务网格服务调用
8.总结
微服务架构的复杂通信问题可以通过服务网格得到解决。服务网格提供了一种管理、简化和增强微服务通信的方式,通过数据面和控制面的结构,实现负载均衡、流量控制、安全性和可观察性。在构建和维护微服务架构时,考虑使用服务网格来应对通信挑战,将有助于提高系统的稳定性和性能。
14.4 云原生架构案例分析---看看即可
14.4.1某旅行公司云原生改造
14.4.2云原生技术助力某汽车公司数字化转型实践
14.4.3某快递公司核心业务系统云原生改造
14.4.4某电商业务云原生改造
14.4.5某体育用品公司基于云原生架构的业务中台构建
站在巨人的肩膀上:
https://author.baidu.com/home?from=bjh_article&app_id=1695948768434894
更多推荐
所有评论(0)