软件架构模式之第二章:架构结构和风格
Figure 2-1. Monolithic architectures are single deployment units
尽管成本和简单性是单体架构的主要优点,但其可伸缩性、容错性和弹性等操作特性却存在一些弱点。在单体架构中,一个致命错误(如内存不足)会导致所有功能都失败。此外,平均恢复时间(MTTR)和平均启动时间(MTTS)通常以分钟为单位计算,这意味着应用程序需要很长时间才能重新启动一旦发生故障。这种长时间的启动也会对可伸缩性和弹性产生影响。虽然有时可以通过负载平衡来实现应用程序的部分可伸缩性,但整个应用程序的功能必须具备伸缩能力,即使只有其中一小部分需要进行伸缩。这种做法不仅效率低下,而且成本高昂且无必要。
单体架构风格的示例包括分层架构(第3章描述)、模块化单体、管道架构和微核架构(第4章描述)。
分布式架构
按照字面意义,分布式架构由多个部署单元组成,这些单元协同工作以实现某种内聚的业务功能。在当前世界中,大多数分布式架构都由服务组成,尽管每种分布式架构风格都有自己正式的服务名称。图2-2展示了一个典型的分布式架构。
Figure 2-2. Distributed architectures consist of multiple deployment units
分布式架构的超能力通常体现在操作特性上,比如可伸缩性、弹性和容错,有时还包括性能。这些架构风格的可伸缩性通常是以单个服务为单位进行衡量的,弹性也是如此。因此,在处理故障时,MTTS(Mean Time to Service)和MTTR(Mean Time to Recovery)相较于单一应用程序要小得多,并且通常以秒甚至毫秒来计算。分布式架构非常适合支持高水平的容错。当一个服务发生故障时,在许多情况下其他服务可以继续正常提供服务而不受影响。即使某个服务真正失败了,它也可以迅速恢复——快到用户可能都察觉不到该服务曾经发生过致命错误。敏捷性(对变化快速响应的能力)通常也是分布式架构所具备的优势之一。由于应用程序功能被划分为独立部署的软件单元,因此更容易定位和实施变更,并且测试范围仅限于受影响的服务,从而显著降低了部署风险。然而,与所有这些优点相伴随而来的是一些问题存在。“分布式计算谬论”困扰着分布式架构领域,即我们认为关于网络和分布式计算方面八个事实其实并非完全正确。“网络是可靠的”、“带宽无限大”和“延迟为零”等假设既使得保持确定性成为挑战,同时也很难达到完全可靠。事实上网络确实会出现故障、带宽并非无限大、延迟亦不可能为零。这些问题在今天依然存在,并且与90年代末被创造出来时一样真实。
除了分布式计算的八大谬论之外,分布式架构还带来了其他一系列困难。其中包括分布式事务、最终一致性、工作流管理、错误处理、数据同步和契约管理都是分布式架构不可避免的部分。更重要的是,与单体架构相比,整体实现和持续维护成本通常会显著增加。当我们考虑到所有这些权衡时,突然间那些强大的超能力似乎也不再那么令人向往了。分布式架构的例子包括事件驱动架构(第5章描述)、广受欢迎的微服务架构(第6章描述)、基于服务和面向服务的架构以及基于空间的架构(第7章描述)。
我应该选择哪一个?
在为你正在创建的系统选择单体架构或分布式架构时,首先需要考虑系统是否需要支持不同的架构特征集。换言之,整个系统是否需要具备伸缩性和高可用性,或仅需部分功能满足这些要求?包含多组不同架构特征的系统通常适合采用分布式架构。一个典型例子是面向客户功能需要具备可伸缩性、响应性、可用性和敏捷性等特点,而管理或后端处理功能则无需这些特征中的任何一个。简单的系统或网站通常可以采用更简洁且成本效益更高的单体架构风格,而执行多种业务功能的复杂系统则通常需要更为复杂的分布式架构。此外,“对速度要求”的场景、对高容量可伸缩性以及高容错性需求都适合采用分布式架构。
架构分区
除了按照单体或分布式进行划分,架构还可以根据系统整体结构的分类方式进行划分。无论是单体架构还是分布式架构,都可以通过技术划分或域划分来实现。接下来的几节将详细描述这些不同的划分结构之间的区别,并解释它们的重要性。
技术分区
技术分区架构是根据技术用途组织系统组件的一种架构。典型例子是分层(n层)架构风格(参见第3章)。在这种架构风格中,组件按照技术层次进行划分,例如表示层组件与用户界面相关、业务层组件与业务规则和核心处理相关、持久层组件与数据库交互、以及包含系统数据的数据库层。需要注意的是,在图2-3中,任何给定域的组件都会分布在所有这些技术层上。举例来说,客户域功能以客户界面形式存在于表示层,在业务逻辑方面驻留在业务层,在查询方面驻留在表示层,并将客户表格存储在数据库层。这些组件通过命名空间进行了如下结构化:app.presentation.customer、app.business.customer、app.persistence.customer等。请注意,命名空间中的第二个节点指明了技术分区,并将客户表格作为一个单独的组件处理。而客户节点则跨越了各个不同的技术分区。
Figure 2-3. In a technically partitioned architecture, components are grouped by their technical usage
如果大部分更改都被隔离到应用程序中特定的技术区域,那么在技术层面上进行分区的体系结构是非常有益的。例如,当您不断调整用户界面的外观和感觉时,并未对相应的业务规则进行修改,这种变化仅限于体系结构中的一部分(在本例中为表示层)。同样地,如果您持续变更业务规则而不影响数据层或表示层,则该变化将局限于体系结构中的业务层,并且对系统其他部分没有任何影响。然而,请设想一下,在技术上划分区域架构中实现一个新需求,即向客户愿望列表项目添加过期数据。这类变更被视为基于领域而非技术使用方面的改动,并会影响到体系结构所有层次。要实现此类变更,您需要在数据库层向愿望列表表添加新列,在持久化层更新相应SQL语句,在业务逻辑组件中加入相关业务规则,在数据库层新增一个表格以及在持久化层修改与业务逻辑和表示层之间契约关系等等。根据系统规模和团队结构不同,这个简单改动可能需要三至四个不同团队协作完成。技术上划分区域架构包括了分层架构(第3章)、微内核架构(第4章)、管道架构、事件驱动架构(第5章)以及基于空间概念的架构(第7章)。尤其值得注意微内核架构因其插件组件使用方式既可进行技术上划分也可进行领域划分而显得十分有趣。例如,当插件组件用作适配器或特殊配置设置时,则可以将其视为技术上划分类别。
领域分区
与技术分区架构不同,领域分区架构中的组件是根据领域划分而非技术使用进行组织。这意味着所有功能(表示、业务逻辑和持久性逻辑)都被分组到应用程序的单独领域和子领域区域中。对于领域分区架构,可以通过命名空间结构来表示各个组件,例如app.customer、app.shipping、app.payment等。需要注意的是第二个节点代表的是领域而非技术层次。实际上,如果需要,可以进一步将领域按照技术层次进行组织,例如app.customer.presentation、app.customer.business等形式。值得注意的是,即使客户端逻辑可能会根据技术使用进行组织,在主要结构(以命名空间第二个节点表示)仍然按照领域划分。图2-4展示了一个典型的领域分区架构示例。
经过多年的发展,域分区架构越来越受到欢迎。其中一个原因是由于对域驱动开发方法的使用和接受程度的提高。领域驱动设计强调领域设计而非复杂的工作流和技术组件。这种方法使团队能够与领域专家密切合作,专注于系统关键部分的开发,并且能够开发出与领域能力相似的软件。
Figure 2-4. In a domain partitioned architecture, components are grouped by domain area
领域划分架构具有明显的优点,即特定领域或子领域的更改在系统中被自包含地限制在特定区域内,使得团队能够准确确定需要修改的系统部分。以客户愿望清单项目实现过期数据为例,通过采用领域划分,代码修改仅局限于系统的一小部分,相比技术划分而言更加高效。例如,在这种情况下,修改将被隔离到以app.customer.wishlist开头的命名空间中,这意味着表示逻辑、业务逻辑和持久性逻辑都位于系统同一区域内。完成此类修改时维护更容易、测试更简便且部署风险较小。领域划分架构示例包括微核架构(第4章)、微服务架构(第6章)、模块化monolith架构和基于服务的架构。正如前文所述,微核架构可以是技术划分也可以是领域划分。如果插件组件基于微核架构,则其可视为技术划分或者领域划分。若通过添加功能来扩展应用程序,则该应用程序将被视为遵循了一个领域划分体系结构。
我应该选择哪一个?
技术分区架构和领域分区架构之间的选择是一个重要问题。为了成功和有效,架构的整体结构不仅必须与团队结构保持一致,还必须与系统中预期的变更类型相匹配。当整体团队结构采用相同的技术领域组织时,无论是单一还是分布式的技术分区架构都非常适合。例如,如果开发团队由用户界面开发人员、后端开发人员和数据库开发人员组成,则技术分区架构将成为理想选择,因为团队结构与技术层次上的架构相匹配。而当大部分变更与技术层次相关时(如多个用户界面、系统外观和感觉改变、替换数据库等),也自然而然地选择了技术分区架构。
如果您正在着手开发一个新系统并采用领域驱动设计方法,则应考虑使用领域分区架构。此外,如果您的团队以跨功能专业化方式组织起来(即包含用户界面开发人员、后端开发人员和数据库开发人员等特定领域功能在同一物理团队中),则领域划分架构非常适合。
当你期望大部分的变化发生在领域范围而非技术使用范围时,选择领域划分架构是一个不错的选择。相较于技术驱动设计架构,它具有更好的灵活性,能够快速响应变化。然而,如果你对技术层面有许多改变需求时,在选择领域驱动设计架构时需要谨慎。例如,在领域驱动设计架构中替换数据库类型或改变整个用户界面框架都将是一项困难且耗时的任务。
本文来自博客园,作者:阳光底下没有秘密,转载请注明原文链接:https://www.cnblogs.com/areswien/p/18010820