编辑推荐: |
文章主要介绍了什么是分布式系统架构,与传统单体应用比较有什么优缺点。一些难点介绍,随后又介绍了分布式系统的技术栈以及全栈监控。
来自于bilibili专栏,,由火龙果软件Anna编辑、推荐。 |
|
终于到了时下讨论最热门的分布式系统架构了,现在各大公司无论是大公司还是小公司都会提及使用分布式系统架构来构建xxx系统,还有PasS平台这些概念的出现,可以说分布式系统架构是现在最热门的技术话题了。我接触分布式系统架构最初是在2016年为之前公司的社交产品“叮趣”,从零到一构建了一套分布式系统架构后端服务,当然那时候自己也是边学边做,摸着石头过河,很多东西都不完善,比如服务之间耦合程度比较高,也没有类似DevOps这样的自动化运维方案,分布式事务问题没有彻底解决,只能算个传统单体应用和分布式系统相结合的半成品。
1.分布式系统架构的定义
什么叫分布式系统架构?
将单体应用拆分成多个子系统,每个子系统运行在各自的进程中,子系统间相互通讯,从而使整个系统运转起来,这就是分布式系统架构。
2.传统单体应用与分布式系统架构的优缺点
分布式系统相比较于单体应用有着很多的优势,比如能增加系统吞吐量,加强系统高可用性等。不过世界上不存在完美的技术方案,分布式系统架构也有很多缺陷,下面这张图表对比了两者的优缺点。
3.分布式系统架构的发展史
开发、维护和使用 SOA 要遵循以下几条基本原则。
可重用,粒度合适,模块化,可组合,构件化以及有互操作性。
符合开放标准(通用的或行业的)。
服务的识别和分类,提供和发布,监控和跟踪。
分布式系统架构的演变史:
我们可以看到,面向服务的架构有以下三个阶段。
l 20 世纪 90 年代前,是单体架构,软件模块高度耦合。当然,这张图同样也说明了有的 SOA
架构其实和单体架构没什么两样,因为都是高度耦合在一起的。就像图中的齿轮一样,当你调用一个服务时,这个服务会调用另一个服务,然后又调用另外的服务……于是整个系统就转起来了。但是这本质是比较耦合的做法。
l 而 2000 年左右出现了比较松耦合的 SOA 架构,这个架构需要一个标准的协议或是中间件来联动其它相关联的服务(如
ESB)。这样一来,服务间并不直接依赖,而是通过中间件的标准协议或是通讯框架相互依赖。这其实就是 IoC(控制反转)和
DIP(依赖倒置原则)设计思想在架构中的实践。它们都依赖于一个标准的协议或是一个标准统一的交互方式,而不是直接调用。
l 而 2010 年后,出现了微服务架构,这个架构更为松耦合。每一个微服务都能独立完整地运行(所谓的自包含),后端单体的数据库也被微服务这样的架构分散到不同的服务中。而它和传统
SOA 的差别在于,服务间的整合需要一个服务编排或是服务整合的引擎。就好像交响乐中需要有一个指挥来把所有乐器编排和组织在一起。
4.分布式系统架构的难点
从目前已经公开的资料来看,分布式服务化架构思想实践最早的公司应该是亚马逊。在2002年的时候亚马逊CEO贝索斯就向公司颁布了几条架构的规定
1.所有团队的程序模块都要通过 Service Interface 方式将其数据与功能开放出来。
2.团队间程序模块的信息通信,都要通过这些接口。除此之外没有其它的通信方式。
3.其他形式一概不允许:不能直接链结别的程序(把其他团队的程序当做动态链接库来链接),不能直接读取其他团队的数据库,不能使用共享内存模式,不能使用别人模块的后门,等等。唯一允许的通信方式是调用
Service Interface。
4.任何技术都可以使用。比如:HTTP、CORBA、Pub/Sub、自定义的网络协议等。
5.所有的 Service Interface,毫无例外,都必须从骨子里到表面上设计成能对外界开放的。也就是说,团队必须做好规划与设计,以便未来把接口开放给全世界的程序员,没有任何例外。
6.不这样做的人会被炒鱿鱼。
亚马逊管理分布式系统架构的要点
针对分布式系统架构运维和管理的难点,亚马逊主要从以下几方面来管理。
l 分布式服务的架构需要分布式的团队架构
l 分布式服务查错不容易
l 没有专职的测试人员,也没有专职的运维人员,开发人员做所有的事情
l 运维优先,崇尚简化和自动化
l 内部服务和外部服务一致
分布式系统架构的难点
问题一:异构系统的不标准问题
问题二:系统架构中的服务依赖性问题
问题三:故障发生的概率更大
问题四:多层架构的运维复杂度更大
首先看第一个问题,这主要体现在软件和应用不标准、通讯协议不标准、数据格式不标准、开发和运维的过程和方法不标准。这些问题都会提升我们构建分布式系统架构的复杂度。
第二是服务依赖性的问题,在分布式系统架构中,服务之间是会有依赖的,一个服务挂了可能会引发“多米诺骨牌”效应,导致整个系统瘫痪。
由于系统被拆分成多个服务,每个服务部署在不同的机器上,每个服务对应的数据库也在不同的机器上,这就使得系统出现故障的概率增加,毕竟分布得越散就越容易犯错。
分布式系统架构主要分为四层:基础层、平台层、应用层和接入层。
基础层就是我们的机器、网络和存储设备等。
平台层就是我们的中间件层,Tomcat、MySQL、Redis、Kafka 之类的软件。
应用层就是我们的业务软件,比如,各种功能的服务。
接入层就是接入用户请求的网关、负载均衡或是 CDN、DNS 这样的东西。
这四层中的任何一层出现问题都有可能导致整个系统瘫痪。
以上就是分布式系统中的难点,在分布式系统中,每个子系统都有对应的分工,分工不是问题,问题是分工后的协作是否统一和规范。
5.分布式系统的技术栈
构建分布式系统架构的目的是为了增加系统吞吐量,提高系统的可用性。在技术方面实际上就是通过集群技术将并发请求负载分散到不同的机器上,提高系统可用性,将服务故障隔离防止出现“多米诺骨牌”效应。
提高系统的性能
缓存系统
加入缓存系统可以有效地提高系统的性能,从前端的浏览器,到网络,再到后端的服务,底层的数据库、文件系统、硬盘和
CPU,全都有缓存,这是提高快速访问能力最有效的手段。在分布式系统架构中需要一个缓存集群。
负载均衡系统
负载均衡系统是水平扩展的关键技术,它可以使用多台机器来共同分担一部分流量请求。
异步调用
异步系统主要通过消息队列来对请求做排队处理,这样可以把前端的请求的峰值给“削平”了,而后端通过自己能够处理的速度来处理请求。这样可以增加系统的吞吐量,但是实时性就差很多了。同时,还会引入消息丢失的问题,所以要对消息做持久化,这会造成“有状态”的结点,从而增加了服务调度的难度。
数据分区和数据镜像
数据分区是把数据按一定的方式分成多个区(比如通过地理位置),不同的数据区来分担不同区的流量。这需要一个数据路由的中间件,会导致跨库的
Join 和跨库的事务非常复杂。而数据镜像是把一个数据库镜像成多份一样的数据,这样就不需要数据路由的中间件了。你可以在任意结点上进行读写,内部会自行同步数据。然而,数据镜像中最大的问题就是数据的一致性问题。
提高架构的稳定性
服务拆分
服务拆分主要有两个目的:一是为了隔离故障,二是为了重用服务模块。但服务拆分完之后,会引入服务调用间的依赖问题。
服务冗余
服务冗余是为了去除单点故障,并可以支持服务的弹性伸缩,以及故障迁移。然而,对于一些有状态的服务来说,冗余这些有状态的服务带来了更高的复杂性。其中一个是弹性伸缩时,需要考虑数据的复制或是重新分片,迁移的时候还要迁移数据到其它机器上。
限流降级
当系统实在扛不住压力时,只能通过限流或者功能降级的方式来停掉一部分服务,或是拒绝一部分用户,以确保整个架构不会挂掉。这些技术属于保护措施。
高可用架构
通常来说高可用架构是从冗余架构的角度来保障可用性。比如,多租户隔离,灾备多活,或是数据可以在其中复制保持一致性的集群。总之,就是为了不出单点故障。
高可用运维
高可用运维指的是 DevOps 中的 CI/CD(持续集成 / 持续部署)。一个良好的运维应该是一条很流畅的软件发布管线,其中做了足够的自动化测试,还可以做相应的灰度发布,以及对线上系统的自动化控制。这样,可以做到“计划内”或是“非计划内”的宕机事件的时长最短。
分布式系统的关键技术
服务治理
服务拆分、服务调用、服务发现、服务依赖、服务的关键度定义……服务治理的最大意义是需要把服务间的依赖关系、服务调用链,以及关键的服务给梳理出来,并对这些服务进行性能和可用性方面的管理。
架构软件管理
服务之间有依赖,而且有兼容性问题,所以,整体服务所形成的架构需要有架构版本管理、整体架构的生命周期管理,以及对服务的编排、聚合、事务处理等服务调度功能。
DevOps
分布式系统可以更为快速地更新服务,但是对于服务的测试和部署都会是挑战。所以,还需要 DevOps
的全流程,其中包括环境构建、持续集成、持续部署等。
自动化运维
有了 DevOps 后,我们就可以对服务进行自动伸缩、故障迁移、配置管理、状态管理等一系列的自动化运维技术了。
资源调度管理
应用层的自动化运维需要基础层的调度支持,也就是云计算 IaaS 层的计算、存储、网络等资源调度、隔离和管理。
整体架构监控
如果没有一个好的监控系统,那么自动化运维和资源调度管理只可能成为一个泡影,因为监控系统是你的眼睛。没有眼睛,没有数据,就无法进行高效的运维。所以说,监控是非常重要的部分。这里的监控需要对三层系统(应用层、中间件层、基础层)进行监控。
流量控制
最后是我们的流量控制,负载均衡、服务路由、熔断、降级、限流等和流量相关的调度都会在这里,包括灰度发布之类的功能也在这里。
分布式系统的“纲”
分布式系统的关键技术其实就是五大方面:
全栈系统监控;
服务 / 资源调度;
流量调度;
状态 / 数据调度;
开发和运维的自动化。
6.分布式系统关键技术:全栈监控
由于应用被拆分成多个服务子系统,因此需要对整个系统进行全栈的监控,一遍我们更好的发现和定位系统故障问题。
全栈监控需要监控哪些内容呢?
基础层
监控主机和底层资源。比如:CPU、内存、网络吞吐、硬盘 I/O、硬盘使用等
中间层
就是中间件层的监控。比如:Nginx、Redis、ActiveMQ、Kafka、MySQL、Tomcat
等
应用层
监控应用层的使用。比如:HTTP 访问的吞吐量、响应时间、返回码、调用链路分析、性能瓶颈,还包括用户端的监控
什么是好的监控系统?
关注于整体应用的 SLA
主要从为用户服务的 API 来监控整个系统
关联指标聚合
把有关联的系统及其指标聚合展示。主要是三层系统数据:基础层、平台中间件层和应用层。其中,最重要的是把服务和相关的中间件以及主机关联在一起,服务有可能运行在
Docker 中,也有可能运行在微服务平台上的多个 JVM 中,也有可能运行在 Tomcat 中。总之,无论运行在哪里,我们都需要把服务的具体实例和主机关联在一起,否则,对于一个分布式系统来说,定位问题犹如大海捞针。
能快速故障定位
对于现有的系统来说,故障总是会发生的,而且还会频繁发生。故障发生不可怕,可怕的是故障的恢复时间过长。所以,快速地定位故障就相当关键。快速定位问题需要对整个分布式系统做一个用户请求跟踪的
trace 监控,我们需要监控到所有的请求在分布式系统中的调用链,这个事最好是做成没有侵入性的。
如何做出一个好的监控系统?
服务调用链跟踪
对应开源实现:Zipkin,SkyWalking
服务调用时长分布
Zipkin
服务的 TOP N 视图
数据库操作关联
对于 Java 应用,我们可以很方便地通过 JavaAgent 字节码注入技术拿到 JDBC 执行数据库操作的执行时间。对此,我们可以和相关的请求对应起来。
服务资源跟踪
我们的服务可能运行在物理机上,也可能运行在虚拟机里,还可能运行在一个 Docker 的容器里,Docker
容器又运行在物理机或是虚拟机上。我们需要把服务运行的机器节点上的数据(如 CPU、MEM、I/O、DISK、NETWORK)关联起来。
一个分布式系统故障的示例图:
7.分布式系统关键技术:服务调度
服务关键程度和服务的依赖关系
1.梳理出定义服务的关键程度
服务的关键程度是根据业务来定义的,需要你对系统的业务有较好的理解,才能更好定义出系统架构中各个服务的关键程序。
2.梳理出服务之间的依赖关系
在分布式系统中要做到服务之间没有依赖是不可能的事情,因此需要梳理出服务间的依赖关系。微服务是服务依赖最优解的上限,而服务依赖的下限是千万不要有依赖环。如果系统架构中有服务依赖环,那么表明你的架构设计是错误的。
服务的依赖关系是可以通过技术的手段来发现的,这其中,Zipkin是一个很不错的服务调用跟踪系统。
服务状态和生命周期的管理
需要一个服务发现的中间件来管理,也就是服务注册中心,例如:Zookeeper、Nacos等。
我们需要知道这些服务的状态和生命周期,比如:有的服务会新加进来,有的服务会下线,服务对应的实例有多少个,这些实例的状态是怎样的?这些都需要被管理起来。
服务的生命周期通常会有以下几个状态:
Provision,代表在供应一个新的服务;
Ready,表示启动成功了;
Run,表示通过了服务健康检查;
Update,表示在升级中;
Rollback,表示在回滚中;
Scale,表示正在伸缩中(可以有 Scale-in 和 Scale-out 两种);
Destroy,表示在销毁中;
Failed,表示失败状态。
整个架构的版本管理
在分布式架构中,我们也需要一个架构的版本,用来控制其中各个服务的版本兼容。比如,A 服务的 1.2
版本只能和 B 服务的 2.2 版本一起工作,A 服务的上个版本 1.1 只能和 B 服务的 2.0
一起工作。这就是版本兼容性。
如果架构中有这样的问题,那么我们就需要一个上层架构的版本管理。这样,如果我们要回滚一个服务的版本,就可以把与之有版本依赖的服务也一起回滚掉。
当然,一般来说,在设计过程中,我们希望没有版本的依赖性问题。但可能有些时候,我们会有这样的问题,那么就需要在架构版本中记录下这个事,以便可以回滚到上一次相互兼容的版本。
要做到这个事,你需要一个架构的 manifest,一个服务清单,这个服务清单定义了所有服务的版本运行环境,其中包括但不限于:
服务的软件版本;
服务的运行环境——环境变量、CPU、内存、可以运行的结点、文件系统等;
服务运行的最大最小实例数。
每一次对这个清单的变更都需要被记录下来,算是一个架构的版本管理。而我们上面所说的那个集群控制系统需要能够解读并执行这个清单中的变更,以操作和管理整个集群中的相关变更。
8.分布式系统关键技术:流量与数据调度
流量调度:
流量调度需要满足的需求有以下两个方面:
1.依据系统运行的情况,自动地进行流量调度,在无需人工干预的情况下,提升整个系统的稳定性
2.让系统应对爆品等突发事件时,在弹性计算扩缩容的较长时间窗口内或底层资源消耗殆尽的情况下,保护系统平稳运行
3.服务流控。服务发现、服务路由、服务降级、服务熔断、服务保护等。
4.流量控制。负载均衡、流量分配、流量控制、异地灾备(多活)等
5.流量管理。协议转换、请求校验、数据缓存、数据计算等
以上这些要求都是一个API Gateway需要做的事情。一个好的API Gateway应具备以下关键技术:
高性能
扛流量
要能扛流量,就需要使用集群技术。集群技术的关键点是在集群内的各个结点中共享数据。这就需要使用像 Paxos、Raft、Gossip
这样的通讯协议。因为 Gateway 需要部署在广域网上,所以还需要集群的分组技术
业务逻辑
API Gateway 需要有简单的业务逻辑,所以,最好是像 AWS 的 Lambda 服务一样,可以让人注入不同语言的简单业务逻辑。
服务化
一个好的 API Gateway 需要能够通过 Admin API 来不停机地管理配置变更,而不是通过一个.conf
文件来人肉地修改配置。
状态数据调度
1.对于应用层上的分布式事务一致性,只有两阶段提交这样的方式
2.而底层存储可以解决这个问题的方式是通过一些像 Paxos、Raft 或是 NWR 这样的算法和模型来解决
3.状态数据调度应该是由分布式存储系统来解决的,这样会更为完美。但是因为数据存储的 Scheme
太多,所以,导致我们有各式各样的分布式存储系统,有文件对象的,有关系型数据库的,有 NoSQL 的,有时序数据的,有搜索数据的,有队列的……
9.PasS平台的本质
第一,提高服务的 SLA
第二,能力和资源重用或复用
第三,过程的自动化(包括自动化运维以及生产环境正在运行的软件的自动化)
PasS平台的本质是:
服务化
分布式
自动化
PaaS 平台的总体架构
一个完整的 PaaS 平台会包括以下几部分。
PaaS 调度层 – 主要是 PaaS 的自动化和分布式对于高可用高性能的管理。
PaaS 能力服务层 – 主要是 PaaS 真正提供给用户的服务和能力。
PaaS 的流量调度 – 主要是与流量调度相关的东西,包括对高并发的管理。
PaaS 的运营管理 – 软件资源库、软件接入、认证和开放平台门户。
PaaS 的运维管理 – 主要是 DevOps 相关的东西。
PaaS 平台的生产和运维下面的图我给出了一个大概的软件生产、运维和服务接入的流程,它把之前的东西都串起来了。
从左上开始软件构建,进入软件资产库(Docker Registry+ 一些软件的定义),然后走 DevOps
的流程,通过整体架构控制器进入生产环境,生产环境通过控制器操作 Docker+Kubernetes
集群进行软件部署和生产变更。
其中,同步服务的运行状态,并通过生命周期管理来拟合状态,如图右侧部分所示。服务运行时的数据会进入到相关应用监控,应用监控中的一些监控事件会同步到生命周期管理中,再由生命周期管理器来做出决定,通过控制器来调度服务运行。当应用监控中心发现流量变化,要进行强制性伸缩时,它通过生命周期管理来通知控制系统进行伸缩。
左下是服务接入的相关组件,主要是网关服务,以及 API 聚合编排和流程处理。这对应于之前说过的流量调度和
API Gateway 的相关功能。
|