高可用可伸缩微服务架构:基于Dubbo、Spring Cloud和Service Mesh
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.5 架构的目标与方法

了解软件系统架构的一些通用目标,可以使我们更加明确如何考虑架构的方向。而了解架构的方法和方法论,则让我们知道从哪些角度可以比较全面地描述清楚一个系统的架构设计。

1.可控性与拆分

人类最原始且最强烈的情绪就是恐惧,而最原始且最强烈的恐惧就是对未知事物的恐惧。

——H.P.Lovecraft

对于复杂问题的简化处理,一个简单办法就是分而治之。按一定的粒度把目标问题进行分解,可以有效地提升目标的可控性,使目标变得可以量化,进而优化。在并行领域或数据库事务理论里,我们把一个复杂的执行步骤分解为多个不同的小步骤,这样就可以把其中可以并行的部分并行执行。整个程序的执行时间就等于所有串行部分的时间和最大可以并行部分的时间之和。在性能优化方面,我们一般采取的第一步就是找瓶颈,把一个复杂的业务处理过程拆解成多个服务或方法级的调用步骤,收集每个步骤的处理时间,然后找到最慢的地方进行优化。如果最慢的步骤还包括多个小步骤,那么可以进一步按这种方式处理,直到可以优化为止。

抛开计算机领域来说,现代化工业的基础是流水线作业,把一个复杂的操作流程拆解成多个独立的简单步骤,把其中可以机械化的部分交给机器完成,需要人工处理的部分增加人工规模,从而最大化地提升生产效率。近年来,很多行业提出了标准作业程序(Standard Operating Procedure, SOP)的概念,通过将日常工作拆解为多个标准规格的步骤,进而找到其中的关键节点和可以优化的步骤,不断提升管理效率。

如果拆分得太细了,那么有可能处理起来太麻烦,就像是一箱子零钱,数了很长时间发现是100块。如果是2张50块,1秒钟就可以知道是100块钱了。

因此,拆分带来好处的同时,也带来一个基本性的问题:拆分到什么粒度是最合适的?这个问题很难回答。一般认为系统被拆分后,每个模块或组件的粒度标准应该满足一个原则:高内聚、低耦合。高内聚是指模块内的功能和逻辑是紧密联系在一起的,低耦合是指模块之间的关联性非常小。例如,我们把系统划分为20个模块后,一般情况下修改其中的一个模块几乎不影响其他19个模块,这时候我们就可以说系统是低耦合的。同理,每个模块内的功能和逻辑都围绕一个核心业务流程,很难继续拆解成两个独立业务,我们就可以说系统是高内聚的。

系统按照合适的粒度拆分成不同模块的过程,我们一般称为模块化。模块化也是软件工程化的基础。在这个基础上才能够实现合理的分工合作。

2.复用性与抽象

天下大势,分久必合,合久必分。

复用性一直是软件设计领域很重要的一个指标。举例来说,一个用于计算贷款利息的方法,无法直接复用于计算理财收益。如果我们把公式作为一个表达式抽象出来,那么这两个方法就有了一个共同点,都是基于一个具体的公式的应用。这时,我们把“输入一个公式表达式和给定的初始值,计算出来公式的结果”作为一个函数,那么就可以复用这个函数,同时来处理计算利息和计算理财收益了。所以,复用的一个关键是我们对于现有具体问题的抽象,找到各种不同问题中存在的不变性,进而作为一种通用结构来统一处理。

拆分是把整体变成很多局部,再对局部分开对待和研究其性质。反过来,我们按照高内聚的指导思想把一些紧密联系的功能聚合后,打包成一个可以整体复用的部分,这就是组件,这个过程就是组件化。通过组件化,我们可以得到抽象复用部分,再组合出来很多业务组件。这样,在更大粒度上实现了功能的复用。

3.非功能性需求九维目标(见图1-4)

图1-4

1)高性能

系统必须满足预期的性能目标,在并发用户数(Concurrent Users)、并发事务数(Transactions per Second, TPS)、吞吐量(Throughout)和延迟(Latency)等指标方面达到预估值,支撑目标使用人群的正常使用。我们一般根据经验,通过预估目标使用人数来设定系统性能指标值,然后通过JMeter、LoadRunner等工具对系统进行性能测试(Performance Testing),收集系统的指标值,进而进行分析与调优,最终满足性能要求。

2)可靠性

业务系统直接影响用户的经营和管理,因此必须是可靠的。可靠性主要体现在业务数据和流程的一致性上。数据不一致常常会涉及用户的资金结算出错,给用户造成直接损失,同时降低用户对软件的使用信心。

3)稳定性

软件系统必须能够在用户的使用周期内长期稳定运行。这就要求系统具有一定的容错能力。

4)可用性

可用性是指系统在指定时间内提供服务能力的概率值。我们一般采取集群、分布式等手段提升系统的可用性。高可用性是目前系统架构设计方面的一个热点。

5)安全性

用户的业务数据具有非常高的商业价值,如果被泄露或篡改将会带来重大损失。安全性是软件系统的一个重要指标,也是架构设计的一个重要目标。

6)灵活性

软件系统应该具备满足不同特点的用户群和目标市场的能力。

7)易用性

软件系统必须拥有较好的用户体验,方便用户使用。

8)可扩展性

业务和技术都在不断地发展变化,软件系统需要随时根据变化扩展改造的能力。

9)可维护性

软件系统的维护包括修复现有的错误,以及将新的需求和改进添加到已有系统。因此一个易于维护的系统对于用户提出的问题或改进,可以及时地实现高效的反馈和响应支持,同时有效降低维护成本。

基于这些目标,经常有人说:“架构是系统非功能性需求的解决办法的集合”。

4.架构方法:4+1视图模型

前面介绍了很多关于软件系统架构的概念和特点,那么从哪些方面可以描述清楚一个系统的架构设计呢?

以介绍一个朋友作为例子,我们可以说他是男的,黑头发、黄皮肤、有点胖,这些词是从外形上形容这个朋友的。当然我们也可以说他穿着格子衬衫、牛仔裤、运动鞋,戴一块手表,这是从衣着打扮上形容这个朋友的。我们也可以说他个性鲜明、热情开朗、善于沟通交流、诚实善良,对朋友很关心照顾等,这是从性格方面介绍他的。我们可以从很多不同的角度去描述这个朋友。

为了清晰地描述软件架构设计,我们引入一个概念:架构视图。什么是架构视图呢?Philippe Kruchten在其著作《Rational统一过程引论》中写道:

一个架构视图是对于从某一视角或某一点上看到的系统所做的简化描述,描述中涵盖了系统的某一特定方面,而省略了与此方面无关的实体。

也就是说,我们可以从不同视角分别描述同一个架构设计,最后把这多个视角的设计综合到一起,就是这个系统的完整架构设计了。这些不同角度的设计文档也成为我们理解一个系统的基本依据。那么,一个新的问题是:哪些视角可以作为全面描述一个系统架构的最核心视图呢?Philippe Kruchten也给出了答案。

1995年,Philippe Kruchten在IEEE Software上发表了论文“4+1架构视图模型(The 4+1 View Model of Architecture)”,正式提出使用场景视图、逻辑视图、开发视图、进程视图和物理视图五个方面来描述架构设计,引起了业界的极大关注,并最终被后来隶属于IBM的Rational软件公司统一软件开发过程方法论(Rational Unified Process,简称RUP)所采纳,如图1-5所示。

图1-5

在4+1视图模型中,不同架构视图承载不同的架构设计决策,支持不同的目标和用途。

著名架构师温昱在“运用RUP 4+1视图方法进行软件架构设计”一文中对这5个视图进行了解释和总结。

用例视图(Use Cases View):最初称为场景视图,关注最终用户需求,为整个技术架构的上下文环境,通常用UML用例图和活动图描述。

逻辑视图(Logical view):主要是整个系统的抽象结构表述,关注系统提供最终用户的功能,不涉及具体的编译即输出和部署,通常在UML中用类图、交互图、时序图来表述,类似于我们采用OOA的对象模型。

开发视图(Development View):描述软件在开发环境下的静态组织,从程序实现人员的角度透视系统,也叫作实现视图(Implementation View)。开发视图关注程序包,不仅包括要编写的源程序,还包括可以直接使用的第三方SDK和现成框架、类库,以及开发的系统将运行于其上的系统软件或中间件,在UML中用组件图、包图来表述。开发视图和逻辑视图之间可能存在一定的映射关系:比如逻辑层一般会映射到多个程序包等。

进程视图(Process view):进程视图关注系统动态运行时,主要是进程及相关的并发、同步、通信等问题。进程视图和开发视图的关系:开发视图一般偏重程序包在编译时期的静态依赖关系,而这些程序运行起来之后会表现为对象、线程、进程,进程视图比较关注的正是这些运行时单元的交互问题,在UML中通常用活动图表述。

物理视图(Physical view):物理视图通常也叫作部署视图(Deployment View),从系统工程师的角度解读系统,关注软件的物流拓扑结构,以及如何部署机器和网络来配合软件系统的可靠性、可伸缩性等要求。物理视图和处理视图的关系:处理视图特别关注目标程序的动态执行情况,而物理视图重视目标程序的静态位置问题;物理视图是综合考虑软件系统和整个IT系统相互影响的架构视图。

概括来说,我们可以从场景视图的功能需求、逻辑视图的对象与交互、进程视图的进程与通信、开发视图的项目开发组织结构、物理视图的网络与机器部署结构这五个方面来描述一个系统的架构设计,并形成文档、设计图等设计输出物,用于指导后续的软件实现、测试、部署与维护等过程。