分布式系统架构与开发:技术原理与面试题解析
上QQ阅读APP看书,第一时间看更新

1.1 分布式系统概述

分布式系统是传统单块系统的一种演进。为了更好地理解和掌握分布式系统的概念,本节先从单块系统开始讲起,然后引出分布式系统的基本特性。

1.1.1 从单块系统到分布式系统

在技术发展的很长一段时间内,软件系统都采用单块系统的模式。时至今日,一些行业和公司仍然在开发与维护很多单块系统。所谓单块系统,简单讲就是把一个系统所涉及的各个组件都打包进一个一体化结构并进行部署和运行。在Java EE领域,如果我们使用当下最流行的Spring Boot框架来开发应用程序,那么这种一体化结构很多时候就表现为一个JAR包,而部署和运行的环境就是以Tomcat为代表的各种应用服务器。图1-1展示的就是一个典型的单块系统,我们可以看到在应用服务器上同时运行着Web服务层、业务逻辑层和数据访问层组件,这些组件作为一个整体进行统一的开发、部署和维护。

显然,图1-1所示的单块系统有其存在和应用的固有优势。当团队规模并不是太大的时候,一个单块系统可以由一个开发者团队独立维护。该团队的成员能够对单块系统进行快速学习、理解和修改,因为其结构非常简单。同时,因为单块系统的表现形式就是一个独立的物理包,想要对它进行集成、部署以及实现无状态集群相对也比较简单,通常只需要采用负载均衡机制,运行该单块系统的多个实例,就能满足系统一定的可伸缩性要求。

图1-1 单块系统示意图

但随着团队或者组织的业务规模不断扩张、业务结构不断变化以及产品用户量不断增加,单块系统已逐渐无法适应互联网时代的快速发展,面临着越来越多的挑战。在使用单块系统时,我们不得不面对业务复杂度过高、代码腐化以及系统可伸缩性无法满足要求等问题,而随着团队规模的不断扩大,众多开发人员维护同一个单块系统,这对人员组织也是一个很大的挑战。针对以上集中式单块系统所普遍存在的问题,基本的解决方案就是合理构建分布式系统。

前面已经提到,网络和通信协调是我们在设计与实现分布式系统时首先需要考虑的两个方面。图1-2展示的就是从软件开发角度出发得到的一个典型的分布式系统,其中包含分布式服务、消息中间件和分布式缓存等用于构建分布式系统的常见技术组件。显然,这些技术组件位于一个封闭或开放的网络环境中,相互之间通过服务的注册和发现、消息通信、数据的缓存共享等机制完成协作。

图1-2 分布式系统示意图

在分布式系统中,我们要打破单块系统中集中式的架构思维,引入系统拆分的思想和实践。拆分的需求来自组织结构、交付速度、业务需求以及技术需求的变化,一般认为系统拆分的基本思路有两种,即纵向拆分和横向拆分。

所谓纵向拆分,就是将一个大应用拆分为多个小应用,如果新业务较为独立,那么就直接将其设计部署为一个独立的应用系统。如图1-3所示,我们可以将电商系统中的商品下单业务拆分成订单、商品和用户等独立的业务服务。纵向拆分关注业务,通过梳理产品线,将内聚度较高的相关业务进行剥离从而形成不同的子系统。

图1-3 分布式纵向拆分示意图

相较于面向业务的纵向拆分,横向拆分更多关注技术。其做法是将可以复用的业务拆分出来并独立部署为分布式服务,开发人员只需调用这些分布式服务即可构建复杂的新业务。所以,横向拆分的关键在于识别可复用的业务,设计其服务接口并规范服务依赖关系。横向拆分的基本实现方式是构建分布式服务体系,图1-4是对图1-3中的商品下单业务进行细化并完成横向拆分的结果。

图1-4 分布式横向拆分示意图

可以看到,当我们把订单、商品、支付和用户等业务抽象成独立的垂直化服务,并在各个服务上层实现分布式的调用和管理框架后,系统业务的构建方式就可以转变为排列组合。如基于订单和支付服务,我们可以构建出业务A,而业务B可能只依赖商品和用户服务。分布式服务框架提供了一种按需构建服务的机制,在保证各个分布式服务的技术、人员、交付独立发展的前提下,确保业务服务整体的灵活性和高效性。

1.1.2 分布式系统的基本特性

分布式系统相较于集中式单块系统具备优势,但也不可避免地引入了复杂度,具体体现在以下几个方面。

□ 网络通信的三态性

构建分布式系统需要依赖网络通信,而网络通信表现为一个复杂且不可控的过程。相比于单块系统中函数式调用的失败或者成功,网络通信会出现“三态”,即成功、失败与超时。由于网络请求超时,消息没有成功发送到接收方,而是在发送过程中发生了丢失;或者在接收方处理后,响应给发送方的过程中消息发生了丢失。这些问题都会增加通信的代价。使通信的代价降到用户可以忍耐的程度是设计分布式系统的重要目标。

□ 请求的容错性

分布式系统中的任何服务器都有可能出现故障,且其故障不尽相同。而运行在服务器上的服务也可能出现各种异常情况,服务之间出现异常的时机一般也是相互独立的。通常,分布式系统在设计上要允许出现部分故障而不影响整个系统的正常运行。

□ 系统的异构性

相较于单块系统,分布式系统基于不同的网络、操作系统、技术体系而实现,必须要考虑一种通用的服务集成和交互方式来屏蔽其中异构系统之间的差异。对异构系统之间关联的不同处理方式会直接影响系统的设计和开发过程。

□ 数据的一致性

在分布式系统中,数据被分散或者复制到不同的服务器上,如何保证各台主机之间的数据一致性成为一个难点。因为网络的异常会导致分布式系统中只有部分节点能够正常通信,从而形成网络分区。

以上是分布式系统的基本特性,我们无法避免这些特性导致的复杂度增加,只能想办法进行利用和管理,这就给我们设计和实现分布式系统提出了挑战。为此,我们需要进一步梳理分布式系统开发过程中的技术核心点。

1.1.3 分布式系统和微服务架构

微服务架构在最近几年的软件开发中已经成为主流架构模式,它形成了一种特定的软件应用设计方法,核心思想是将各个服务套件进行独立部署。在微服务架构的设计理论中,对业务建模、服务集成、数据去中心化等方面进行抽象和提炼的架构设计思想及方法已得到普遍认可。

相比于其他系统架构的构建方式和技术方案,微服务架构具有固有的特点,这些特点也为我们使用微服务架构进行系统设计提供了关键切入点。微服务架构的提出者Martin Fowler指出,微服务架构具有以下特点。

□ 服务组件化

所谓组件是指一种可独立替换和升级的软件单元。在日常开发过程中我们可能会设计和使用很多组件,这些组件可能服务于系统内部,也可能存在于系统所运行的进程之外。而服务就是一种进程外组件,服务之间利用诸如RPC(Remote Procedure Call,远程过程调用)的通信机制完成交互。服务组件化的主要目的是实现服务的独立部署。如果你的应用程序是由很多运行在进程中的组件组成的,那么对任何一个组件的改变都将导致其应用程序的重新部署。但是如果你把应用程序拆分成很多独立运行的服务,显然,在通常情况下,你只需要重新部署那个需要改变的服务。在微服务架构中,每个服务运行在其独立的进程中,服务与服务之间采用轻量级通信机制互相沟通。

□ 按业务能力组织服务

当寻找方法来把一个大的应用程序进行拆分时,研发过程通常都会围绕产品团队、UED(User Experience Design,用户体验设计)团队、App前端团队和服务器端团队而展开,这些团队也就是通常所说的职能团队(function team)。当根据各团队的职能对系统进行划分时,任何一个需求变更,无论大小,都将导致跨团队协作,从而增加沟通和协作成本。而微服务架构的划分方法有所不同,它倾向于围绕业务功能的组织来分割服务。这些服务面向具体业务结构,而不是面向某项技术能力。因此,团队是跨职能的特征团队(feature team),具备用户体验、项目管理和技术研发等开发过程所要求的所有技能。每个服务都围绕着业务进行构建,并且能够被独立部署到生产/类生产环境中。

□ 去中心化

服务集中治理的一个好处是可以在单一平台上进行标准化,但采用微服务架构的团队更喜欢对不同的服务采用不同的治理标准。一方面,把整体式框架中的组件拆分成不同的服务,我们在构建这些服务时就会有更多的选择。对一个具体的服务而言,应该根据业务上下文,选择合适的语言、工具进行构建。另一方面,微服务架构也崇尚对数据进行分散管理。当整个应用使用单一的数据处理逻辑进行数据持久化时,通常在应用内只使用一个数据库。而微服务让每个服务管理自己的数据库,无论是使用相同数据库的不同实例,还是使用不同的数据库系统,都可以实现。

□ 基础设施自动化

许多使用微服务架构的产品或者系统,它们的团队拥有丰富的持续集成(Continue Integration,CI)和持续交付(Continuous Delivery,CD)的经验。团队使用微服务架构来构建软件需要更广泛地依赖基础设施自动化技术。

从以上特点出发,我们认为微服务架构设计的首要切入点在于服务建模,尽可能明确领域的边界。我们可以充分利用领域驱动设计(Domain Driven Design,DDD)的方法,识别领域/子域中的模块和服务,判断这些模块和服务是否独立,考虑提升某些模块和服务的层次,并建立充血领域模型,从而明确各个界限上下文之间的边界。

同时,在微服务架构的设计过程中,我们需要关注服务之间的集成方式,即需要保证集成方式的技术无关性,不要选择对服务的具体实现有技术性限制的集成技术。采用技术无关的集成接口,充分融合多样化的技术,意味着我们在特定场景下不应该使用类似私有化协议和重量级通信框架的方式,而应该尽可能地使用如RESTful的轻量级通信方式进行服务集成,来确保服务易于使用,消费方可以使用多种技术实现集成。

服务的部署是在微服务架构实施过程中的一个重点,在微服务架构中,可以独立部署单个服务而不需要修改其他服务。同时,由于服务数量大,修改和发布的频率可能很高,对接口的修改通常采用逐步迁移的方案。而在接口的发布上,常见的API网关等模式也得到广泛应用。

最后,我们需要强调的一点是,微服务架构本质上也是一种分布式架构。一方面,它遵循通用的分布式特性,因此在微服务中同样需要考虑服务容错性设计等问题。另一方面,在分布式系统的基础上,微服务架构还表现出一定的特殊属性。微服务架构崇尚服务的组件化,并基于业务能力来合理划分和组织服务。而在服务与服务的集成方式上,微服务架构需要保证集成方式的技术无关性,推荐选择对服务具体实现没有技术性限制的集成技术。