架构模式指南-全-
架构模式指南(全)
原文:
zh.annas-archive.org/md5/c89a9bf04617b8818ff7f0cd5be49990译者:飞龙
前言
异构性以及多重因素导致任何系统开发和运营的复杂性增加。神秘而典范的软件工程(SE)领域正被无数和异构的技术和工具所填充和夹击。它们的使用似乎有点挑战性,但如果正确使用,它们的贡献确实是迷人的和迅速的。
令人感兴趣的是,我们个人、专业和社会环境中的每一种资产和物品正被先锋软件库所嵌入和强化。随着软件的不断渗透和参与我们接触、感受和使用的一切,我们将拥有大量复杂和智能的应用程序。确切地说,我们正朝着承诺的软件定义世界迈进。然而,下一代软件应用的开发和运营复杂性实际上是非常威胁的。也就是说,利用软件工程领域的各种美味进步实际上变成了一项困难的事情。因此,迫切需要挖掘易于理解和使用的途径来减轻软件工程复杂性。
技术专家、倡导者和传教士强调,强调、吸收和阐述适用于高质量软件实施和交付的架构原理,是摆脱这一困境的可行途径。优雅地运用架构模式,以及设计、部署、集成和其他专业模式,是生产和管理下一代软件解决方案的前进之路。软件模式(架构、设计、部署、集成等)的宝库对于生产高度可靠、可扩展、可用、性能良好、适应性强的安全软件系统非常有用。本书的编写目的仅在于列举和表达对读者来说突出和占主导地位的软件模式。各个章节及其独特的贡献在此简要说明。
本书涵盖的内容
第一章,《揭秘软件架构模式》,阐述了本书的背景并描述了软件模式的需求。各种架构模式被列出并详细解释,以便传达架构模式的是什么、为什么、在哪里和如何。
第二章,《客户端/服务器多层架构模式》,涵盖了客户端/服务器架构模式,这是企业架构空间中最古老的模式之一。在这个架构空间中有几种变体,例如两层客户端/服务器架构模式、三层模式和n层模式。随着企业架构中几种新型架构的发展,客户端/服务器架构在企业架构中已经退居次要位置。本章的第二部分涵盖了 Web 应用模式。本章涵盖的 Web 应用模式的关键类型是 MVC、MVP 和 MVVM。本章还提供了每种模式类型的几个示例。
第三章,《面向对象软件工程模式》,涵盖了面向对象(OO)软件工程模式。本章旨在为您复习面向对象设计原则和最佳实践的基础知识。我们相信,面向对象编程模式是现代软件设计范式的基础,并有助于您更好地理解其他模式。本章涵盖了各种突出的创建型、结构型和行为型 OO 模式,以及如半同步/半异步、领导者/跟随者等并发架构模式。
第四章,《企业集成模式》,描述了各种企业集成模式。在现代社会,有大量的商业应用程序。其中一些是现成的商业应用程序,而另一些则是根据组织需求定制的遗留应用程序。由于企业内部存在如此多的应用孤岛,因此确保它们无缝工作变得必要。本章涵盖了可用于企业集成的关键模式。本章涵盖的企业集成模式的关键类型是消息模式、移动集成模式和 API 管理模式。
第五章,《领域驱动设计(DDD)原则与模式》,阐述了领域驱动设计(DDD)的原则和模式。本章帮助您了解 DDD 原则、实践以及一些关键模式,以及它们如何支持将技术与商业卓越结合在一起以创建复杂的软件。我们关注领域、通用语言通信、边界上下文、聚合以及更多 DDD 方面。本章涵盖了几个关键和突出的 DDD 模式,以帮助您了解战略、战术、遗留系统集成、分布式上下文,以及了解两种新兴模式:领域事件和事件溯源。
第六章,《企业架构平台和工具》,展示了企业架构平台和工具的独特功能。企业架构有助于将企业中所有与软件相关的流程映射到一个框架中,以便满足企业的所有目标。本章讨论了在 IT 行业景观中广泛使用的两个突出企业架构框架:TOGAF 和 Zachman 框架。本章还讨论了一些突出的架构平台和工具,如 Enterprise Architect、Dragon 和 Abacus。
第七章,《面向服务的架构(SOA)》,揭示了流行的面向服务的架构(SOA)模式,这些模式可以产生面向服务的应用程序。本章提供了关于 SOA 原则、最佳实践和特性的详细信息。你还将了解处理 Web 服务安全、服务间通信、消息传递、服务版本化和服务重构的最常见 SOA 模式。本章还包含一个表格,帮助你理解各种模式和它们相关的 SOA 原则。
第八章,《事件驱动架构模式》,涵盖了新兴和演变的事件驱动架构模式。现代组织本质上是敏捷的,希望采用允许它们以敏捷方式工作的架构风格。事件驱动架构模式主要是为了满足这一需求而开发的。本章全面介绍了流行的事件驱动模式。本章还讨论了事件驱动架构领域的新趋势。
第九章,《微服务架构模式》,解释了各种微服务架构(MSA)。随着容器化技术的广泛应用,微服务在构建企业级、弹性、可扩展和动态应用中的角色和责任必将增加。书中详细介绍了各种架构和设计模式,以及相应的用例。
第十章,《容器化和高可靠性应用模式》,讨论了各种设计模式在构建容器化和高可靠性应用中的独特贡献。容器化和微服务的融合,以及各种容器和集群管理及编排平台的到来,保证了实现高度弹性的微服务,进而导致可靠的应用程序的产生。
第十一章,软件定义云 - 架构与设计模式,提供了关于云应用架构及其各种设计模式的信息。众所周知,各种遗留和单体应用正在现代化并迁移到云环境中。本章规定了如何巧妙地利用模式以实现快速而明智的云采用。
第十二章,大数据架构与设计模式,为您提供了大数据架构模式和大数据设计模式的前瞻性指导。这些模式按层级分组,例如数据摄取层、数据存储层和数据访问层,以帮助您了解涉及数据源、数据消息传递、数据分析以及消费的统一架构。本章涵盖的一些突出模式包括数据湖、lambda 架构、工作负载模式的简短总结、多语言和连接器。本章还涵盖了大数据的一些基本概念。
您需要本书的内容
在开始本书之前,没有具体的要求。您将在阅读章节的过程中找到所有所需的信息。
本书面向的对象
本书将赋予并丰富 IT 架构师(如企业架构师、软件产品架构师、解决方案和系统架构师)、技术顾问、传教士和专家的权力和财富。
惯例
在本书中,您会发现多种文本样式,用于区分不同类型的信息。以下是一些这些样式的示例及其含义的解释。
文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称如下所示:“我们可以通过使用include指令来包含其他上下文。”
代码块设置如下:
package main
import "fmt"
// this is a comment
func main() {
fmt.Println("Hello World")
}
当我们希望您注意代码块中的特定部分时,相关的行或项目将以粗体显示:
package main
import "fmt"
// this is a comment
func main() {
fmt.Println("Hello World")
}
任何命令行输入或输出都写作如下:
docker run --rm -ti -v $(pwd):/go/src/myapp google/golang go build myapp
新术语和重要词汇以粗体显示。
警告或重要注意事项如下所示。
小贴士和技巧看起来像这样。
读者反馈
我们欢迎读者的反馈。请告诉我们您对本书的看法——您喜欢或不喜欢的地方。读者反馈对我们来说很重要,因为它帮助我们开发出您真正能从中获得最大价值的标题。要发送一般反馈,请简单地发送电子邮件至feedback@packtpub.com,并在邮件主题中提及本书的标题。如果您在某个主题领域有专业知识,并且对撰写或为本书做出贡献感兴趣,请参阅我们的作者指南www.packtpub.com/authors。
下载本书的颜色图像
我们还为您提供了一个包含本书中使用的截图/图表的颜色图像的 PDF 文件。这些彩色图像将帮助您更好地理解输出的变化。您可以从www.packtpub.com/sites/default/files/downloads/ArchitecturalPatterns_ColorImages.pdf下载此文件。
勘误
尽管我们已经尽最大努力确保内容的准确性,错误仍然可能发生。如果您在我们的书籍中发现错误——可能是文本或代码中的错误——如果您能向我们报告这一情况,我们将不胜感激。通过这样做,您可以帮助其他读者避免挫败感,并帮助我们改进本书的后续版本。如果您发现任何勘误,请通过访问www.packtpub.com/submit-errata,选择您的书籍,点击勘误提交表单链接,并输入您的勘误详情来报告它们。一旦您的勘误得到验证,您的提交将被接受,勘误将被上传到我们的网站或添加到该标题的勘误部分下的现有勘误列表中。要查看之前提交的勘误,请访问www.packtpub.com/books/content/support,并在搜索字段中输入书籍名称。所需信息将出现在勘误部分下。
盗版
互联网上版权材料的盗版是一个跨所有媒体的持续问题。在 Packt,我们非常重视我们版权和许可证的保护。如果您在互联网上遇到任何形式的我们作品的非法副本,请立即向我们提供位置地址或网站名称,以便我们可以寻求补救措施。请通过发送链接到疑似盗版材料至copyright@packtpub.com与我们联系。我们感谢您在保护我们作者和我们为您提供有价值内容的能力方面的帮助。
问题
如果您对本书的任何方面有问题,您可以通过questions@packtpub.com联系我们,我们将尽力解决问题。
第一章:揭秘软件架构模式
这将是软件定义的、数字化驱动的、云托管的、上下文感知的、面向服务的、事件驱动的和以人为本的时代。众所周知,反应性和认知软件在塑造预期的和明确的知识密集型服务和应用时代中起着非常重要的作用。也就是说,我们需要高度响应、可靠、可扩展、自适应和安全的软件套件和库来满足即将到来的知识时代的目标。有能力的信息和通信技术(ICTs)、工具、技术和技巧正在迅速出现和演变,以艺术地实现这类高级和精明的软件模块的实现。
模式领域的快速扩大已经存在了几十年。软件工程的复杂性也在无节制地增加。软件专家、传教士和倡导者已经阐述了软件模式在减轻软件工程日益增长的复杂性方面的巧妙和决定性的优势。因此,软件模式被广泛认为是构建弹性且多功能的软件包和程序的一种主要且至关重要的方法。专业人士和教授们一直在稳步挖掘新的模式。因此,大量开创性和有前景的架构、设计、部署、交付和集成模式正在迅速出现和演变,以加快和简化设计、开发、调试、部署和交付稳健且有益的软件应用的过程。
本章旨在解释突出的软件模式,特别是以下广泛讨论和详细说明的架构模式:
-
面向对象的架构(OOA)
-
基于组件的组装(CBD)架构
-
领域驱动设计架构
-
客户/服务器架构
-
多层分布式计算架构
-
分层/分层架构
-
事件驱动架构(EDA)
-
面向服务的架构(SOA)
-
微服务架构(MSA)
-
基于空间的架构(SBA)
-
专用架构
展望软件定义的世界
现在存在新的需求,如智能家居、酒店、医院等,而满足不断变化的企业和人们需求的信息和通信技术(ICT)的关键作用和责任正在稳步增长。目前,在神秘的 ICT 领域正在发生许多值得注意的趋势和转变。其中突出的包括以下内容:
-
通过云计算实现 IT 工业化
-
通过虚拟化和容器化实现 IT 分区
-
通过手持设备、可穿戴设备、手机、游牧设备等实现 IT 消费化
-
通过物联网(IoT)、网络物理系统(CPSs)等技术,各种物理、电气、机械和电子系统之间的极端和深层连接
-
认知 IT 使我们的日常系统能够认知其行为和反应
随着一切事物相互连接,生成、收集、清洗和处理的 数据量呈指数级增长。有集成平台用于大数据、快速、流式和物联网数据分析,以从数据堆中提取有用信息和可操作见解。数据库范式正在经历一系列的变化和挑战。
中间件领域正在提高赌注,因为需要集成异构的多个系统和服务,并使它们协同工作。我可以继续说下去。简而言之,IT 和商业领域每天都在变化。此外,企业期望他们的 IT 服务提供商具有创新性、颠覆性和变革性,以便用更少的资源实现更多。随着全球企业正在削减 IT 预算,IT 领域必须选择最新的进步,以便对利益相关者来说是正确和相关的。
如往常一样,软件工程领域也在稳步进步,取得了令人瞩目的进展。有敏捷编程模型来促进商业敏捷性。在最近过去,有 DevOps 方法在萌芽,以确保 IT 敏捷性。有新的软件基础设施和平台解决方案正在迅速出现,以满足不同利益相关者的各种需求。专业人士和教授们正在加班加点,以确保流程卓越和基础设施优化。合理的架构范式和风格正在被吸收。进一步来说,随着人工智能(AI)方法的采用,自动化水平将提高并达到新的高度。
如我们所知,软件工程中最强大的领域一直都在为商业加速、增强和自动化做出巨大的贡献。随着物联网和 CPS 范式的到来和阐述,软件领域正在稳步而明智地转向人们期待已久的赋能。相应地,对软件应用和服务智能赋能业务运营和产品,以及为个人、创新者和机构的日常决策、交易和行动做出贡献的需求越来越大。目前可用的编程模型、框架和工具正在帮助我们生产满足功能需求的应用程序。从现在起,软件专业人士和从业者面临的关键挑战是提供符合所有类型的非功能性需求(NFRs)/服务质量(QoS)属性的软件库和套件。也就是说,我们应该构建能够确保各种能力(如可靠性、可扩展性、可用性、可修改性、可持续性、安全性等)的应用程序。软件模式在这里非常有用。确切地说,软件模式的渗透、参与和普遍性一直在持续增加。
软件模式
如我们所知,模式是一种简化和更智能的解决方案,用于解决任何重要领域中的重复问题和持续挑战。在软件工程领域,主要存在许多设计、集成和架构模式。这些模式在迅速克服软件架构师、开发人员和集成人员在日常任务和工作中遇到的一些常规和新鲜问题时非常有用。设计模式非常受欢迎,用于专业设计企业级软件系统,而架构模式则用于巧妙地决定正在开发中的系统的优化和组织架构。通过巧妙地利用各种架构模式,可以大大处理变化和复杂性。架构模式使得在技术选择和工具选择方面做出一系列决策成为可能。各种系统组件、它们的独特能力以及它们如何相互连接和协作是构建和设计下一代软件系统的关键要素。架构模式在这里提供了巨大的服务。随着系统架构变得越来越复杂,架构模式的作用和责任持续增加。同样,随着我们走向分布式和去中心化的时代,集成模式非常重要,因为它们带来了许多值得称赞的简化和委托。
随着 DevOps 概念的蓬勃发展,IT 敏捷性中出现了更多的新模式。这些模式也勤奋地加速了构建更新、更强大的软件包的过程。除了以开发为中心的模式外,还有特定于部署和交付的模式。在随后的 DevOps 和无操作(NoOps)时代,部署模式将极大地有利于自动化耗时且繁琐的任务。同样,还有交付能力模式。模式随着使用量的增加和持续的改进而快速演变和稳定。模式也能够帮助克服新技术初期的困难。模式将成为 IT 在市场驱动、知识驱动和残酷竞争环境中生存和发光的关键因素。确切地说,模式是通过对软件开发者的工作量进行最小化,在构建复杂软件时的关键推动力。通过精心使用经过验证的软件模式,构建企业级、高质量和基于微服务应用的风险正在得到实质性缓解。
为什么是软件模式?
在 IT 领域,尤其是软件工程领域,正在发生许多值得注意的变革。由于业务期望的持续演变,最近软件解决方案的复杂性不断上升。对于复杂的软件,不仅软件开发活动变得非常困难,而且软件维护和增强任务也变得繁琐且耗时。软件模式为软件架构师、开发人员和操作人员提供了一个舒缓的因素。
软件系统正变得越来越复杂和精密,以满足新的业务需求。软件架构领域有助于平滑和直化通往生产定义明确和设计良好的软件套件的道路。软件架构主要是为了调节不断上升的软件复杂性和变化。因此,有所谓的努力提出软件架构模式,以实现易于实施和可持续的软件架构。本节从一些关于架构的基本知识开始,然后详细阐述一些广泛使用的软件架构模式。
架构对于由于持续添加新模块而日益复杂的系统至关重要。架构通常由三个关键方面决定:参与组件、每个组件的独特能力,以及最终,这些组件之间的连接性。建立软件架构不是一项容易的工作。在决定架构时需要考虑各种因素。需要仔细考虑许多架构决策,以加强最终架构。不仅需要记录功能需求,还需要记录非功能需求。通常,架构模式是为了设计一个系统的通用架构,例如软件解决方案。
软件模式的精华成分
文献中用于描述模式的格式多种多样,没有一种格式得到了广泛的认可。以下描述的元素将在大多数模式中找到,即使使用不同的标题来描述它们。在 Opengroup.org 网站上,使用了以下术语:
-
名称(Name): 一个有意义且易于记忆的方式来引用模式,通常是单个单词或短语。
-
问题(Problem): 这是对当前问题的简明描述。它必须对预期达到的目标和目的提供一些启示。
-
上下文(Context): 上下文通常说明了在应用模式之前可以应用的先决条件。也就是说,这是在应用模式之前的初始状态描述。
-
力(Forces): 这用于描述相关的力和约束以及它们如何相互作用/冲突。它记录了预期的目标和目的。描述应阐明问题的复杂性,并明确必须考虑的权衡类型。力的概念大致等同于架构师寻求获得和优化的QoS 属性(可用性、可伸缩性、安全性、可持续性、可组合性、机动性、弹性、可靠性、可重用性等),除了他们在设计架构时试图解决的问题之外。
-
解决方案(Solution): 这全部关于清楚地解释如何实现预期的目标和目的。描述应识别解决方案的静态结构和动态行为。
-
结果上下文(Resulting context): 这表明在应用模式后的后置条件。实施解决方案通常需要在竞争的力之间进行权衡。该元素描述了哪些力已被解决以及如何解决,哪些仍未解决。它还可能表明在新上下文中可能适用的其他模式。
-
示例:这是关于包含一些模式的样本应用,以说明每个元素(一个具体问题、上下文、一组力量、模式如何应用以及结果上下文)。
-
理由:有必要对整个模式或其中个别组件给出令人信服的解释/论证。理由必须表明模式实际上是如何工作的,以及它是如何解决力量以实现预期的目标和目的。
-
相关模式:存在其他类似模式,因此必须明确阐述此模式与其他模式之间的关系。这些可能是前导模式,其结果上下文对应于本模式的初始上下文。或者,这些可能是后续模式,其初始上下文对应于本模式的结果上下文。还可能有替代模式,它们描述了相同问题的不同解决方案,但处于不同的力量之下。最后,这些可能是相互依赖的模式,可能/必须与该模式一起应用。
-
已知用途:这需要详细说明模式在现有系统中的已知应用。这是为了验证模式确实描述了一个针对重复问题的经过验证的解决方案。已知用途还可以作为增值示例。
模式也可能从一个摘要开始,概述模式的内容并指出它解决的问题类型。摘要还可以确定目标受众以及关于读者的假设。
软件模式的类型
为了满足不同的需求,正在出现几种新的模式类型。本节将简要介绍这些模式。
架构模式表达了一个复杂系统的基本结构组织或方案。它提供了一套预定义的子系统,指定了它们的独特责任,并包括组织它们之间关系的决策启用规则和指南。软件系统的架构模式展示了整个软件解决方案的宏观结构。架构模式是一组原则和粗粒度模式,为系统族提供了一个抽象框架。架构模式通过提供针对频繁出现的常见问题的解决方案来提高分区并促进设计重用。精确地说,架构模式由一组塑造应用程序的原则组成。
设计模式提供了一种改进系统子系统或组件,或它们之间关系的方案。它描述了一种常见且重复出现的通信组件结构,该结构在特定上下文中解决了一般设计问题。软件系统的设计模式规定了构建软件组件的方法和手段。设计模式阐述了系统内部的各种组件如何相互协作,以实现所需的功能。
还有其他模式。大数据时代的到来要求分布式计算。企业级应用的庞大和单体特性要求以微服务为中心的应用。在这里,需要找到并集成应用服务,以提供综合的结果和视图。因此,存在支持集成的模式。同样,还有简化软件部署和交付的模式。其他复杂操作通过智能利用简单以及复合模式得到解决。在下一节中,我们将讨论 IT 的各个维度,目的是传达软件模式对下一代 IT 的巨大影响。
软件架构模式
本节用于描述突出和主导的软件架构模式。
与单体应用相关联的几个弱点:
-
可伸缩性:单体应用设计为在单个强大系统内运行。提高应用的速度或容量需要升级到更新、更快的硬件,这需要大量的规划和考虑。
-
可靠性和可用性:单体应用中的任何故障或错误都可能使整个应用离线。此外,更新应用通常需要停机时间以重启服务。
-
敏捷性:随着新功能的不断添加,单体代码库变得越来越复杂,发布周期通常以 6-12 个月或更长时间来衡量。
正如之前提到的,遗留应用在本质上具有单体特性,规模庞大。将它们重构和修复为支持 Web、云和服务将消耗大量时间、金钱和人才。随着企业持续削减 IT 预算,同时期望 IT 团队以更少的资源做更多的事情,利用各种架构模式单独或集体准备和部署现代化应用的时机已经到来。以下各节详细介绍了各种有希望和潜在的架构模式。
面向对象架构 (OOA)
对象是所有软件应用的基本和基础构建块。任何软件应用的结构和行为都可以通过使用多个互操作对象来表示。对象优雅地以优化和有序的方式封装了各种属性和任务。对象通过定义良好的接口连接、通信和协作。因此,面向对象架构风格已成为生产面向对象软件应用的主导风格。最终,软件系统被视为一组协作对象的动态集合,而不是一系列例程或程序性指令。
我们知道,有经过验证的面向对象编程方法和使能语言,如 C++、Java 等。面向对象分析(OOA)提供的继承、多态、封装和组合属性在产生高度模块化(高度内聚和松散耦合)、可使用和可重用的软件应用中非常有用。
如果我们想要将逻辑和数据封装在一起,以便在可重用组件中使用,面向对象风格是合适的。此外,需要抽象和动态行为的复杂业务逻辑可以有效地使用这种面向对象分析(OOA)。
基于组件的组装(CBD)架构
单一和大规模应用可以被分割成多个交互和较小的组件。当组件被找到、绑定和组合时,我们就得到了完整的软件应用。组件成为设计和开发企业级应用的基础构建块。因此,复杂应用的分解和组件的组合以达到高效应用方面受到了很多关注。组件为其他组件提供了定义良好的接口,以便发现和通信。这种设置提供了比面向对象设计原则更高层次的抽象。CBA 不关注诸如通信协议和共享状态等问题。组件是可重用的、可替换的、可替代的、可扩展的、独立的,等等。依赖注入(DI)模式或服务定位器模式等设计模式可以用来管理组件之间的依赖关系,促进松散耦合和重用。这些模式通常用于构建组合应用,这些应用结合并重用了跨多个应用中的组件。
面向方面编程(AOP)方面是另一个流行的应用构建块。通过巧妙地操作这个开发单元,可以构建和部署不同的应用。AOP 风格旨在通过允许分离横切关注点来增加模块化。AOP 包括支持在源代码级别关注点模块化的编程方法和工具。面向方面编程包括将程序逻辑分解成不同的部分(关注点,功能的一致区域)。所有编程范式本质上都通过提供抽象(例如,函数、过程、模块、类、方法等)来支持将关注点分组和封装到独立实体中。这些抽象可以用于实现、抽象和组合各种关注点。有些关注点无论如何都会跨越程序中的多个抽象,并违反这些实现形式。这些关注点被称为横切关注点或横向关注点。
记录日志是一个横切关注点,因为日志策略必然影响系统中的每个记录部分。因此,日志横切了所有记录的类和方法。简而言之,方面被表示为横切关注点,并且根据需要注入。通过关注点的分离,源代码的复杂性急剧下降,编码效率必然提高。
面向代理的软件工程(AOSE)是一种编程范式,其中软件的构建以软件代理的概念为中心。与核心是具有变量参数方法的对象的经过验证的面向对象编程相比,面向代理编程以具有接口和消息能力的外部指定的代理为核心。它们可以被认为是对象的抽象。交换的消息由接收代理以特定于其代理类的方式解释。
软件代理是一个持久、目标导向的计算机程序,它对其环境做出反应,无需持续的直接监督即可运行以执行为最终用户或另一个程序的功能。软件代理是自主机器人的计算机模拟。有一些特定的应用和行业垂直领域需要软件代理的独特服务。因此,我们有软件对象、组件、方面和代理作为构建各种不同能力应用的流行软件构造。
领域驱动设计(DDD)架构
领域驱动设计(DDD)是一种面向对象的方法,用于根据业务领域、其元素和行为以及它们之间的关系来设计软件。它旨在通过定义以业务领域专家的语言表达的领域模型,实现软件系统对底层业务领域的正确实现。领域模型可以被视为一个框架,从该框架中可以准备和合理化解决方案。
架构师必须对要建模的业务领域有很好的理解。开发团队往往与业务领域专家合作,以精确和完美的方式建模领域。在这方面,团队同意只使用一种专注于业务领域的单一语言,排除任何技术术语。由于软件的核心是领域模型,它是这种共享语言的直接投影,这使得团队能够通过分析其周围的语言来快速找到软件中的差距。DDD 过程不仅旨在实现所使用的语言,还旨在改进和精炼领域语言。这反过来又有利于正在构建的软件。
如果我们有一个复杂的领域并且希望提高开发团队内部的沟通和理解,DDD 是很好的。如果我们的企业数据场景庞大且复杂,难以使用现有技术管理,DDD 也可以是一个理想的方法。
客户端/服务器架构
此模式将系统分为两个主要应用,其中客户端向服务器发出请求。在许多情况下,服务器是一个数据库,应用逻辑以存储过程的形式表示。此模式有助于设计涉及客户端系统、服务器系统和连接网络的分布式系统。客户端/服务器架构的最简单形式涉及一个服务器应用程序,它被多个客户端直接访问。这被称为两层架构应用程序。Web 和应用服务器扮演服务器角色,以接收客户端请求、处理它们并将响应发送回客户端。以下图是客户端/服务器模式的图示:

对等网络(P2P)的应用模式允许客户端和服务器交换它们的角色,以便在多个客户端之间分发和同步文件和信息。每个参与系统都可以扮演客户端和服务器角色。它们只是朝着实现业务功能的目标工作的对等体。它通过多个对请求的响应、共享数据、资源发现和对对等体移除的弹性扩展了客户端/服务器风格。
客户端/服务器架构模式的优点主要包括:
-
更高的安全性:所有数据都存储在服务器上,这通常比客户端机器提供更大的安全控制。
-
集中式数据访问:因为数据只存储在服务器上,所以对数据的访问和更新比其他架构风格更容易管理。
-
易于维护:服务器系统可以是单台机器或由多台机器组成的集群。服务器应用程序和数据库可以运行在单台机器上,或者跨多台机器复制以确保易于扩展性和高可用性。通过适当的网络,多台机器最终形成一个集群。最近,企业级服务器应用程序由多个子系统组成,每个子系统/微服务可以在集群中的单独服务器机器上运行。另一个趋势是每个子系统及其实例也正在被托管并在多台机器上运行。这种利用单个或多个服务器机器来执行服务器应用程序和数据库的做法确保了客户端对服务器维修、升级或迁移一无所知且不受影响。
然而,传统的两层客户端/服务器架构模式有许多缺点。首先,将应用程序和数据都保存在服务器上的趋势可能会对系统的可扩展性和可伸缩性产生负面影响。服务器可能成为单点故障。可靠性是这里的主要担忧。为了解决这些问题,客户端/服务器架构已经演变成更通用的三层(或 N 层)架构。这种多层架构不仅克服了上述问题,还带来了一系列新的好处。
多层分布式计算架构
两层架构既不灵活也不可扩展。因此,多层分布式计算架构吸引了大量关注。应用程序组件可以部署在多台机器上(这些机器可以是本地部署和地理分布的)。应用程序组件可以通过消息或远程过程调用(RPCs)、远程方法调用(RMIs)、通用对象请求代理架构(CORBA)、企业 Java 豆(EJBs)等方式进行集成。应用程序服务的分布式部署确保了高可用性、可扩展性、可管理性等。Web、云、移动和其他面向客户的应用程序都是使用这种架构进行部署的。
因此,根据业务需求和应用程序的复杂性,IT 团队可以选择简单的两层客户端/服务器架构或高级的多层分布式架构来部署他们的应用程序。这些模式旨在简化软件应用程序的部署和交付给订阅者和用户。
分层/层架构
这种模式是客户端/服务器架构模式的改进。这是最常用的架构模式。通常,一个企业级软件应用包含三个或更多层:表示/用户界面层、业务逻辑层和数据持久层。为了实现与第三方应用/服务的集成,可以轻松地在分层架构中添加额外的层。后端主要是数据库管理系统,中间层涉及应用和 Web 服务器,表示层主要是用户界面应用(胖客户端)或 Web 浏览器(瘦客户端)。随着移动设备的快速普及,移动浏览器也被附加到表示层。这种分层隔离在管理和维护每一层时非常有用。这种方法的插件和即插即用功能得到了实现。根据需要,可以添加额外的层。有许多符合模型-视图-控制器(MVC)模式框架,极大地简化了企业级和 Web 规模应用。MVC 是一种 Web 应用架构模式。分层架构的主要优势是关注点的分离。也就是说,每一层可以专注于其角色和责任。分层和分层模式使应用:
-
易于维护
-
可测试性
-
容易分配特定的和独立的角色
-
容易单独更新和增强层
这种架构模式非常适合快速开发、无风险地开发 Web 规模、生产级和云托管的软件应用。当前和传统的分层应用可以很容易地在每一层使用新技术和工具进行修改。这种模式显著地调节和最小化了软件应用的开发、运营和管理复杂性。系统参与的不同组件的分区可以被其他合适的组件替换和替代。当出现业务和技术变化时,这种分层架构在嵌入新事物以满足不断变化的企业需求时非常有用。
如下图中所示,可以有多个层来满足各种需求。某些层可以被称作开放的,以便在某些特定请求中绕过。在图中,服务层被标记为开放。这意味着请求可以绕过这个开放的层,直接到达其下的层。现在业务层可以直接访问持久层。因此,分层方法非常开放和灵活。

简而言之,分层或分层方法必然能够调节软件应用日益增长的复杂性。此外,绕过某些层,灵活性可以轻松地被整合。根据需要,可以嵌入额外的层,以实现高度同步的应用。
事件驱动架构(EDA)
通常,服务器应用程序响应用户请求。也就是说,根据著名的客户端-服务器架构风格,请求和回复方法是客户端和服务器之间交互的主要方式。这是一种从服务器拉取信息的方式。通信也是同步的。在这种情况下,客户端和服务器都必须在线才能启动和完成任务。进一步来说,当服务器机器正在处理和执行服务请求时,请求服务/客户端必须等待从服务器接收预期的响应。这意味着客户端在等待接收服务器的响应时不能做任何其他工作。
世界最终正在变成事件驱动的。也就是说,应用程序必须积极主动、预先、精确地敏感和响应。每当发生事件时,应用程序必须立即接收事件信息并投入必要的活动。请求和回复概念为发送后即忘原则铺平了道路。通信变得异步。不需要参与的应用程序始终在线。
事件是指在任何商业内部或外部发生的值得注意的事情。事件可能表示一个问题、一个机会、一个偏差、状态变化或阈值突破。每个事件发生都有一个事件头和事件体。事件头包含描述事件发生详细信息的元素,例如规范 ID、事件类型、名称、创建者、时间戳等。事件体简洁而明确地描述了发生了什么。事件体必须包含所有正确和相关的信息,以便任何感兴趣的方都能及时使用这些信息采取必要的行动。如果事件没有完全描述,那么感兴趣的方必须回到源系统去提取增值信息。
EDA 通常基于异步消息驱动的通信模型,在整个企业中传播信息。它通过将业务活动描述为一系列事件,支持与组织操作模型的更自然对齐。EDA 不会将功能不同的系统和团队绑定到同一集中式管理模式中。EDA 最终导致高度解耦的系统。通过采用经过验证和潜在的 EDA,系统依赖性引入的常见问题正在得到消除。
我们已经看到了在不同领域使用的各种事件形式。有业务和技术事件。系统通过发出事件来更新其状态和条件,以便捕获并对其进行各种调查,以精确理解当前情况。提交网页表单和点击某些超文本会生成需要捕获的事件。增量数据库同步机制、RFID 读取、电子邮件消息、短信服务(SMS)、即时消息等事件不容忽视。可能存在粗粒度和细粒度事件。通常,粗粒度事件由多个细粒度事件组成。也就是说,粗粒度事件被抽象成业务概念和活动。例如,外部网站上发生了新的客户注册,订单完成了结账流程,贷款申请在承保阶段获得批准,市场交易完成,向供应商提交了履行请求,等等。另一方面,如基础设施故障、应用程序异常、系统容量变化和变更部署等细粒度事件仍然很重要。但它们的范围是局部和有限的。
存在事件处理引擎、面向消息的中间件(MoM)解决方案,如消息队列和代理,用于收集和存储事件数据和消息。通过这些 MoM 解决方案,可以收集、解析并通过多个主题传递数百万事件。当事件源/生产者发布通知时,事件接收者可以选择监听或过滤特定事件,并在实时中对下一步做什么做出主动决策。
EDA 风格建立在事件通知的基本方面之上,以促进即时信息传播和反应式业务流程执行。在 EDA 环境中,信息可以实时传播到所有服务和应用程序。EDA 模式使得高度反应式的企业应用程序成为可能。随着 EDA 模式的日益流行,实时分析已成为新常态。
Anuradha Wickramarachchi 在他的博客中写道,这是最常见的分布式异步架构。这种架构能够产生高度可扩展的系统。该架构由单一用途的事件处理组件组成,这些组件监听事件并异步处理它们。事件驱动架构中有两种主要拓扑结构:
- 调解器拓扑:调解器拓扑有一个单独的事件队列和一个调解器,它将每个事件引导到相关的事件处理器。通常,事件通过事件通道输入到事件处理器,以过滤或预处理事件。事件队列的实现可以是简单的消息队列,也可以是通过利用大型分布式系统的消息传递接口,这本质上涉及复杂的消息协议。以下图表展示了调解器拓扑的架构实现:

- 经纪人拓扑:这种拓扑不涉及事件队列。事件处理器负责获取事件、处理并发布另一个事件以指示结束。正如拓扑名称所暗示的,事件处理器充当经纪人以链式处理事件。一旦事件被处理器处理,就会发布另一个事件,以便另一个处理器可以继续。

如图表所示,一些事件处理器仅处理事件而不留下痕迹,而另一些则倾向于发布新事件。某些任务的步骤以回调的方式链式连接。也就是说,当一个任务结束时,回调被触发,所有任务仍然保持异步的本质。
突出的例子包括使用 JavaScript 编写网页。这个应用程序涉及编写对鼠标点击或按键等事件做出反应的小模块。浏览器本身协调所有输入并确保只有正确的代码看到正确的事件。这与所有数据通常通过所有层传递的分层架构非常不同。
EDA 的主要问题
EDA 模式缺乏事务的原子性,因为事件没有执行序列。这是因为事件处理器正在被实现为高度分布式、解耦和异步的。结果也预计将在未来某个时间通过回调提供。由于处理过程的异步性,对具有事件驱动架构的系统进行测试并不容易。最后,由于任务是异步和非阻塞的,执行是并行的,这保证了更高的性能。这种设置超过了队列机制的代价。
企业每天都会被大量简单和复杂的事件所轰炸,企业和云 IT 团队必须具备适当的事件捕获和处理引擎,以便采取纠正措施并在实时提供相关答案。众所周知的例子包括各种实时和现实世界的 IT 系统,例如贸易结算系统、航班预订系统、运输和物流公司的实时车辆位置数据、金融服务公司的流媒体股票数据等等。公司赋予这些系统处理大量复杂数据的能力,并能实时舒适地处理。
面向服务的架构(SOA)
我们一直在尝试面向对象、基于组件、面向方面和基于代理的软件开发流程。然而,随着服务范式的到来,软件包和库正被开发为一系列服务。也就是说,软件系统和它们的子系统越来越多地以服务的形式表达和暴露。服务能够在不依赖于底层技术的情况下独立运行。此外,服务可以使用任何编程和脚本语言来实现。
服务是自我定义的、自主的、互操作的,公开可发现、可评估、可访问、可重用和可堆肥的。服务通过消息相互交互。有服务提供者/开发者和消费者/客户端。有服务发现服务,这些服务天生利用私有和公共服务注册表和存储库。客户端服务可以通过服务发现服务动态地找到它们的服务。
每个服务都有两部分:接口和实现。接口是请求服务的单一接触点。接口在服务之间提供了所需的分离。所有类型的服务实现缺陷和差异都被服务接口所隐藏。为了使服务接口易于其他服务使用,使用一个定义消息结构的模式定义是一个好主意。当服务被多个其他服务使用时,使用合同正式化服务至关重要。合同将服务与模式、清晰的消息交换模式和策略绑定。策略定义了 QoS 属性,如可伸缩性、可持续性、安全性等。SOA 与客户端/服务器架构的区别在于,服务是普遍可用且无状态的,而客户端/服务器架构要求参与者之间紧密耦合。
具体来说,SOA 允许将应用功能作为一组服务提供,并创建利用软件服务的个人和专业应用程序。
基于服务的集成(SOI)
服务可以集成不同的分布式应用程序和数据源。企业服务总线(ESB)是服务中间件,它使得多个资产和资源的基于服务的集成成为可能。ESB 促进了服务互连、路由、修复、增强、治理等功能。ESB 是任何服务环境的集成中间件,其中消息是服务之间交互的基本单元。与之前的中间件解决方案(如 EAI 中心)相比,ESB 更轻量级。这是因为 ESB 消除了为集成流程/应用程序、数据源和 UIs 而使用定制连接器、驱动程序和适配器的需求。
让我们考虑一个示例场景。应用 A 只能将文件导出到特定目录,而应用 B 希望通过 HTTP 上的 SOAP 消息从导出的文件中获取一些信息。ESB 可以实现一个由应用 B 的 SOAP 请求消息触发的messsage flow,并使用文件适配器读取应用 A 导出文件中的请求信息。
ESB 收集所需信息并将其转换为符合约定 XML 模式的 SOAP 消息。然后,ESB 通过 HTTP 将 SOAP 消息发送回应用 B。
消息流是任何 ESB 解决方案的重要成分。消息流是一个定义,描述了消息的来源、如何到达 ESB,以及随后如何到达目标服务/应用程序。匹配是 ESB 提供的另一个突出功能。该功能规定了当消息到达 ESB 时,必须执行哪个消息流。
还有其他关键功能,包括路由、格式转换和消息格式转换。路由主要涉及将消息从一个服务路由到另一个服务。路由通常由消息流模块用来描述对于特定传入消息将调用哪个服务。第二个核心功能是协议转换。有许多应用程序和消息传输协议。ESB 可以将请求者协议转换为提供者兼容的协议。假设请求者支持 HTTP 协议,而提供者/接收者支持 FTP 协议。那么,ESB 的这个功能将 HTTP 协议转换为 FTP 协议,以便不同的分布式应用程序能够找到、绑定和交互。以下图是宏观层面的 SOA:

ESB 的最后一个核心功能是消息/数据格式转换。当请求者以 SOAP 格式发送消息时,ESB 可以使用 EDIFACT 消息格式调用提供者。此类消息格式转换背后的技术可以是经过验证的XML 样式表语言转换(XSLT)。
SOA 本质上是一组动态的服务集合,它们之间相互通信。这种通信可能涉及简单的数据传递,也可能涉及两个或更多服务协调某些活动。SOA 基于传统的请求-响应机制。服务消费者通过网络调用服务提供者,并必须等待提供者侧操作完成。回复以同步方式发送回消费者。
总之,异构应用程序在企业级和云 IT 环境中部署,以自动化业务操作、提供和输出。通过附加一个或多个接口,传统应用程序被服务化。通过将 ESB 置于中心,服务化应用程序可以轻松集成,以连接、通信、协作、证实和关联,从而产生预期的结果。简而言之,SOA 是为了实现单体和大规模应用程序的服务化和基于服务集成。通过智能利用服务范式,企业流程/应用程序集成的复杂性得到缓解。ESB 是使不同和分布式应用程序以无风险方式相互通信的最优中间件解决方案。
事件驱动的面向服务架构
今天,大多数 SOA 工作都热衷于实现同步请求-响应交互模式,以连接不同和分布式的流程。这种方法在高度集中的环境中效果良好,并在 IT 基础设施级别为分布式软件组件创建了一种松散耦合。然而,由于同步通信,SOA 导致应用程序功能紧密耦合。尽管如此,越来越多的企业环境正趋向于在交互、决策支持和执行方面实现动态和实时。SOA 模式可能难以确保下一代企业 IT 的压倒性需求。
如果需求仅仅是同步发送请求和接收响应,SOA 是一个不错的选择。但是,SOA 在处理异步实时事件方面还不够强大。这就是为什么事件驱动的 SOA 新模式,本质上结合了经过验证的 SOA 的请求-响应和 EDA 的事件发布-订阅范式,最近受到了很多关注和吸引力。也就是说,为了满足新引入的需求,需要这样的复合模式。这被吹捧为新一代 SOA(也被称为 SOA 2.0)。它基于异步消息驱动通信模型,在整个企业中传播各种企业级应用的信息。服务通过不同来源的事件被激活,结果的事件消息通过正确的服务传递以完成预定的业务操作。精确地说,参与和贡献的服务通过事件消息完全解耦并连接。在这个新模型中,各种依赖关系都被简单地消除了。
应用程序被设计、开发和部署得非常敏感且优雅,以实现高度响应。随着企业应用和大数据强制采用分布式计算模型,无疑事件驱动的 SOA 模式是未来的方向。通过这种新模式可以实现动态性、自主性和实时交互的目标。这种新的事件驱动 SOA 模式允许系统架构师和设计师处理事件消息和服务请求(RPC/RMI)。这使业务需求与相应的 IT 解决方案之间的亲和力和关联更加紧密。这不可避免地导致业务敏捷性、适应性、自主性和成本效益。
下面的图示说明了传统的请求-响应 SOA 风格。SOA 模式通常规定同步和基于拉取的方法:

下面的图示展示了面向消息、事件驱动、异步和非阻塞的过程架构:

EDA 的基本原则
在异步推送式消息模式中,EDA 模型基于发布/订阅模型,以“发射并遗忘”的方式向订阅的监听器推送各种实时通知和警报。这既不阻塞也不等待同步响应。此外,这是一个单向和异步的模式。
-
自主消息:事件以自主/自定义消息的形式进行通信。也就是说,每条消息只包含足够的细节来表示一个工作单元,这为通知接收者提供了决策能力。事件消息不应需要任何额外的上下文。它们也不应需要依赖于连接应用程序的内存会话状态。事件消息的简单目的是在企业内部传达每个应用程序、领域或工作组内每个应用程序的业务状态转换。
-
解耦和分布式系统:如前所述,EDA 模式在逻辑上解耦了连接的系统。SOA 保证松散和轻量级的耦合。也就是说,参与业务任务的应用程序不需要始终在线即可可用。中间件(ESB)负责在不引人注目的情况下将消息传递给目标应用程序。这里的问题是,发送系统必须知道目标应用程序的相关细节,以便在服务调用和处理完成时进行服务调用。
在同步 SOA 情况下,连接和依赖的系统通常需要满足各种非功能性要求/服务质量(QoS)属性,例如可伸缩性、可用性、性能等。但在异步 EDA 的情况下,一个系统的交易负载不需要影响或依赖于下游系统的服务级别。这种解耦带来的自主性允许应用架构师在设计各自的物理架构和容量规划时更加无忧无虑。解耦的系统可以独立部署,并且具有横向可伸缩性,因为参与模块之间没有依赖关系。
-
接收者驱动的流控制:EDA 模式将大部分控制流的责任从事件源(或发送系统)转移出去,并将其分配/委托给事件接收者。以 EDA 为中心的连接系统在决定是否进一步传播事件方面具有更多的自主性。支持这些决策的知识被分散到架构中的离散步骤或阶段,并封装在所有权所在的区域。以下图表是 SOA 和 EDA 模式的宏伟混合:

ED-SOA 组合模式的好处
单一应用程序将所有功能放入单个进程中。为了扩展,必须复制整个应用程序。然而,将应用程序划分为一组动态应用程序服务可以促进选择和复制一个或多个应用程序组件/服务以进行扩展。因此,分而治之的技术在日益复杂的软件工程世界中仍然发挥着重要作用。本节说明了 SOA 和 EDA 模式结合的其他好处。
-
有效的数据集成:在同步请求驱动架构中,重点是重用远程持有的功能并实现面向过程的集成。这意味着数据集成,作为集成环境的重要方面,在 SOA 环境中本质上是不支持的。但在 EDA 的情况下,数据集成本质上是通过事件数据/消息作为通信和协作的基本单元来完成的。
-
时效性和可靠性:事件在所有参与的应用程序中实时传播,以实现实时数据捕获、处理、决策和执行。事件数据/消息的及时交换使得运营系统能够获得最准确和最新的业务状态/情况视图。基于精确和完美数据的决策将会是正确和有信息的。
-
改进的可扩展性和可持续性:异步系统与同步系统相比,通常具有更好的可扩展性,这是一个事实。单个进程阻塞较少,对远程/分布式进程的依赖性较低。此外,中间件(消息队列和代理)可以设计得更加无状态,从而降低分布式系统的整体复杂性。较低的依赖性最终导致它们具有高度的可扩展性、可靠性/依赖性、弹性、响应性和可管理性。在解耦系统中,任何类型的替换、替代和进步都可以轻松执行。
因此,SOA 和 EDA 模式的良好结合能够产生实时、自适应和可扩展的企业。这种混合模式已经准备好带来无数的创新、颠覆和变革。
微服务架构(MSA)
我们已经讨论了 SOA 模式在建立和维持服务驱动的环境和企业方面的独特贡献。面向服务的架构模式经过几十年的发展,能够表达和暴露任何遗留的、单体和大规模应用程序作为动态的、相互依赖的服务集合。服务拥有接口和实现。接口是任何服务驱动的应用的接触和合同机制。有标准、语言、模型、框架、平台、模式和一系列工具包来引导服务范式达到其逻辑结论。尽管 SOA 为 IT 企业做了很多事情,但仍然存在一些问题、缺点和局限性。
流行的 SOA 风格主要依赖于具有多个层次的结构化数据模型。在 SOA 中共享数据库往往会在服务和系统组件之间创建一种紧密的数据耦合。这种紧密耦合阻碍了数据库中所需变化的实现。也就是说,如果一些 RESTful 服务与后端数据库紧密耦合,并且如果对数据库模式有任何变更要求并实施,那么就需要重新测试服务以验证和确认服务在更改后的模式上如何工作。这种依赖性对于日益自动化和动态的世界来说有点麻烦。
另一个挑战是,SOA 风格中的服务通常是粗粒度的,因此重用性方面相当棘手。大多数遗留应用程序的应用组件都配备了面向服务的接口,以实现发现、集成和交互。在基础设施层面,没有依赖问题,因为这些服务化的应用程序组件实际上可以在任何地方运行。没有共置的限制。SOA 使用一种分层的组织架构,其中包含一个用于服务调用、中介和协调的集中式消息中间件。但这里棘手的问题是,应用程序组件需要知道彼此的相应细节,以便启动并完成所需的协作、协调和关联。还有其他挑战与高度成熟和稳定的 SOA 范式相关联。
让我们转向 MSA 模式,它正在以跳跃式的速度发展。微服务架构是定义、设计、开发、部署和交付分布式和企业级软件应用的新架构模式。这种快速涌现和演变的模式被定位为易于快速实现任何软件应用的非功能性需求,如可伸缩性、可用性和可靠性。
MSA 模式旨在生成细粒度、松耦合、水平可扩展、独立部署、互操作、公开可发现、网络可访问、易于管理和可组合的服务,这不仅是最优化的软件构建单元,还允许实现更快的软件部署和交付。在过去,软件公司组建了大量的工程师团队来构建应用程序,随着时间的推移,这些应用程序变得庞大且难以控制。传统应用程序紧密、庞大、难以维护、缺乏灵活性,且不符合现代标准。我们需要的是能够适应、动态、开放、易于修改和增强的应用程序。在理解了 MSA 模式的独特贡献之后,全球的企业今天都在积极战略规划和策划,以清晰和自信地拥抱这一新模式。因此,企业级的云、移动和嵌入式应用程序正在使用强大且开创性的 MSA 模式来构建。
工具辅助编排加速了以微服务为中心的应用程序的生产过程。借助工具辅助编排,微服务被巧妙地编排,以产生适用于业务自动化、加速和增强的多功能应用程序。
微服务建立在被称为边界上下文的概念之上,这导致单个服务与其数据之间有一个自包含的关联。对于受 MSA 启发的应用程序而言,没有技术或供应商锁定。每个微服务都配备了其自己的数据源,这可能是一个文件系统、SQL、NoSQL、NewSQL、内存缓存等等。有 API 网关解决方案来简化微服务的端到端生命周期管理。微服务完全依赖于服务间的通信。每个微服务根据需要调用另一个微服务以完成其功能。此外,被调用的微服务可以在一个称为服务链的过程中有需要时调用其他服务。微服务使用一个非协调的 API 层来覆盖组成应用程序的服务。随着 Docker 容器成为微服务的最合适的运行时,MSA 模式最近受到了很多关注。
每个微服务都被设计成一个原子化和自给自足的软件组件。实现一个应用程序通常需要组合对这些单一职责和分布式端点的多次调用。虽然当请求者期望立即响应时需要同步请求-响应调用,但基于事件和异步消息的集成模式提供了最大的可扩展性和弹性。微服务方法与典型的大数据部署非常吻合。
通过在许多通用硬件服务器上部署服务,我们可以获得所需的模块化、广泛的并行性和成本效益的扩展。微服务模块化促进了独立更新/部署,并有助于避免单点故障,这有助于防止大规模中断。
事件驱动微服务模式
正如之前提到的,微服务架构风格是一种将应用程序作为一系列离散但自给自足的服务构建的方法,这些服务围绕特定的业务能力。以微服务为中心的应用程序现在可以启用事件驱动。一些有趣的架构模式正在迅速出现和演变。在本节中,我们将探讨事件流模式。
就像多语言和去中心化持久化一样,去中心化多语言消息方法应该是实现微服务架构预期成功的关键。这允许不同的服务组以自己的节奏开发。此外,它最大限度地减少了高度协调和风险大的大爆炸式发布的需要。微服务方法为开发者提供了更多灵活性,以便选择最佳的消息中间件解决方案。每个用例都将有其特定的需求,要求使用不同的消息技术,如 Apache Kafka、RabbitMQ,甚至是事件驱动的 NoSQL 数据网格,如 Apache Geode / Pivotal GemFire。
在 MSA 方法中,一个常见的架构模式是使用如 Kafka 或 MapR Streams 这样的只追加事件流进行事件源,MapR Streams 实现了 Kafka。使用 MapR Streams,事件被分组到称为主题的逻辑事件集合中。主题被分区以实现并行处理。我们可以将分区主题视为一个队列。事件按接收顺序交付。与队列不同,事件被持久化,即使在交付后,它们仍然位于分区上,可供其他消费者使用。根据流的生存时间设置自动删除旧消息;如果设置为零,则它们永远不会被删除。读取消息时不会从主题中删除消息,并且主题可以有多个不同的消费者。这允许不同消费者以不同目的处理相同的消息。
在消费者丰富事件并将其发布到另一个主题的情况下,也可以实现流水线:

随着微服务架构的快速传播、渗透和参与,将出现新的模式来解决其日益增长和普遍的问题和限制。此外,现有模式可以无缝结合,产生更大、更好的模式,以实现以微服务为中心的应用程序的实现。我们在第九章,《微服务架构模式》中详细介绍了架构和设计模式。
基于空间的架构(SBA)
通常,企业应用程序都会配备一个后端数据库管理系统。只要数据库能够跟上负载,这些企业级应用程序就能良好运行。但当使用量达到峰值,数据库无法跟上不断挑战的记录交易日志时,应用程序注定会失败。在任何高流量应用程序中,如果并发用户负载极大,数据库通常会成为我们能够同时处理的交易数量的最终限制因素。虽然各种缓存技术和数据库扩展产品有助于解决这些问题,但将普通应用程序扩展到极端负载仍然是一个非常困难的提议。
空间架构的设计目的是使软件系统即使在用户负载很重的情况下也能正常工作。这是通过在多个服务器之间分割处理和存储来实现的。数据分散在许多节点上。空间架构模式被广泛用于解决和解决可扩展性和并发性问题。面向客户的应用程序非常不可预测,这种专门的架构足够强大和智能,能够支持大量用户。
通过去除中心数据库约束并使用内存中数据网格进行复制,实现了高可扩展性。应用程序数据保存在内存中,并在所有活动处理单元之间进行复制。处理单元可以根据用户负载的增加和减少动态启动和关闭,从而解决可变可扩展性问题。因为没有中心数据库,所以去除了数据库瓶颈,在应用程序中提供了近乎无限的扩展性。符合这种模式的大多数应用程序都是标准网站,它们接收来自浏览器的请求并执行某种操作。一个拍卖网站就是很好的例子。该网站会不断通过浏览器请求接收来自互联网用户的出价。应用程序会收到特定商品的出价,记录该出价的时间戳,更新该商品的最新出价信息,并将信息发送回浏览器。
具体来说,SBA 风格主要是为了确保更高的并发性目标。下一代应用程序必须具有可扩展性、可用性和可靠性。SBA 模式是一个强大的推动者。
结合架构模式
正如我们所知,世界正在变成一个软件定义的世界。一切事物都被软件填充以展现适应性。因此,诸如软件定义网络、存储、计算、安全和环境等术语如今正变得越来越重要。此外,软件定义一切的概念正变得突出且至关重要。因此,软件的角色和责任正在增加。随着软件的快速传播、渗透和参与,软件产品也正变得复杂。软件专家和倡导者建议结合我们之前讨论过的多种架构模式,以减轻并加速下一代软件解决方案和服务的实现。我们描述了如何将 SOA 和 EDA 结合起来,为产生动态和自适应的应用程序奠定刺激的基础。同样,其他架构模式也可以同步,以产生复合模式,从而产生有能力和多功能的软件。
专用架构
具有上下文感知的事件驱动服务导向架构(ALFONSO GARCÍA DE PRADO 及其团队)。
上下文感知已成为实现以人为本的 IT 应用的基本要求。人们离开家时,期望他们留下的灯光能自动关闭。手机可以警告人们,如果上班路上有交通拥堵。如果下雨,雨刷会自动打开。如果家中、酒店或医院有火灾的可能性,那么传感器必须相互集成,及时进行数据融合,以便于火灾、火焰和跌倒检测。我们当前的 IT 服务和系统通常不具备上下文感知能力。每个常见的、随意的和便宜的商品都必须具备自我、周围环境和情境感知,以便在决策、交易和行为中独一无二。软件包、库和套件必须具有事件驱动性,以便敏感和响应。它们必须被设计和部署成能够接收任何值得注意的事件,并相应地做出反应。我们已经讨论了面向服务和事件驱动的架构。它们需要与新一代技术,如物联网(IoT),相结合,以便在日益互联的世界中正确且相关。
连接的物体、传感器、执行器、机器人、无人机、信标、机器、设备、仪器、商品、用具和其他设备将赋予软件服务上下文感知能力。有物联网数据分析平台、不断增长的不同和分布式事件源、事件处理器的更快成熟和稳定性、流分析引擎、大量的连接器、驱动器和适配器、知识可视化仪表板以及其他旨在跨行业垂直领域产生上下文感知应用的使能框架、模式、流程、实践和产品。
作者设计了一种高级上下文感知的事件驱动服务导向架构:

随着颠覆性的物联网时代的到来,应用和数据架构将同步以创建适用于各种用例的通用架构。
实时上下文感知预测架构
随着在个人、专业和社会环境中建立物联网环境以实现连接和智能环境的梦想,生成、收集、清洗和处理的多种结构化数据量正呈指数级增长。随着一系列特定和通用、消失的、可丢弃的但又不可或缺、轻薄、便携、时尚、嵌入式但联网的设备的到来,预期的大数据时代已经到来。这为企业和 IT 服务/解决方案提供商开辟了新的可能性和机会。
通过应用开创性的边缘技术,我们的制造车间、零售店、仓库、机场、火车站、公交车站,多学科诊所、购物中心、商场和超市,礼堂和体育场,娱乐中心和电影院,餐饮店等,正缓慢而稳步地变得更加智能。这意味着软件应用必须具备上下文感知能力,才能适应、包容和调整。
考虑到在 IT 领域发生的趋势和转型,一些研究人员(大卫·科拉尔-普拉扎及其团队)构想了一种全面的事件驱动服务导向架构(ED-SOA),它具有以下重要因素:
-
数据生产者应从多个来源(数据库、物联网传感器、社交网络等)收集数据,并将它们发送到数据收集器。
-
数据收集器执行必要的转换,以便接收到的信息可以在其解决方案的后续阶段中使用。它是一个中间层,执行同质化过程,因为在大多数情况下,信息很可能会以不同的格式和结构接收。
-
数据处理应提供复杂事件处理(CEP)、上下文感知和预测模块。
-
数据消费者,可以是数据库、最终用户或额外的端点,为协作架构铺平了道路。这些数据消费者通过 REST 接口与前面的模块进行通信:

我们正朝着实时应用程序和企业的世界迈进。实时数据捕获、处理、知识发现和传播、决策和执行已成为新常态。IT 系统正在被赋予实时能力。前面的架构阐述了实现实时预测的方法和手段。
摘要
我们详细介绍了突出的和主导的软件架构模式,以及它们如何对于生产任何类型的面向企业级和生产级软件应用程序具有明显的根本性和基础性。为了适应演变和革命,以及克服由于商业和技术领域不断变化而产生的复杂性,建议巧妙地利用各种软件模式作为前进的道路。越来越明显,为了设计和开发复杂和智能的应用程序,各种架构模式正被精心选择和认知地组合在一起,以产生复合模式。
此外,还有许多由全球研究人员形成、验证和验证的应用和领域特定架构,作为研究贡献被提出。因此,架构模式领域持续增长,以支持并维持软件工程领域。接下来的章节将进一步深入探讨,为现有和新兴技术提供大量有用和可用的设计模式细节。我们已经涵盖了新兴和发展的技术,如 Docker 支持的容器化、微服务架构(MSA)、大数据分析、响应式编程、高性能计算(HPC)等。
其他阅读材料
要了解更多信息,您可以参考以下阅读资源:
-
.NET 容器化应用程序的微服务架构:
docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/ -
SOA 模式:
www.soapatterns.org/ -
在高度分布式架构中使用事件:
msdn.microsoft.com/en-us/library/dd129913.aspx -
关于微服务和设计模式的全部内容:
microservices.io/index.html -
事件驱动架构模式:
towardsdatascience.com/event-driven-architecture-pattern-b54fc50276cd -
简要概述常见的软件架构模式:
towardsdatascience.com/10-common-software-architectural-patterns-in-a-nutshell-a0b47a1e9013
第二章:客户端/服务器多级架构模式
本章提供了一个客户端-服务器架构模式的鸟瞰图。它从两层客户端-服务器模式演化的需求开始,并强调了两层客户端-服务器模式的局限性如何导致了三层以及随后的n层客户端-服务器模式的演化。本章还深入解释了客户端-服务器模式的不同变体,如主从模式、对等网络模式等,并提供了相关的用例。本章的第二部分专注于 Web 应用程序框架。Web 应用程序的需求与客户端-服务器应用程序不同,关键的区别因素是基于底层数据的更改对 UI 的动态更新。本章的这一部分涵盖了 Web 应用程序设计中使用的所有流行模式。
本章涵盖的主要主题如下:
-
两层、三层和n层客户端-服务器模式
-
主从模式
-
对等网络模式
-
分布式客户端-服务器模式
-
模型-视图-控制器模式
-
模型-视图-表示者模式
-
模型-视图-模型模式
-
前端控制器模式
-
用于 Web 应用程序开发的常见设计模式
客户端-服务器模式是其中最古老的架构模式之一。简单来说,我们如何描述客户端和服务器?它被描述如下:
-
客户端: 这是请求服务的组件,向服务器发送各种类型服务的请求
-
服务器: 这是提供服务的组件,根据客户端提出的请求,持续不断地向客户端提供服务
客户端和服务器通常由分布式系统组成,它们通过网络进行通信。
下面的图是一个简单的图形,描述了客户端-服务器架构:

单个服务器可以服务的客户端数量没有上限。客户端和服务器是否位于不同的系统中也不是强制性的要求。根据系统的硬件配置和服务器提供的功能或服务类型,客户端和服务器可以位于同一系统中。客户端和服务器之间的通信是通过使用请求-响应模式交换消息来实现的。客户端基本上发送一个服务请求,服务器返回一个响应。客户端和服务器之间发生的这种请求-响应通信模式是进程间通信的一个很好的例子。为了使这种通信高效进行,有必要有一个定义良好的通信协议,该协议规定了通信规则,例如请求消息的格式、响应消息、错误处理等。所有用于客户端-服务器通信的通信协议都在协议栈的应用层工作。为了进一步简化客户端-服务器通信的过程,服务器有时会实现特定的应用程序编程接口(API),这些接口可以被客户端用来访问服务器上的任何特定服务。图中所示的这个客户端-服务器模式有两个层次:客户端层和服务器层,因此它也被称为两层客户端-服务器模式。
在客户端-服务器架构的上下文中,“服务”这个术语指的是资源的抽象。资源可以是任何类型,服务器根据服务器提供的资源(服务)来命名。例如,如果服务器提供网页,它被称为网页服务器;如果服务器提供文件,它被称为文件服务器,等等。服务器可以在特定时间点接收来自n个客户端的请求。但任何服务器都会有其处理能力的限制。因此,很多时候,服务器需要优先处理传入的请求,并根据其优先级提供服务。服务器中存在的调度系统帮助服务器分配优先级。针对不同用例的客户端-服务器模式的常见应用如下。
邮件服务器和邮件客户端:邮件服务器根据从邮件客户端收到的请求提供电子邮件。一些常用的企业级电子邮件解决方案包括来自微软的 Microsoft Exchange、来自 IBM 的 Lotus notes、来自谷歌的 Gmail 等。对电子邮件系统的工作描述如下。
邮件服务器,也称为电子邮件服务器,是处理和通过网络(通常是互联网)传递电子邮件的服务器。邮件服务器还配备了从客户端计算机接收电子邮件并将其传递到网络中其他邮件服务器的功能。电子邮件客户端是一个读取电子邮件的系统。它可以是台式机、笔记本电脑或支持电子邮件的智能手机。
以下图示展示了电子邮件系统的工作原理:

当从客户端发送电子邮件时,客户端系统中的电子邮件软件将连接到网络中的服务器,该服务器被称为简单邮件传输协议(SMTP)服务器。SMTP 指的是用于将电子邮件从客户端发送到服务器以及从一台服务器发送到另一台服务器的协议。
当使用客户端机器上现有的电子邮件软件下载电子邮件时,电子邮件软件将连接到另一个服务器,该服务器执行一个称为邮局协议版本 3(POP3)服务器的功能。POP3 服务器使用 POP3 协议。该协议的工作方式类似于邮局中使用的邮件投递系统,因此得名。这些协议的详细讨论超出了本章的范围。
域名服务(DNS)服务器和 DNS 客户端
DNS 是互联网上最重要的服务之一。互联网上有成千上万的设备都是其一部分,每个设备都被称为主机。每个主机都有一个与其关联的唯一 IP 地址。除了 IP 地址之外,每个主机还有一个与其关联的唯一主机名。例如,如果主机名为LP471并且位于域名technest.com中,那么该主机的完全限定域名(FQDN)就是LP471.technest.com。FQDN 用于在 DNS 命名空间内唯一标识主机。DNS 命名空间包含一些常用的名称后缀;它们如下所示:
-
.com: 商业组织 -
.edu: 教育机构 -
.gov: 政府组织 -
.org: 如 IEEE 等非营利组织 -
.net: 网络组织
除了这些常用的名称后缀之外,还有其他几个。
DNS 的工作原理
DNS 使用基于客户端-服务器模型的分布式数据库概念来工作。DNS 客户端是需要进行域名解析(将主机名映射到 IP 地址)的实体。DNS 服务器维护用于域名解析所需的数据。以下图示给出了 DNS 客户端-服务器架构的高级示意图:

假设将 URL www.xyzworks.com 输入 DNS 客户端的浏览器中。浏览器会连接到 DNS 服务器以获取相应的 IP 地址。DNS 服务器通过首先连接到一个根 DNS 服务器来执行此任务。根服务器将存储处理顶级域名(如 .edu、.com 等)的所有 DNS 服务器的 IP 地址。在这个例子中,根服务器在获取顶级域名 .com 的 IP 地址后,向其发送一个查询请求,询问 www.xyzworks.com 的 IP 地址。处理 .com 域的 DNS 服务器将响应,提供处理 www.xyzworks.com 域的名称服务器的 IP 地址。
名称服务器然后将查询发送到 www.xyzworks.com DNS 服务器。该 DNS 服务器向名称服务器响应整个 IP 地址,名称服务器再将它发送回发起 DNS 请求的 DNS 客户端。DNS 客户端机器可以使用该 IP 地址访问所需的网页。
这种客户端-服务器架构的显著特点如下:
-
冗余:每个级别都有多个 DNS 服务器,这样即使一个服务器失败,另一个服务器可以接替其角色。
-
缓存:一旦 DNS 请求被解决,DNS 服务器会缓存它收到的 IP 地址。例如,DNS 服务器缓存
.com域服务器的 IP 地址,以便任何后续对.com域的请求都可以由它处理,而无需启动重复的 DNS 查询机制。
两层客户端-服务器模式中的功能需求
在两层客户端-服务器模式中,关键的功能需求被分类如下表:
| 功能需求 | 描述 |
|---|---|
| 展示服务 | 提供用户界面和对话框控制 |
| 展示逻辑 | 用户交互和输入验证 |
| 商业逻辑 | 指定数据如何存储、创建和更改的一组商业规则 |
| 分发服务 | 通信管理 |
| 数据库逻辑 | 数据操作和管理数据完整性 |
| 数据库服务 | 管理数据库事务的各种属性 |
| 文件服务 | 文件操作和文件共享 |
在客户端-服务器模式中功能需求的分配
客户端被广泛分为以下两大类:
-
胖客户端:大部分功能服务由客户端组件执行。一个经典的胖客户端例子是文件服务器。
-
瘦客户端:如果是瘦客户端,它依赖于服务器组件来提供大部分的计算能力。
客户端的选择基于客户端-服务器模式类型,该模式是在系统中计划并实现的。例如,如果该模式涉及大量需要在客户端完成的功能,那么客户端的选择通常是胖客户端,反之亦然。本节讨论的功能需求将更好地说明选择客户端和服务器系统以实现特定客户端-服务器模式。
在客户端-服务器模式中,有多种方式可以实现功能需求。以下是一些实现客户端-服务器模式的主要方式:
-
远程数据访问客户端-服务器模式
-
远程表示客户端-服务器模式
-
分离逻辑数据客户端-服务器架构模式
远程数据访问客户端-服务器模式
在远程数据访问客户端-服务器模式中,应用程序位于客户端组件上,而数据管理则由服务器组件完成。执行数据管理的服务器通常被称为数据库管理系统(DBMS)或数据服务器。市场上大多数关系型数据库管理系统(RDBMS)产品都是使用这种模式实现的。这些 RDBMS 产品通常在客户端提供一层或组件的软件,该软件负责与数据服务器进行通信。这个软件组件被称为数据操纵语言(DML)。客户端系统支持表示层和业务逻辑,并使用 DML 与数据服务器进行交互。这些模式通常涉及使用胖客户端,因为客户端系统也执行大量的处理。
在以下图中展示了在远程数据访问客户端-服务器架构中实现功能需求:

远程表示客户端-服务器模式
在远程表示客户端-服务器模式中,图形用户界面(GUI)前端映射到现有应用程序的基于文本的屏幕。这个过程被称为远程映射或前端处理。这种模式的典型操作模式涉及使用智能工作站,这些工作站具备拦截从服务器系统发送的文本屏幕数据流的能力,并使用 GUI 在窗口系统中显示它们。然而,在这些系统中,大多数处理和计算仅在服务器端进行。这种实现的理想例子是 IBM 的 3270(主机)应用程序。在这个应用程序中,应用程序数据被发送到主机上的 3270 屏幕程序以进行显示。然后,数据以 3270 数据流的形式发送到客户端工作站。客户端工作站接收数据,对其进行解释,并将其转换为图形形式以在窗口中显示。如果用户通过客户端工作站的 GUI 窗口输入任何数据,运行在客户端工作站上的前端应用程序将数据转换为 3270 兼容格式并发送回服务器以进行下一步操作。远程表示客户端-服务器模式中功能分离的图示如下:

分离逻辑数据客户端-服务器架构模式
在分离逻辑数据客户端-服务器架构模式中,应用程序功能被分为两部分:一部分将在客户端实现,另一部分将在服务器端实现。与另外两种模式相比,这种模式非常复杂,因为客户端和服务器都需要为它们的运行分别编译应用程序程序。在实现此模式之前,开发者识别要在客户端和服务器端实现的功能,并列出应用程序程序在客户端和服务器端之间必须发生的通信对话类型非常重要。
三层模式/多层模式客户端-服务器
以下图表示了客户端-服务器交互:

在本节中,我们将讨论一些客户端-服务器模式的变体。客户端-服务器模式的一些显著变体如下:
-
主从模式
-
对等模式
让我们详细讨论它们。
主从模式
如果系统涉及需要重复执行且具有不同输入和上下文的相似或相同计算,则应用主从模式进行系统设计。主从模式提供了容错和并行计算的支持。
主从模式在以下图中展示:

主组件将工作分配给所有奴隶组件,并通过将每个奴隶返回的结果相加来计算最终结果。主从模式用于架构嵌入式系统,并用于设计执行大规模并行计算的系统。以下是主从模式的序列图:

主从模式的问题
主从模式基于分而治之的原则。在这个模式的工作中,协调概念与实际工作分离,因为所有奴隶都并行工作。因此,奴隶没有共享状态,并且它们独立工作。主从模式中的另一个问题是其延迟。这可能在响应时间非常关键的系统中引起问题,例如实时系统。此外,只有当问题可分解时,此模式才能应用于特定问题。
实现主从模式的一种方法是通过单个主线程,该线程创建多个奴隶线程。每个奴隶线程执行所需计算的变体,并将结果返回给主线程。一旦计算完成,主线程累积结果并终止奴隶线程。
客户端-队列-客户端模式这也可以称为被动队列架构。这是一种客户端-服务器架构的变体,其中所有组件,包括服务器,都仅被视为客户端系统。这是因为服务器被系统中的客户端视为被动队列,客户端使用它将消息传输到网络中其他客户端。这种架构可以被视为对等网络架构的早期演变之一,这在下一节中讨论,并且现在已过时。
对等模式
对等架构模式属于对称客户端-服务器模式的范畴。在这里,“对称”指的是在系统网络中不需要对客户端、服务器等进行严格划分。在对等模式中,单个系统既充当客户端也充当服务器。每个系统,也称为对等点,向网络中的其他对等点发送请求,并同时接收并处理来自网络中其他对等点的请求。这与传统客户端-服务器网络有很大的不同,在传统客户端-服务器网络中,客户端必须仅发送请求并等待服务器处理。
通常情况下,这种模式被用来实现一个使用分布式资源的去中心化系统网络,这些资源被期望执行特定的功能。分布式资源可以是处理能力、数据或带宽,这些资源可以用于任何分布式计算任务,如内容共享、通信等。对等网络模式的通用架构在以下图中展示(然而,可能存在一些变体,我们将在后面讨论):


对等网络模式基本上有两种实现方式:
-
纯对等网络模式
-
混合对等网络模式
在纯对等网络模式中,网络中的所有系统都是对等节点,它们既充当客户端也充当服务器。没有对集中式服务器进行各种操作管理的依赖。这种架构的主要优势是其容错性。另一个优势是简单易实现,因为这种架构远离了集中化的概念。这种架构的缺点是由于网络中的所有对等节点请求的洪泛,导致网络带宽过度使用。Gnutella,一个流行的文件共享协议,就是使用纯对等网络模式实现的。前面的图示是一个纯对等网络模式的例子。
在混合对等网络模式中,存在一个中央服务器来执行某些必要的行政任务,以确保 P2P 服务的顺畅运行。这可以通过一个简单的例子来更好地解释。Napster,一个文件共享协议,就是基于混合对等网络模式设计的。在 Napster 中,有一个服务器,其主要功能是帮助网络中的对等系统查找文件。文件之间的传输是基于服务器返回的搜索结果来启动的。换句话说,只有文件目录存储在服务器上,而目录中实际存在的文件则分散在网络的各个对等系统中。与纯对等网络模式相比,这种模式由于依赖于集中式服务器组件,其容错性较低。然而,这种模式的主要好处是没有不必要的网络资源消耗,并且这种架构具有高度的扩展性。混合对等网络模式在以下图中展示:

虽然对等模式对于文件共享等应用程序非常有效,但它们也提供了许多安全威胁和恶意代码进入网络并传播到网络中其他对等系统的选项。因此,对等应用程序使用的 TCP 端口应始终受到监控,并置于入侵检测系统/入侵预防系统的监督之下。
双层客户端-服务器模式的优势
客户端-服务器系统的一些关键优势如下:
-
安全性:数据存储在服务器上。这提供了对服务器的更大控制,并且比保护散布在大量客户端机器上的数据提供更高的安全性,这可能涉及为每个客户端机器提供特殊的保护机制。
-
集中访问数据:由于大部分数据都存储在服务器上,因此对数据进行更新要容易得多。这是一种最简单的架构风格之一。
-
易于维护:在这个架构模式中,客户端不知道服务器的详细信息,因此服务器维护活动(如修复、升级等)不会影响客户端的功能。
设计考虑因素 - 何时使用双层客户端-服务器模式?
在阅读了大量关于双层客户端-服务器模式的内容之后,我们心中产生的下一个问题是何时在特定的架构设计中使用双层客户端-服务器模式。以下要点可以作为决定该问题的指南:
-
如果正在考虑的应用程序是基于服务器的并且将支持众多客户端,那么双层客户端-服务器模式是一个不错的选择。
-
一些与双层客户端-服务器模式配合良好的应用程序包括通过网页浏览器访问的 Web 应用程序,或可能在整个组织中使用的业务流程应用程序。
-
即使您正在考虑集中数据操作,如存储、备份和其他相关管理任务,双层客户端-服务器模式也是一个理想的选择。
双层客户端-服务器模式的局限性
以下是一些客户端-服务器模式的主要局限性:
-
有限的扩展性、可伸缩性和可靠性:在大多数实现中,应用程序数据和业务逻辑都驻留在同一个中央服务器上。这一方面影响了系统的扩展性、可伸缩性和可靠性。
-
过度使用网络带宽:客户端和服务器之间的通信消耗了过多的带宽。请求和响应数据通常需要转换为通用格式,因为它们在客户端和服务器端可能有不同的表示格式。这一方面也导致了额外的流量。
为了克服两层客户端-服务器模式的这些限制,开发了三层/多层客户端-服务器架构。当今大多数使用客户端-服务器架构开发的应用程序,其基础都是三层/多层架构模型,这在下一节中讨论。
由于它们架构上的细微差异,本章将三层架构和多层架构作为单独的主题处理,尽管在许多其他论坛中它们可能被交替使用。
三层客户端-服务器架构
该架构中存在的三层如下:
-
表示层
-
应用或业务逻辑层
-
数据层
描述三层客户端-服务器架构的图示如下:

在三层架构中,不同的层作为不同的模块开发和维护,有时甚至在不同的平台上。以下各层的功能如下:
-
表示层:这是应用程序中存在的第一层和最顶层。这一层提供表示服务,即通过图形用户界面向最终用户展示内容。这一层可以通过任何类型的客户端设备访问,如桌面、笔记本电脑、平板电脑、手机、瘦客户端等。为了向用户展示内容,相关的网页应由运行在客户端设备上的网络浏览器或其他表示组件获取。为了展示内容,这一层必须与它之前存在的其他层进行交互。
-
应用层:这是该架构的中间层。这是应用程序业务逻辑运行的那一层。业务逻辑是组织制定的指导方针下运行应用程序所需的规则集。这一层的组件通常运行在一个或多个应用服务器上。
-
数据层:这是该架构中的最低层,主要涉及应用程序数据的存储和检索。应用程序数据通常存储在数据库服务器、文件服务器或任何其他支持数据访问逻辑并提供必要步骤以确保仅暴露数据而不提供对数据存储和检索机制的访问的设备或媒体中。这是通过数据层通过向应用层提供 API 来实现的。提供此 API 确保了在此层进行的所有数据操作对应用层完全透明,而不会影响应用层。例如,此层中系统的更新或升级不会影响该架构的应用层。
三层架构的好处如下:
-
可扩展性和灵活性:这种架构的主要优势是其可扩展性和灵活性。该架构的每一层都是一个模块化组件,也就是说,对某一层进行的任何操作,如更改或升级,都不会影响或导致其他层的中断或停机。客户端执行的功能较少,并且不需要高端配置,对于存在于表示层的客户端系统。
-
增强安全性:将任务分配给各个层级可以提高每个层级的安全性。
虽然三层架构模式提供了许多好处,但当涉及到需要大规模可扩展性的网络,如互联网时,该架构的可扩展性仍然有限。
使用三层架构的设计考虑因素
以下是一些三层架构是不错的选择的场景:
-
如果你正在开发一个具有有限功能/配置的客户端系统的应用程序。在这种情况下,可以将架构的其他组件,如业务逻辑和数据逻辑,分配到其他层级。
-
如果你正在开发一个将在内部网络中部署的应用程序,其中所有服务器都位于特定的私有网络中。
-
如果你正在开发一个没有在 Web 或应用程序服务器公共网络上部署业务逻辑的安全约束的互联网应用程序。
提供大规模可扩展性的三层架构模式的变体是n层架构模式。在n层架构模式中,总层数为n,其中n的值大于三,以区别于三层架构模式。在n层架构中,应用层(即中间层)被分割成多个层级。应用代码和功能在各层级之间的分配因架构设计而异。n层架构模式的图示如下:

使用 n 层架构的设计考虑因素
以下是一些n层架构是不错的选择的场景:
-
如果你正在设计一个系统,可以将应用程序逻辑分割成更小的组件,这些组件可以分布在多个服务器上。这可能导致在应用层设计多个层级。
-
如果考虑的系统需要更快的网络通信、高可靠性和出色的性能,那么n层架构具有提供这些功能的能力,因为这种架构模式旨在减少由网络流量引起的开销。
n 层架构的示例(购物车 Web 应用程序)
我们可以通过电子商务网站上普遍存在的购物车网络应用程序的例子来说明n层架构的工作原理。电子商务网站的用户使用购物车网络应用程序通过电子商务网站完成商品购买。
因此,应用程序应具有一些功能,使用户能够执行以下活动:
-
将选定的商品添加到购物车
-
改变购物车中物品的数量
-
进行支付
在购物车应用程序中存在的客户端层通过图形用户界面与最终用户交互。客户端层还与运行在多个层中的应用服务器中的应用程序进行交互。由于购物车是一个网络应用程序,客户端层包含网络浏览器。购物车应用程序中存在的表示层显示与浏览商品、购买商品、将商品添加到购物车等相关服务的相关信息。表示层通过向客户端层和所有网络中存在的其他层发送结果与这些层进行通信。
表示层还调用数据库存储过程和 Web 服务。所有这些活动都是为了提供快速响应时间给最终用户。表示层通过充当粘合剂,允许不同层中的功能相互通信,并通过网络浏览器向最终用户显示输出,从而发挥至关重要的作用。
在这个n层架构中,处理如计算运费等活动所需的企业逻辑从应用层拉到表示层。应用层还充当集成层,允许应用程序与数据层和表示层无缝通信。最后一层是数据层,用于维护数据。这一层通常包含数据库服务器。这一层独立于应用服务器和企业逻辑维护数据。这种方法为数据层提供了增强的可扩展性和性能。
分布式客户端-服务器架构
在前一部分讨论的购物车网络应用程序中使用的n层客户端-服务器架构是分布式客户端-服务器架构的理想例子。分布式架构通常有一些后端主机组件(如主机机、数据库服务器等),前端有一个智能客户端,中间有多个代理,负责处理所有与交易相关的活动,如交易处理、安全、消息处理等,以及用于通信的网络。

与分布式架构相关的关键概念如下:
-
事务处理:事务处理是指自动处理事务以更新共享数据库的过程。一般而言,事务处理应用程序将拥有许多用户,他们同时与系统交互,以便在共享数据库上处理业务事务。
-
事务处理监视器(TP 监视器):TP 监视器的主要任务是高效地管理通过客户端/服务器系统的事务流。TP 监视器还致力于确保在共享数据库上发生的并发事务不会对数据库中现有的数据造成任何不一致性。
TP 监视器还提供以下功能:
-
它们帮助在客户端和服务器组件之间建立双向连接。
-
它们提供帮助进行事务跟踪、负载均衡以及自动重启服务器及其队列中的队列的服务。
开发网络应用程序模式的动机
大多数网络应用程序在本质上都是高度交互式的。这意味着当数据发生变化时,它应该立即在用户界面中反映出来,而不应有任何进一步的延迟。在此基础上,应用程序的不同用户可能要求以各种格式(如电子表格、条形图、饼图、仪表板等)输出结果,如下面的图所示:

当特定应用程序的功能发生变化时,应用程序的用户界面也应该能够通过添加新选项(如菜单、下拉菜单等)来反映这些变化。这强调了网络应用程序的用户界面始终会受到一系列变更请求的影响。这些用户界面(UIs)变更请求可能发生在各种情况下,如下所述:
-
最终用户/客户出于易用性、适应性等各种原因对 UI 功能变更的请求
-
将系统从一个平台迁移到另一个平台
-
系统升级到新版本
-
数据库设计的变更
从这个角度来看,我们可以推断出用户界面总是变化的目标。应用程序的不同用户对用户界面提出不同类型的冲突要求,以便使他们的操作变得容易。例如,使用基于表单的界面进行数据输入的行政人员可能需要在基于表单的界面中获得更多易用性,而负责报告的行政人员可能需要向报告界面添加更多功能。所有这些都要求有一个设计灵活的用户界面,能够容纳所有类型的 UI 范式。如果 UI 与应用程序的功能核心紧密耦合,则无法构建具有这种灵活性的系统。在这种情况下,开发和维护多种类型的软件应用程序成为必要,每种类型的用户界面都需要一个应用程序。以下是设计 Web 应用程序设计模式时需要考虑的主要方面:
-
应该能够在不同的窗口中以不同的格式表示相同的信息,例如,在一个窗口中以饼图的形式,在另一个窗口中以 Excel 表格的形式,等等。
-
应该能够在运行时轻松地更改 UI。
-
应该能够提供各种外观和感觉标准,并且用户界面的更改不应意味着应用程序代码的更改。
所有这些因素都是设计模型-视图-控制器(MVC)模式动机,该模式主要用于移动和 Web 应用程序的设计和开发。以下是 MVC 架构模式的主要组件:
-
模型:MVC 模式中模型组件的功能是封装核心数据和功能。模型组件具有独立运行的能力,不受输出表示和输入行为的影响。在设计术语中,模型本质上代表了一组用于表示业务逻辑的类。
-
视图:视图组件的功能是向最终用户显示信息。视图组件从模型获取要显示的数据。一个模型可以有任意数量的视图,具体取决于应用程序的需求。在设计术语中,视图本质上描述了 UI 组件,如 HTML、jQuery 等。
-
控制器:每个视图都与一个控制器相关联。控制器获取输入,通常是用户事件的形式。这些事件可能是鼠标点击、键盘按键等。这些事件被转换为服务请求并传递给模型或视图。控制器是用户与系统交互的唯一组件。
模型、视图和控制器的组件分离提供了灵活性,因为它允许对同一模型有多个视图。如果用户更改了使用视图组件的模型数据,那么使用相同数据的所有其他视图应立即更新以反映新的更改。这是通过模型在数据更改时通知所有视图来处理的。视图随后从模型获取更新后的数据并更新所有相关视图。所有这些动作序列都需要 MVC 模型中存在一个变更传播机制。这种传播机制的变更将在下一节中解释。
MVC 模式的工作原理
模型组件导出用于应用特定处理的程序。这些程序由控制器组件在接收到用户输入时调用。模型组件还提供视图组件可以用来访问其数据的函数。
视图组件用于向最终用户展示信息。根据用户的需求,可能会有不同的视图以不同的方式提供信息。每个视图都与一个更新程序相关联,该程序由变更传播机制激活。变更传播机制通过维护模型中所有依赖组件的注册表来工作。所有受这些组件更改影响的关联视图和控制器也会注册他们的需求,以便他们能够了解所有更改。模型状态中的任何更改都会反过来触发变更传播机制。借助更新程序,视图组件从模型检索最新的数据值并在用户界面屏幕上显示它们。
控制器组件接受用户输入,形式为事件。这种事件数据传递给控制器的格式取决于用户界面平台。但一般来说,每个控制器执行与事件相关联的事件处理程序。MVC 模式的整体工作原理在本节给出的图形中展示:

在下一节中,我们将讨论一个流行的编程框架,该框架是使用 MVC 模式开发的。
ASP.Net 框架
在 ASP.Net 中,视图组件和控制器组件的模式已经定义良好。只有模型组件的模式需要开发者根据具体的应用需求来设计。
视图:处理与视图组件相关的责任的文件是 ASPX 和 ASCX。在这个设计中,视图对象通常继承自控制器对象。
控制器:控制器组件的责任被分配到两个组件中。事件生成和传递由框架完成,更具体地说,由页面和控制类完成。事件处理由代码后置类负责。
模型:ASP.NET 不一定需要模型。是否创建模型类或放弃它由开发者选择。如果不使用模型,控制器中的事件处理程序可以用来执行任何计算并确保数据持久性。
模型-视图-表示者(MVP)模式
MVP 模式是 MVC 模式的变体,主要用于开发 Web 应用的用户界面。它主要是为了使自动化单元测试更容易而设计的。这里给出的图形描述了 MVP 模式的架构:

MVP 模式的各种组件如下:
-
模型:该组件指定要显示/从用户界面发送或接收的数据。
-
视图:表示逻辑位于表示组件中。它作用于模型和视图组件。它负责从模型获取数据,应用适当的逻辑,并将其发送回视图进行显示。与 MVC 模型中的视图和控制器组件相比,MVP 模式中的视图和表示组件是完全解耦的,并且通过接口进行通信。
-
表示者:视图组件仅作为被动接口。它显示模型中的数据,并将用户输入和命令发送到表示组件。这些用户输入和命令将被用来对数据进行操作。
以下是一些关于 MVP 模式的关键考虑因素:
-
最终用户仅与视图交互
-
一个视图组件仅映射到一个表示组件
-
视图引用表示者组件,但没有引用模型组件
-
该模式促进了视图组件和表示组件之间的双向通信
一些使用此模式的一些常见应用包括 ASP.Net 表单和 Windows 表单。
模型-视图-视图模型(MVVM)模式
MVVM 是一种流行的模式,用于开发可重用且易于测试的 Web 应用。MVVM 是 MVC 的现代变体,其核心目标是实现模型和视图组件之间的真正分离。模式的主要组件如下:
-
Model
-
View
-
ViewModel
该模式的分层架构在以下图中描述:

MVVM 模式的各种组件如下:
模型:该组件代表业务逻辑和数据。这意味着指定如何操作数据的业务逻辑存在于模型组件中。
视图:此组件代表 UI 组件,并将本质上包含 CSS、HTML 等 UI 元素。它仅负责表示数据,不对数据进行任何操作。然而,与 MVM 不同,MVVM 中的视图是一个活动组件,包含行为、事件和数据绑定,这些需要关于底层模型和 viewModel 组件的信息。
ViewModel:ViewModel 是架构中非常重要的组件,因为它有助于展示分离,即它有助于保持视图与模型分离,同时充当支持视图和模型组件之间交互和协调的控制器。ViewModel 组件还包含命令和方法,有助于维护视图的状态,并帮助根据在视图中执行的操作操纵模型。ViewModel 组件还帮助在视图组件本身中触发事件。
MVVM 模式的关键优势
使用 MVVM 模式进行设计的以下关键优势:
-
可维护性:在此模式中,不同代码片段的清晰分离使得维护代码更加容易,同时也确保了使用代码的快速发布。
-
可测试性:在此模式中,不同的代码片段非常细粒度,并且与核心功能逻辑的关键距离。这使得单元测试变得非常容易。
-
可扩展性:细粒度的代码片段促进了代码的重用,并允许快速修改代码片段。
使用 MVVM 模式的设计考虑因素
MVVM 模式是设计需要以下方面的 Web 应用程序的正确选择:
-
对各个组件进行彻底的单元测试
-
使用可重用代码的概念开发应用程序,以及开发能够生成可重用代码片段的应用程序
-
能够在不更改代码库的情况下更改用户界面
在下一节中,我们将讨论一个使用 MVVM 模式构建的示例框架。
Prism
Prism 是一个使用 MVVM 模式构建的框架。它有助于设计和开发灵活且易于维护的Windows 演示基础(WPF)桌面应用程序。它还帮助使用 Microsoft Silverlight 浏览器插件构建富互联网应用程序。以下 Prism 框架的关键特性:
-
它使用支持重要设计概念(如关注点分离和松散耦合组件)的架构模式。
-
Prism 有助于设计可轻松集成以形成应用程序的代码片段/组件。通过集成组件形成的应用程序称为复合应用程序。
Prism 的一些重要特性包括:
-
支持 MVVM 模式,这反过来又提供了一个可绑定基类。
-
它具有灵活的 ViewModelLocator,允许视图和 ViewModel 组件以松耦合的方式连接。因为它有几个松耦合的类库,所以它为模块化应用程序的开发提供了全面的支持。这些库可以在运行时以应用程序的形式组合在一起,供最终用户使用。代码库仍然保持解耦。
-
支持丰富的导航功能,支持如前进导航、后退导航等功能。Prism 的导航堆栈允许 ViewModel 直接参与导航过程。
-
Prism 支持发布/订阅事件的概念。这些是指一种松耦合事件机制,其中发布者和订阅者组件可以通过事件进行通信。发布者或订阅者组件不一定需要具有显式的引用或相同的生命周期。
网络应用程序开发的设计模式
除了在前几节中讨论的 MVC、MVP 和 MVVM 架构模式之外,还有一些设计模式与这些模式一起用于应用程序的设计。在本节中,我们将讨论一些常用的网络应用程序设计模式。以下表格描述了这些模式和它们的功能:
| 模式名称 | 功能 |
|---|---|
| 解释器设计模式 | 这种模式在开发编辑器和集成开发环境(IDE)等应用程序的菜单时广泛使用。这种模式通过解释以语言语法或符号形式编写的指令来工作。这种模式涉及实现一个表达式接口,用于解释给定的上下文。 |
| 中介者设计模式 | 这种模式的关键特性是它允许对象在不了解其结构的情况下相互交互。这是通过定义一个对象,通过封装它们与其他对象交互的方式实现的。这个特性也有助于代码的易于维护和重用。这种模式也广泛用于开发编辑器和 IDE 等应用程序的菜单。 |
| 备忘录设计模式 | 这种模式的关键特性是它有助于捕获对象当前状态并将其存储为原始状态,以便在需要时可以在稍后的时间点再次使用,而不必实际违反与对象封装相关的规则。 |
| 观察者设计模式 | 这种模式用于存在对象之间一对一关系的场景。在这种情况下,如果对象被修改,就必需通知其依赖对象关于这些变化的信息。这就是使用观察者设计模式的主要动机。这种模式允许一个称为主题的单个对象通知所有依赖它的其他观察者对象其状态的变化。 |
| 状态设计模式 | 此模式用于存在对象之间一对一关系的场景。在这种情况下,如果对象被修改,则必须通知其依赖对象关于更改的信息。此模式主要用于在对象内部状态发生变化时需要改变对象行为的情况。此模式通过创建一个对象来表示各种状态,以及一个相关的上下文对象,其行为根据创建对象的州变化而变化。 |
| 策略设计模式 | 此模式为客户端提供了在运行时从一组算法中选择任何特定算法的灵活性。它还为客户端提供了一个简单的方式来访问算法。此模式通过将算法从其宿主类中移除并将其放置在单独的类中来实现。这将有助于防止如果算法存在于宿主类中可能出现的代码相关问题。 |
| 模板方法设计模式 | 此模式提供了定义算法执行基本步骤的功能,同时允许特定的执行步骤被更改。这与策略设计模式非常相似;唯一的区别是它允许修改某些算法步骤而不是整个算法。 |
| 访问者设计模式 | 此模式提供了在不改变对象及其相关类的结构的情况下创建和执行一组对象上新操作的灵活性。此模式允许组件的松散耦合,因此可以在不改变现有对象结构的情况下对它们执行新操作。 |
| 桥接模式 | 此模式提供了将抽象与其实现分离的灵活性。这允许它们独立修改。通过提供一个接口来实现抽象类和实现类之间的桥梁,从而实现抽象与实现的分离。这种分离也使得实现类功能独立于抽象类功能。 |
| 组合模式 | 此模式提供了以相同方式处理一组对象和单个对象的灵活性。组合模式以树结构的形式排列对象,以表示部分以及整体层次结构。 |
| 工厂方法设计模式 | 此模式提供了在不暴露其创建逻辑的情况下创建对象的灵活性。在此模式中,使用接口来创建对象。子类决定需要实例化哪个类。对象的创建仅在需要时进行。 |
| 建造者设计模式 | 该模式允许我们通过逐步方法构建一个复杂对象。一个称为建造者接口的专用接口指定了构建最终对象所需的步骤。这个建造者接口与对象的创建过程无关。一个称为导演的类控制着对象的创建过程。该模式的另一个特点是它指定了一种将对象与其构造分离的方法。相同的构造方法可以用来创建同一对象的多个表示形式。 |
| 适配器模式 | 当需要提供两个不兼容接口之间的桥梁时,使用此模式。该模式提供了一个名为适配器的单一类,它促进了两个独立或不兼容接口之间的通信。例如:读卡器作为笔记本电脑中内存卡的适配器。这是通过将内存卡插入读卡器来完成的。然后,将读卡器插入笔记本电脑,以便可以通过笔记本电脑读取内存卡。 |
前端控制器模式
另一种在 Web 应用程序开发中流行的架构模式是前端控制器模式。该模式确保所有传入请求只有一个入口点。一个称为控制器的单一代码片段处理所有传入请求,然后将每个请求的处理委托给系统中的其他应用程序对象。该模式的这一核心特性通过代码的重用为 Web 应用程序开发者提供了必要的灵活性。前端控制器模式的架构在以下图形中展示:

以下是该模式的不同组件:
-
前端控制器:该组件处理应用程序所有类型的传入请求
-
分发器:该组件用于将请求分发给特定的处理器以进行进一步处理
-
视图:这些对应于请求的对象
在下一节中,我们将讨论一个使用前端控制器模式开发的流行框架。
Spring 框架
Spring,一个非常流行的 Web 应用程序开发框架,在其设计中遵循了两种架构模式:前端控制器模式和 MVC 模式。架构在以下图形中展示:

分发器 Servlet 组件是作为前端控制器功能并处理所有传入请求的单个 Servlet。分发器 Servlet 随后调用处理器映射以找到可以处理请求的对象。然后将请求交给控制器对象,以便分发器可以自由执行与用户请求的业务逻辑满足相关的功能。控制器对象返回一个封装的对象,其中包含模型对象和视图对象。这由 ModelandView 类表示。如果 ModelandView 包含视图的逻辑名称,分发器 Servlet 将调用视图解析器以获取实际视图对象的详细信息。然后分发器 Servlet 将模型对象交给视图对象,以便它可以显示给最终用户。
摘要
在本章中,我们以两层客户端-服务器模式开始讨论。这是最早和最古老的客户端-服务器模式之一。随着信息技术产业的增长,这种两层客户端服务器模式不足以满足基础设施需求。这导致了三层客户端-服务器模式的演变,随后是n层客户端-服务器模式。本章还讨论了客户端-服务器模式的某些其他变体,如主从模式、对等模式等。本章还讨论了每种模式的适用应用程序和设计考虑因素。
网络应用程序开发,虽然后来才兴起,但由于其固有的局限性,无法使用客户端-服务器架构。这导致了某些专为网络应用程序开发量身定制的模式的演变。这些模式需要基本的灵活性,以便在不更改代码库的情况下更改用户界面。本章的后半部分主要讨论了这些模式。本部分讨论的主要模式是 MVC、MVP、MVVM 和前端控制器。
本章还讨论了一些与这些模式一起使用的常见设计模式。
本章的附加参考资料:www.dotnettricks.com/learn/designpatterns/adapter-design-pattern-dotnet
第三章:面向对象软件工程模式
软件工程中的面向对象(OO)概念并不新鲜,在我们深入探讨面向对象设计模式之前,让我们先简要介绍面向对象的概念。当你阅读本章时,环顾四周;你所看到的一切都是对象:书籍、书架、阅读灯、桌子、椅子等等。你周围的一切都可以想象成对象,它们都具备两个主要特征,如下:
-
状态
-
行为
阅读灯有“关闭”和“开启”两种状态,以及“开启”和“关闭”两种行为。对象也可能有多个状态和多个行为,有时甚至还有其他对象。
面向对象设计(OOD)旨在提供模块化、抽象(信息隐藏)、代码重用以及可插拔(即插即用)和易于代码调试。
Grady Booch 在其名为《面向对象分析与设计与应用》的书中定义了 OOD,如下所述:
"OOD 是一种设计方法,包括面向对象分解的过程,以及用于表示正在设计中的系统的逻辑、物理以及静态和动态模型的符号。"
本章涵盖了以下 OOD 的要素:
-
OOD 的基本和非基本要素
-
OOD 的主要特性
-
OOD 的核心原则
-
OOD 最常见的设计模式
-
面向对象设计模式的交叉引用
OOD 的关键要素
OOD 有四个关键要素。具体如下:
-
抽象:隐藏内部复杂性和低级实现细节。
例如,你看到可以切换开启和关闭的电气开关按钮,但它如何实现开启和关闭并未向外界展示,实际上,对于普通用户来说,这并不必要。
-
封装:将数据与其操作方法捆绑在一起,防止数据被意外或未经授权访问。
例如,关闭功能应仅关闭目标元素,例如阅读灯,而不应影响同一电气系统中的其他任何电气功能。
-
模块化:将程序/函数分解成模块的过程,以降低整体复杂度。
例如,开关开启和关闭是电气系统的常见功能。开关阅读灯的开启和关闭可能是一个独立的模块,并且与关闭洗衣机和空调等其他复杂功能解耦。
-
层次结构:抽象的排序和与子系统相关联的系统的层次结构。这些子系统可能还拥有其他子系统,因此层次结构有助于达到给定系统中组件的最小可能级别。
OOD 的其他要素
OOD 有三个其他要素。具体如下:
-
类型:一组项目的特征。在面向对象编程中,类是一个独特的类型。它有两个子类型。具体如下:
-
强类型
-
弱类型
-
-
并发性: 操作系统允许同时执行多个任务或进程。
-
坚持: 类或对象占据空间并在特定时间内存在。
设计原则
本章和以下各节详细介绍了面向对象设计原则、其特征以及设计模式。每个模式部分都涵盖了其需求、设计考虑因素和最佳实践,以便读者了解模式及其应用。
让我们从通常被称为缩写“SOLID”的核心原则开始详细说明。
单一职责原则(SRP)- SOLID
在面向对象的编程风格中,单一职责强制每个类应代表一个且仅代表一个职责,因此如果它需要更改,那应该是只有一个原因,即一个类应该只有一个且仅有一个更改的原因。
当我们设计一个类或重构一个类,并且如果它需要多个原因来更改,那么将功能拆分为与类数量一样多的部分,因此每个类只代表一个职责。
在这个上下文中,职责是对功能/业务规则的任何更改,这会导致类发生变化;对连接的数据库模式、用户界面、报告格式或任何其他系统的任何更改都不应迫使该类也发生变化:

上述类图描述了一个Person类有两个职责:一个职责是用用户的姓氏或姓问候用户,另一个职责是验证电子邮件。如果我们需要在Person类上应用 SRP,我们可以将其分为两个;Person有一个问候方法,而Email有电子邮件验证。
SRP 不仅适用于类级别,也适用于方法、包和模块。
开放和封闭原则 – SOLID
面向对象编程的开放和封闭原则建议,面向对象的软件实体,如类、方法或函数以及模块,应该对扩展是开放的,但对任何修改是封闭的。
想象一个你永远不会更改的类,并且任何新功能都只能通过添加新方法或子类,或者通过重用现有代码来添加,因此我们可以防止对现有代码或功能引入任何新缺陷。

上述类图展示了在Account类及其子类上应用开放和封闭原则。账户可以是任何类型,如储蓄或活期。SavingsAccount可能被分类为GeneralAccount、KidsAccount等,因此我们可以强制 Account 和其他子类对增强是可用的,但对修改是封闭的。
开放和封闭原则带来了代码无需更改、不引入任何新缺陷的好处,但可能存在一个缺点,即现有的缺陷从未得到解决。
李斯克替换原则(LSP)- SOLID
这个原则指出,任何子类都不应该破坏父类的类型定义,换句话说,派生类应该可以替代其基类。
首先,让我们了解替代性原则的违反,然后我们看看如何通过使用我们之前关于账户类作为 LSP 是 OCP 主要启用者的例子来解决这个问题:

假设从儿童账户的提款是不允许的,与普通账户不同。正如你在前面的类图中看到的,儿童账户类中的withdraw方法违反了 LSP,因此通过引入从SavingsAccount类继承的其它可提款和非提款类来处理不可提款行为,我们可以消除这种违反,并且子类不会改变基类的行为:

因此,SavingsAccount的行为在继承给KidsAccount时被保留。前面的代码片段证明了这一点。
接口分离原则(ISP)- SOLID
想象一下,你正在实现一个名为 pets 的类的接口,编译器抱怨你的Cat类中没有包含 bark 方法;这很奇怪,不是吗?
ISP 建议“任何类的接口都不应该强迫客户端包含任何对该客户端来说不必要的方 法”;在我们的例子中,Cat不需要实现 bark 方法,这是Dog类的专属:

前面的图描述了 ISP 的违反以及如何通过将<
依赖倒置原则(DIP)- SOLID
DIP 强制执行以下两点:
-
任何高级模块都不应该依赖于低级模块,而两者都应该依赖于抽象模块
-
模块的抽象不应依赖于其实施或细节,而实现应依赖于抽象
请参考前面的接口分离原则(ISP)- SOLID部分,以及示例类(图 3.5)Pets 类及其抽象类。Dog和Cat依赖于抽象(接口),并且任何对底层实现的任何更改都不会影响其他实现。
其他常见设计原则
其他常见原则如下;然而,每个原则的详细内容不在本章的范围内,如果您需要了解更多关于这些原则的信息,请参考其他材料:
-
封装
-
总是封装你认为迟早会改变代码
-
组合优于继承
-
在某些情况下,您可能需要在运行时更改类行为,并且这些情况更倾向于组合而不是继承
-
为接口编程(而不是实现)
-
为代码带来灵活性,并且可以与任何新的实现一起工作
-
一般责任分配软件模式(GRASP)
-
指导如何分配协作对象的责任
-
不要重复自己(DRY)
-
通过适当抽象公共代码到一处来避免代码重复
-
单一层抽象原则(SLAP)
-
方法中的每一行都应该处于相同的抽象级别
面向对象设计模式
面向对象设计模式解决了许多常见的软件设计问题,如下所述,建筑师每天都会遇到:
-
寻找合适的对象
-
确定对象粒度
-
指定对象接口
-
指定对象实现
-
面向接口编程,而非面向实现
-
利用重用机制
在本节中,我们将讨论一些常见问题以及设计模式如何解决这些问题,并详细介绍面向对象设计模式。
我们可以将模式分为三种类型:创建型、结构型和行为型。在我们继续详细讨论之前,请参考本章末尾的表格,该表格以简单参考的形式描述了模式和其类别。
创建型设计模式
创建型模式旨在提倡一种更好的创建对象或类的方法,其重点如下:
-
抽象类实例化过程
-
定义创建、组合和表示对象的方式,并从涉及系统中隐藏实现细节
-
强调避免硬编码一组固定的行为,而是定义一组较小的核心行为,这些行为可以组合成任意数量的(复杂)集合
创建型设计模式有两个基本特征:一是它们封装了关于系统使用哪个具体类的知识,二是它们隐藏了这些类的实例是如何创建和组合的。
类创建型模式使用继承进行实例化,而对象创建则委托给另一个对象。
下一节将处理每个模式,其一般结构和在大多数情况下的示例实现图。
工厂方法(虚拟构造函数)
此模式建议让子类实例化所需的类。工厂方法定义了一个接口,但实例化是由子类完成的:

上述结构描述了一个工厂方法,应用程序使用工厂来创建具有接口的子类型。
使用此方法的优点如下所示:
-
松耦合:将应用程序与类及其子类分离
-
定制钩子:工厂方法为子类提供了一个提供对象扩展版本的钩子
使用这种方法的副作用是它创建了并行类层次结构(相互镜像结构),因此我们需要使用智能子模式或延迟识别状态变量模式以最佳方式来结构化。
抽象工厂(套件)
抽象工厂模式旨在提供接口,如果我们想创建相关或依赖对象的家庭,但又不明确指定它们的具体类:

上述类图展示了抽象工厂类结构和为结合来自两个不同组(<
其好处如下:
-
隔离具体类
-
使交换产品族变得容易
-
促进产品之间的一致性
影响如下;支持新产品类型是困难的。
建造者
建造者旨在将复杂对象的构建与其表示分离,以便相同的构建过程可以创建不同的表示。换句话说,使用此模式以逐步方式通过简单对象简化复杂对象的构建:

类图展示了典型的建造者模式结构和建造者模式的示例实现类。建造者(TextConverter)是一个抽象接口,用于创建产品页面的部分。具体建造者(AsciiConv,TexConv)通过接口实现构建和组装部分,导演(Reader)通过建造者接口构建对象,而产品(AsciiTxt,Text)是正在构建的复杂对象。
好处如下:
-
允许更改内部表示并定义新的建造者类型
-
隔离构建和表示的代码
-
提供对构建过程的更精细控制
影响如下:
-
导致为每种产品类型创建一个单独的具体建造者
-
导致可变的建造者类
原型
原型模式建议复制或克隆现有对象,并在需要时对其进行定制,而不是创建新对象。当系统应独立于其产品的创建、组合和表示时,选择此模式:

我们可以在运行时创建PublicProfile(有限信息)或FullProfile的副本。这两个类共享一些状态组合,因此将其设计为原型是很好的。
让我们看看它的好处:
-
在运行时添加和删除产品
-
通过改变值和结构来指定新对象
-
减少子类数量
-
动态类配置到应用程序中
影响是,每个子类都必须实现克隆操作,并且无法克隆循环引用类。
单例
此模式建议创建一个实例,并提供对创建对象的全球访问点:

前面的图中数据库连接旨在作为单例,并为它的唯一对象提供一个获取器。
这里是其优点:
-
控制对唯一实例的访问
-
减少命名空间
-
操作和表示的细化灵活性
-
比类操作更灵活
影响如下:
-
在整个应用程序生命周期中携带状态,为单元测试创建额外的开销
-
一定程度违反单一职责原则
-
通过使用单例作为全局实例,它隐藏了应用程序的依赖关系;相反,它应该通过接口来暴露
结构设计模式
结构模式提供了根据面向对象设计原则组合类和对象以形成更大结构的指导方针。
结构类模式使用继承来组合接口或实现,而结构对象模式提倡组合对象和实现新功能的方法。
结构设计模式的一些关注领域如下:
-
提供不同接口的统一抽象(适配器)
-
在运行时更改组合并提供对象组合的灵活性;否则,使用静态类组合是不可能的
-
通过共享对象确保效率和一致性
-
动态添加对象责任
以下部分将描述每个结构模式,以及标准结构和示例实现结构图。
适配器类(包装器)
将一个类的接口转换为客户端想要的另一个接口。换句话说,适配器使异构类能够协同工作:

前面的类图描绘了一个名为OnlineLinkedAccounts的适配器,它采用储蓄账户的详细信息和一个目标接口信用卡详情,并将结果组合起来显示两个账户号码。
适配器(对象)
适配器对象依赖于对象组合,当我们需要使用几个现有的子类时,我们可以使用对象适配器来适配父类的接口:

前面的图描绘了适配器的正式结构。
这些是优点:
-
通过模拟应用程序不同部分的行为,在开发和测试期间节省时间
-
为具有相似行为的新功能提供易于扩展
-
允许单个适配器与多个适配者一起工作(适配器对象)
影响如下:
-
导致类之间不必要的代码重复(较少使用继承类功能)
-
可能会导致嵌套适配以到达更长的链中的目标类型
-
使覆盖适配者行为更困难(适配器对象)
桥接(处理/主体)
桥接模式的目标是将抽象与其实现解耦,因此抽象和实现是独立的(不是在编译时绑定,因此不会影响客户端):

好处如上所述:
-
将接口与实现解耦
-
在运行时配置抽象的实现
-
消除了编译时依赖
-
改进了可扩展性
-
从客户端隐藏实现细节
影响是,引入了一定程度的复杂性。
组合
组合对象让客户端可以统一地对待单个对象和对象的组合。组合将对象层次表示为树结构。

前面的图示描述了组合模式的标准结构和部分-整体层次结构的实现(代理的员工部分、会计和出纳员),以及对于客户端,所有对象都是组合的,并且结构统一。
这些是好处:
-
它通过隐藏复杂的通信(叶或组合组件)简化了客户端代码
-
添加新组件更容易,并且当添加新组件时,客户端不需要更改
影响如此之大,以至于它使得设计过于通用和开放,因为没有限制向组合类添加任何新组件。
装饰器
装饰器模式动态地为对象附加额外的责任。它提供了一种替代方法(通过组合)来子类化和在运行时扩展对象的功能。
此模式通过包装原始类来创建一个装饰器类,以提供额外的功能,而不会影响方法签名。

观察前面的图示,因为它动态(运行时)展示了通过组合扩展的发票功能
让我们列出好处:
-
它减少了升级所需的时间
-
它简化了从目标类增强功能,并将行为纳入对象中(改变类责任,而不是接口)
影响如下:
-
它倾向于引入更多类似的对象
-
由于它在运行时添加功能,因此会导致调试困难
外观
外观模式建议提供一个高级接口,该接口统一了子系统接口集,因此简化了子系统的使用。

如前图所示,服务外观的示例实现,会话子系统与会话外观(本地和远程)统一。
让我们看看它的好处:
-
它促进了松散耦合(客户端和子系统之间)
-
它隐藏了子系统对客户端的复杂性
影响如此之大,以至于它可能导致外观检查子系统结构是否发生变化。
享元
享元建议使用大量细粒度对象的共享支持。我们可以使用享元模式来减少创建的对象数量(通过共享),从而减少内存占用并提高性能。

上述图展示了享元模式的一般结构和示例实现。考虑一个在打印机和屏幕之间共享的巨大对象;享元是一个很好的选择,也可以被缓存(例如,用于打印多份)。
这里是好处:
-
由于减少了实例总数(通过共享对象),它导致良好的性能。
-
它使得对象缓存实现变得容易
影响如此之大,以至于它可能会引入与传输、查找或计算外部(外部的)状态相关的运行时成本。
代理
代理模式建议提供一个占位符(代理)来控制另一个对象并获取对其的访问。这对于对象的延迟加载(直到需要使用时才创建和初始化)是最合适的。

上述图展示了支付类代理模式的示例实现,支付可以是支票或汇票。然而,实际的访问将是到DebitAccount对象,因此PayOrderProxy和CheckProxy都是 Debit Account 的代理。
以下是一些好处:
-
它在访问对象时引入了正确级别的间接性(位于不同空间的对象的抽象)
-
按需创建对象
-
写时复制(如果未修改,可能减少重对象的复制)
影响如此之大,以至于它可能会因为间接性而使某些实现效率降低。
行为模式
行为模式为在对象之间分配责任提供了指导。这确实有助于实现算法以及类和对象之间的通信。
行为模式关注以下特性:
-
对象和类之间的通信
-
描述复杂的控制流;软件编程中的控制流(否则,在运行时很难跟踪)
-
强制使用对象组合而不是继承
-
同伴对象之间的松散耦合,同时,它们通过间接性相互了解
-
在对象中封装行为并将请求委托给它
有各种设计模式可用于强制执行上述行为焦点和特性。在本节中,我们将看到这些行为模式的详细信息。我们还提供了一些模式的示例实现结构图。
责任链
此模式建议通过使对象(多个)能够处理请求来避免将客户端对象(请求的发送者)与接收对象耦合。

上述图展示了责任链的典型结构;处理者是定义请求的接口,并可选择表达后继者,包括可以处理请求的具体处理者,如果需要,可以转发请求。
这里列出了好处:
-
减少了耦合(对象不知道哪些其他对象处理请求)
-
在责任分配(对象)方面有更多的灵活性
影响是,请求处理器之间没有握手,因此无法保证其他对象处理请求,并且它可能在不被注意的情况下从链中脱落。
命令(动作/事务)
这个模式建议将请求封装为对象,用不同的请求参数化客户端;它可以放在消息队列上,可以记录,并支持撤销操作。

上述图示描述了命令模式的结构以及股票经纪人应用程序类的示例实现。<
这里是它的好处:
-
对象封装有助于部分更改请求(通过更改单个命令)而不会影响其余流程
-
将调用对象与实际执行动作的对象分离
-
容易添加新命令,而不会对现有类造成任何影响
影响是,随着时间的推移或取决于命令的数量(具体命令实现),类和对象的数量会增加。
解释器
这个模式建议定义语法以及使用表示的解析器,以便系统可以解释任何给定语言的句子。

抽象表达式或正则表达式声明解释操作,终端表达式或字面表达式实现语法中的符号,而非终端表达式(选择、序列、重复)在语法中有非终端符号。
让我们看看它的好处:
-
容易更改和扩展语法
-
实现语法同样简单
-
有助于引入解释表达式的新方法
-
影响
-
为复杂的语法引入了维护开销
迭代器(光标)
这个模式建议提供一个方法,以顺序访问聚合对象的元素,同时隐藏底层实现。

上述图示描述了迭代模式的结构,其中迭代器接口定义了遍历方法,具体的迭代器实现了接口。聚合定义了一个创建迭代器对象的接口,而具体的聚合实现了聚合接口以创建对象。
这里是它的好处:
-
它支持聚合遍历中的变化
-
迭代器简化了聚合接口
-
它可能包含空迭代器,并有助于更好地处理边界条件
-
影响
-
它可能引入额外的维护成本(多态迭代器的动态分配)
-
它可能具有特权访问权限,因此引入了定义新遍历方法在迭代器中的复杂性
中介者
中介者模式提倡定义封装对象之间交互的方式,而不依赖于彼此的显式引用。

上述图示是中介者模式的典型结构,其中中介者或对话导演定义了一个与其他同事对象通信的接口;具体中介者通过协调同事对象来实现协作行为。
让我们看看它的好处:
-
限制子类化(通过本地化行为并限制行为分布到几个其他对象)
-
强制同事对象之间的解耦
-
简化对象协议(将多对多交互替换为一对一)
-
提供关于对象如何交互的明确说明
影响是集中控制,导致系统更加复杂和单一。
备忘录
此模式建议捕获和外部化对象内部状态,而不违反封装原则;因此,我们可以恢复捕获的对象。

上述图示展示了备忘录模式的结构以及一个计算器应用的示例实现。保管者接口帮助恢复在<<计算器>>具体类中处理的前一个操作。
这些是它的好处:
-
它通过暴露仅限于发起者的信息来保持封装边界
-
它简化了发起者
影响如下:
-
备忘录实现可能成本高昂,因为它需要复制大量数据以存储到备忘录中
-
它可能难以实现(通过某些编程语言)并确保只有发起者可以访问备忘录的状态
-
它可能在保管者实现中产生隐藏的存储和维护成本
观察者(依赖者/发布/订阅)
观察者模式建议当一个对象改变状态时,它通知其依赖者并自动更新。当实现需要一对多依赖关系时,您会想使用此模式。

上述图示展示了观察者模式的结构以及一个出版物应用的示例实现;每当发生事件时,订阅者都需要被告知。订阅者有不同的发布模式(短信、印刷和电子邮件),并且未来可能还需要支持新的模式,因此最合适的选择是观察者,正如我们刚才看到的。
让我们来看看它的好处:
-
实现了通信的轻松广播
-
支持对象之间的松散耦合,因为它能够将数据发送到其他对象,而无需对主题进行任何更改
-
主题和观察者之间的抽象耦合(观察者的变化不会影响主题)
-
可以随时添加或删除观察者
影响如下:
-
意外的或非预期的更新对系统影响很大,因为它会级联到下层的观察者
-
可能导致性能问题
-
独立的通告可能导致不一致的状态或行为(没有握手)
状态(状态的对象)
这些允许对象在其内部状态变化时改变其行为,并看起来像类变化一样。
当一个对象的行为依赖于其状态,并且运行时状态的变化依赖于该状态时,使用状态模式。

该图展示了状态模式的结构和示例实现;上下文类携带状态,Off和On类实现状态接口,以便上下文可以使用每个具体类的开/关操作。
列出的好处如下:
-
建议将特定于状态的行为本地化,并为不同状态划分行为(通过子类定义可以轻松添加新状态和转换)
-
使得状态转换明确
-
状态对象是可共享的
影响是,它可能使添加新的具体元素变得困难。
策略(策略)
策略模式,也称为策略,定义了一个算法家族或一组算法,封装每个算法,并使它们可互换。策略允许算法独立于使用它的客户端变化。当一组类仅在行为上有所不同时,最好将算法隔离在单独的类中,并提供在运行时选择不同算法的能力。

上述图显示了策略结构,以及排序算法(作为一个家族)的实现,它取决于输入的量,然后客户端可以使用预期的算法从具体的策略排序类中。
好处如上所述:
-
实现了开闭原则
-
实现了大规模的可重用性
-
消除了条件语句(导致代码清晰、职责明确、易于测试等)
影响如下:
-
客户需要了解不同的策略以及它们之间的差异
-
策略和上下文之间的通信开销
-
对象数量增加
模板方法
这表明提供算法操作的框架,并将一些步骤推迟到子类中。模板方法允许子类在不改变算法结构的情况下重新定义定义算法的几个特定操作。

以下是一些好处:
-
代码重用的基本技术
-
允许在委托实现特定部分到实现对象的同时部分实现业务流程(在创建原型时灵活)
-
帮助实现好莱坞原则(反转控制结构,别叫我们,我们会叫你)
影响如下:
-
流程的顺序可能导致混淆
-
维护成本高,对代码的任何更改影响都很大
访问者
访问者模式表示对对象执行的操作。它允许我们定义一个新操作,而无需更改它所操作的类元素。简单来说,我们使用访问者类来根据访问者的变化来改变算法的执行。
这里是它的好处:
-
在对象结构上添加新操作很简单且容易(通过添加一个新的访问者)。
-
访问者将无关操作分离并聚集相关操作。
影响如下:
-
当添加一个新的具体元素类时,访问者类层次结构可能难以维护。
-
实现通常迫使提供公共操作以访问元素的内状态(导致其封装性受损)。
并发模式
在软件范式中,软件应用能够同时执行多个任务(并发)是一个关键因素;大多数软件应用都有某种形式的并发。考虑到这一点,让我们简要地讨论一些并发模式,因为本书的其他章节详细介绍了许多(并发)相关模式。
并发设计模式
在许多情况下,自动化系统可能需要同时处理许多不同的事件,这被称为并发。面向对象编程提供了处理并发的充分手段(抽象、可重用性、分布式持久数据的共享、并行执行等)。本节将简要介绍一些并发模式。
生产者-消费者
生产者-消费者模式解耦了生产与消费数据的过程。该过程可能以不同的速率处理数据。生产者-消费者模式的并行循环可以分为两类:一类是生产数据,另一类是消费生产出的数据。
数据队列用于在生产者/消费者设计模式中的循环之间传递数据。这些队列在生产者和消费者循环之间提供数据缓冲。
活动对象
活动对象模式强制将方法执行与方法调用解耦,从而增强了并发性并简化了对驻留在它们(自己的)控制线程中的对象的同步访问。
我们使用此模式(实现同步)来处理多个客户端请求,以提高其服务质量。
监视对象
此模式建议对并发方法执行进行同步,以确保一次只有一个方法在对象中运行。监视器还允许对象的方法以协作的方式执行预定的序列。
我们使用此模式(实现同步)当多个线程调用修改对象内部状态的方法时。与活动对象相反,监视对象属于被动对象组;监视器没有自己的控制线程。
并发架构模式
半同步/半异步:在并发系统中,同步和异步服务处理的解耦带来了编程的简单性,而不会降低性能。半同步/半异步引入了两个相互通信的层,一个用于同步服务处理,另一个用于异步服务处理,中间有一个排队层。
此模式使得同步和异步处理服务能够相互通信,并帮助这些过程分解为层次。
领导者/跟随者:如果我们需要一个高效的并发模型,其中多个线程需要轮流共享一组检测、解复用、调度和处理事件源服务请求的事件源,那么在我们的系统中实现领导者/跟随者模式是最好的选择。
此模式的目的是提供一个优雅的解决方案,以同时处理多个事件,例如在多线程服务器应用程序中。
摘要
设计模式自 1992 年以来已经发展,即使在今天,在解决许多软件设计问题时,设计模式这种经过验证的技术和实践仍然是不可避免的。不难将任何特定的模式视为一种可以分析、实现和重用的解决方案或技术,但很难描述它解决的问题以及它最佳适用的情况。了解模式的目的至关重要,因为它有助于理解任何给定系统的现有设计。
通过本章,我们探讨了面向对象设计(OOD)的关键要素,包括抽象、封装、模块化和层次结构,以及一些额外的项目,如类型、并发性和持久性。
此外,我们还讨论了设计原则,希望读者能够对面向对象原则为面向对象软件设计师提供的帮助有一个SOLID的理解。我们相信,SOLID 原则是任何想要进入软件设计和开发领域的人的基本培训材料,即使在当今世界也是如此。
我们简要介绍了面向对象设计的三个广泛类别:创建型、结构型和行为型。我们还讨论了每种模式的益处和影响,以便读者能够轻松地描述它解决的问题以及它作为软件解决方案的最佳适用环境。
我们还增加了一个部分,希望读者能够对并发(设计和架构)模式有一个公平的介绍。
参考资料
以下表格是面向对象软件设计模式的交叉引用:

以下是一些参考书籍:
-
《设计模式:可复用面向对象软件元素》by Erich Gamma, Richard Helm, Ralph Johnson 和 John Vlissides
-
《面向对象分析与设计:应用篇》(第 2 版) by Grady Booch
本章的其他参考资料:
第四章:企业集成模式
本章将涵盖企业集成模式的更深入话题。这些话题包括:
-
集成模式的需求
-
企业中的集成场景
-
企业集成的主要挑战
-
开始使用消息模式
集成模式的需求
当今的企业由成千上万的应用程序组成。其中许多是商业化的现成应用;一些是内部应用,还有一些是长期作为企业一部分的遗留应用。尽管有数千个应用程序,但员工不可能使用单独的控制台分别访问每一个。
为什么企业需要这么多应用程序?这个问题的答案是,每个企业都有数千个业务功能,这些功能无法由单个应用程序完成。即使是像 ERP 这样的应用程序,与企业的实际需求相比,也只能执行非常有限的功能。
多个应用程序的另一个原因是,将各种功能分散到多个应用程序中可以确保更高的业务连续性水平,即即使一个应用程序失败,其他应用程序也会继续运行,而不会阻碍业务功能。
市场上的供应商也已经学会了开发专注于满足特定业务功能需求的应用程序的艺术。然而,随着各种业务功能动态的变化,供应商们正试图将多个功能集成到一个单一的业务应用程序中。例如,许多计费系统应用程序开始整合额外的会计功能。简而言之,在当前情况下,无法为应用程序定义清晰的边界。
用户,如客户和合作伙伴,往往在关注底层应用程序参与执行功能时不太关心。所有这些参数都要求在企业的生态系统中的各种应用程序之间有一个适当的集成机制。在过去,集成仅限于组织内部存在的应用程序。
在当今的背景下,有许多新的范例,如社交媒体应用、基于物联网(IoT)的应用、基于云的应用、支持微服务的应用等,仅举一些突出的例子。为了实现无缝的数据共享并支持企业内部业务流程,企业必须确保所有应用程序都是集成的。不同类型的应用程序使得企业需要为其集成平台开发一套强大的功能,以便他们能够在当今敏捷企业的动态环境中保持竞争力,这些企业处于不断变化的状态,以满足客户的需求和期望。
企业集成没有捷径。这是一个非常广泛且难以处理的领域,但对于当今的企业来说是不可避免的。企业集成模式不提供任何现成的代码,可以用于集成应用程序。实际上,它们建议经过验证和测试的方法来解决企业集成问题。如果正确使用,企业集成模式可以帮助组织填补其集成愿景与实际实施之间存在的巨大差距。
在下一节中,我们将检查企业中需要集成的各种不同场景。
企业集成场景
集成的概念是一个非常广泛的领域。然而,企业中最常见的集成场景包括以下几种:
-
信息门户
-
数据复制
-
共享商业功能
-
面向服务的架构
-
分布式商业流程
-
商业对商业集成
根据业务性质和它们处理的领域,企业可能会有几种其他场景。现在我们将检查一些突出的集成场景。
信息门户
组织中的许多用户将需要访问多个应用程序以执行单一的商业功能。例如,人力资源专业人士可能需要访问多个应用程序,如人才招聘、薪酬和福利、学习和开发、人才品牌等,以提取与人才管理各个方面相关的详细信息。这种场景使得他们难以以适当的速度执行日常业务功能。这就是信息门户概念对他们有所帮助的地方。信息门户可以从不同的系统中获取信息,汇总并在单一视图中展示。简单的信息门户将显示屏幕划分为几个区域。每个区域将显示来自特定应用程序的数据。这些信息门户还具有根据用户在另一个区域选择的信息在某个区域提供钻取信息的功能。以下是一个信息门户的示例:

数据复制
在企业中,许多应用程序将拥有相同数据的副本。例如,客户详细信息可能存在于订单管理系统、计费系统、广告和促销系统中等。因此,如果在一个系统中更新了地址,则必须确保在其他系统中也进行更新。复制是确保这种所需一致性的技术之一。数据复制是如何进行的?许多组织定义了政策,确保数据在规定的时间间隔内持续同步和复制,以确保所有系统上的数据保持最新。另一种技术是将数据导出到文件中,然后导入到其他系统中。另一种称为面向消息的中间件的技术用于将数据记录嵌入到消息中,并将它们发送到其他应用程序以进行同步目的:

共享业务函数
如果同一组数据存储在多个系统中,会导致数据冗余。用于处理这些数据的功能(如前例中的客户地址)可以一次实现为共享业务函数,并作为服务暴露给具有相同数据集的其他系统。
共享业务函数可以用作良好的功能来替换冗余数据。例如,让我们以客户地址为例,该地址存储在组织内的多个系统中。而不是在多个系统中存储相同的数据,一个名为GetCustomerAddress的业务函数可以被系统用来从其他系统中获取数据,而不是永久存储它。
使用冗余数据与共享业务函数之间的权衡基于几个标准。定义这些标准的参数包括以下内容:
-
对数据所在系统的控制程度(在某些情况下,调用
共享函数可能比将数据加载到数据库中更耗费资源) -
考虑的数据变化率(例如,客户地址可能非常频繁地需要,而可能很少改变)
以下是一个展示使用共享函数的图示:

面向服务的架构
我们之前讨论的共享业务函数通常被称为服务。服务通常是一个定义良好的函数,它对所有系统普遍可用,以执行特定操作。这些服务可供其他作为服务消费者的系统使用。一旦创建了一组服务,确保它们以适当的方式维护并提供给其他系统就非常重要。服务管理的两个重要方面如下:
-
服务发现:所有服务都通过一个集中的服务目录提供,其他应用程序可以通过该目录发现它们
-
服务协商:每个服务必须以这种方式描述其接口,使得企业中的其他应用能够与他们协商并建立通信合同。
面向服务的架构(SOA)也是一种应用集成的机制,这反过来又模糊了集成和分布式应用之间的界限。SOA 在第七章,《面向服务架构(SOA)》中进行了详细讨论。描述 SOA 的框图如下:

面向服务架构的另一个重要方面是企业服务总线(ESB)的概念,它以松耦合的方式提供 SOA 发送者和接收者组件之间的连接性。
分布式业务流程管理
正如我们之前讨论的,一个单一的商业功能可以分布在企业中存在的几个应用中。在这种情况下,确保各种应用之间的协调非常重要。这可以通过实施业务流程管理系统来实现。业务流程管理系统将与属于特定商业功能的全部相关应用协调,并确保无缝执行。然而,在这个背景下,重要的是要记住,业务流程管理和 SOA 之间存在一条非常模糊的界限。始终存在所有服务都作为服务提供,而一个业务流程功能可以作为应用程序提供,以便通过 SOA 访问所有服务的可能性。分布式流程管理系统的图示如下:

商业对商业集成
如本章开头所述,当今的企业需要与其生态系统之外的多个组件进行交互,例如客户、合作伙伴等。这些外部元素需要访问企业的一部分应用。例如,在产品组织的案例中,将会有几个合作伙伴实施产品的一部分服务。在这种情况下,合作伙伴能够访问一些关键的企业应用以了解新产品功能、更新、学习资源、产品用户论坛和群组非常重要。反之亦然,企业也严重依赖某些外部组织的一些功能,因此确保某些外部应用向企业传输数据非常重要。这些场景引发了需要企业对企业集成的情形。这并不是一个像企业内部应用集成那样非常直接的情况。这主要是因为在企业对企业集成时,还需要考虑许多其他方面,如安全性、法律影响和治理,以实现顺利集成。描述企业对企业集成场景的图形如下:

在下一节中,我们将分析在集成企业应用时存在的各种挑战。
企业集成的主要挑战
与企业应用集成相关的一些主要挑战如下:
-
网络速度慢且不可靠:企业集成应用需要将数据从一个应用传输到另一个应用。这些应用可能位于不同的州、国家或大陆。在这种情况下,数据需要通过 LAN、WAN 或两者的组合进行传输。通过不同的网络拓扑和协议传输数据引入了显著的传输延迟和其他类型的干扰,这些干扰成为企业应用集成的绊脚石。
-
异构应用平台:在集成多个应用时,重要的是要记住每个应用都将有自己的平台和操作系统。为了确保这些应用之间无缝集成,必须确保数据在应用之间以所有相关应用都能理解的形式进行传输。为了实现这一点,应该有一个中间件组件,将数据转换为所有应用都能理解的通用格式。
-
应用更新和升级:集成的应用将因系统更新而不断进行升级。在某些情况下,某些系统升级将对整体应用引入重大变化。这可能会影响所有参与集成的其他应用。对于集成解决方案来说,最小化集成中各个应用之间的依赖关系非常重要。实现这一目标的一种方法是通过确保应用之间的松散耦合。
-
安全性:在医疗保健和保险等领域的某些应用受到严格的网络安全政策和框架的约束。如果这些应用参与集成过程,遵守安全指南非常重要。否则,将导致违反法律指南。
用于克服上述挑战的一些关键技术如下:

让我们简要讨论这些技术。
文件传输
在这里,文件是需要在集成的应用之间传输数据的基本模式。一个应用将对文件执行写操作,该文件将被另一个应用读取。然而,为了成功执行并产生必要的影响,涉及的应用就以下关于文件的参数达成一致非常重要:
-
文件名和位置
-
文件格式
-
写入和读取文件的时间
-
文件将如何被删除
共享数据库
在这种情况下,数据库成为集成发生的点。需要集成的多个应用共享一个共同的数据库模式,该模式位于同一个数据库中。这防止了重复数据存储,并防止了从应用之间进行数据传输的需求。
远程过程调用
在这种情况下,应用的集成是通过一个应用暴露的功能来实现的。其他应用作为远程过程远程访问这些功能。将功能作为远程过程调用的过程称为远程过程调用。远程过程调用是实时发生的,是一种同步通信。
消息传递
在这种情况下,应用的集成是通过消息传递来实现的。其中一个应用向一个所有其他应用都可以访问的消息通道发布消息。其他应用访问消息通道并在稍后的某个时间点获取消息。这里唯一的条件是,涉及的应用应该就消息通道和发送到通道的消息格式有一个预定义的协议。在下一节中,我们将深入探讨消息传递的概念以及企业应用如何通过消息传递的概念进行集成。在下一节中,我们将深入探讨各种消息传递模式。
开始使用消息模式
消息传递是一种可靠的连接应用程序的技术,它使用称为消息的包的概念。这些包被发送到通道,这些通道是逻辑路径,提供各种应用程序之间的互连。这些通道也称为队列。可以在通道中排队多个消息,并在同一时间点使多个应用程序可访问。在消息传递中,主要有两种类型的应用程序,它们是:
-
发送者/生产者
-
接收者/消费者
发送者是一个向通道发送消息的应用程序。接收者是一个读取发送到通道的消息的应用程序。消息传递是一种异步通信模式,这意味着接收者不必在消息到达通道后立即从通道中读取消息。
消息可以是任何类型的数据结构,例如数组、字符串或对象。每个消息包含两个部分:
-
标题
-
消息体
标题包含有关消息的元数据,例如发送者、接收者、时间戳等详细信息。这些信息由消息系统使用,但通常被应用程序忽略。消息体包含应用程序实际发送的数据。消息体被消息系统忽略,但被应用程序使用。
消息传递功能由一个称为面向消息的中间件(MOM)的专用软件应用程序提供。MOM 也称为消息系统。MOM 是确保消息在应用程序之间平稳传输所必需的。MOM 存在的一个主要原因是连接系统的网络不可靠状态。即使应用程序发送了消息,如果网络不正常,也不一定能够到达预期的目的地。MOM 有助于克服这种与网络相关的限制和其他限制,并确保消息在到达目的地之前会重复传输。以下图表展示了通过消息传递的应用程序通信:

消息传输涉及的五个步骤如下:

在这些步骤中的每一个,都会执行以下活动:
-
创建: 在这一步,发送者或生产者添加标题和数据,创建消息
-
发送: 在这一步,发送者将消息发送到通道
-
投递: 在这一步,消息队列(MOM)将消息从发送者的系统移动到接收者的系统,使消息对接收者可用
-
接收: 在这一步,接收者或消费者从通道中读取消息
-
过程: 在这一步,接收者从消息中提取数据
在下一节中,我们将探讨在企业系统设计中使用的突出消息模式。
管道和过滤器模式
在许多情况下,单一事件可能触发一系列动作,每个动作将执行特定的功能。因此,管道和过滤器模式被用来处理需要复杂消息处理同时保持灵活性和独立性的情况。一个大任务被分解成一系列较小的、顺序的、独立的任务(过滤器),这些任务通过通道(管道)连接起来。管道和过滤器模式的图示如下:

每个过滤器都有一个简单的接口,它由一个接收、处理并将结果发布到输出管道的输入管道组成。管道的作用是将一个过滤器连接到下一个过滤器。在管道和过滤器模式中,所有组件使用相同的外部接口,因此它们可以存在于不同的解决方案中。这些解决方案可以通过不同的管道相互连接。提供管道和过滤器之间连接的连接出口称为端口。通常,每个过滤器有一个输入端口和一个输出端口。
消息路由模式
这种模式用于那些步骤的顺序执行可能并不总是可行的情况。在某些情况下,过滤器的输出可能需要根据某些标准或条件传递到几个管道之一。在这种情况下,会使用消息路由模式。描述消息路由模式的图示如下:

消息翻译器模式
在本章的开头,我们讨论了可能需要将某些第三方应用程序/合作伙伴应用程序集成到企业中的一些应用程序的场景。这些应用程序将使用不同的数据模型,有时可能使用完全不同的数据格式进行通信。对于当今敏捷的企业来说,使用能够通过将数据从一种格式转换为另一种格式来连接不同类型应用程序的模式是必要的。这就是消息翻译器模式发挥关键作用的地方。消息翻译器模式充当其他过滤器或应用程序之间的特殊过滤器,将数据从一种格式转换为另一种格式。描述消息翻译器模式的图示如下:

消息端点模式
企业应用通过消息通道发送消息来相互通信。但接下来需要解决的问题是需要有一个机制来帮助应用连接到消息通道。这对于发送应用发送消息和接收应用接收消息都是适用的。这就是消息端点模式出现的地方。消息端点充当消息系统的客户端,发送和接收应用可以使用它来发送和接收消息。消息端点代码对应用和 MOM 的客户端 API 都是可访问的。剩余的应用不知道关于消息格式、消息通道或它通过消息通信的其他应用的任何细节。它只知道它已经向另一个应用发送了一些数据,或者它将接收来自另一个应用的数据。消息端点代码接收数据,将其转换为消息,并发送到正确的消息通道。同样,在接收端,消息端点接收消息,提取内容,并将其交给应用。描述消息端点模式的图如下:

点对点通道模式
考虑一个应用使用消息进行远程过程调用的场景。在这种情况下,必须确保只有一个接收者执行调用。这就是点对点通道模式帮助我们的地方。如果通过点对点通道发送消息,它将确保只有一个接收者会收到消息。如果通道有多个接收者,只有其中之一能够接收到消息。如果有多个接收者尝试消费消息,通道将确保其中只有一个能够成功。但这并不阻止通道有多个接收者,并且它们可以同时接收多个消息。这里唯一的条件是只有一个接收者会收到特定的消息:

发布-订阅通道模式
这种模式将适用于使用消息来宣布事件的那些应用。事件的宣布将涉及同时向多个接收者发送消息。如果消息是在发布-订阅通道上发送的,消息的副本将被发送到每个接收者:

发布-订阅通道基本上就像一个广播机制。它有一个输入通道,该通道被分成几个输出通道,每个订阅者一个。当一个事件在通道中发布时,消息的副本被发送到与之相连的每个输出通道。每个输出通道只有一个订阅者。每个订阅者只能消费消息一次。这样,每个订阅者只能得到一次消息,一旦被消费,消息副本就会从通道中消失。
数据类型通道模式
如果通过一个通道传输多种类型的数据,区分各种数据格式就很重要。这就是数据类型通道模式派上用场的地方。数据类型通道模式的图示如下:

如果为每种类型的数据使用数据类型通道,特定通道上的消息将只包含相同类型的数据。发送者应该知道数据的类型,并通过适合该类型数据的适当通道发送它。接收者应该能够根据接收数据所在的通道知道数据的类型。
消息总线模式
在企业中,将存在几个不同的系统。这些系统应该能够相互通信和共享数据,以便企业能够无缝地运作。这就是消息总线模式派上用场的地方。消息总线模式的架构在以下图中展示:

如果各种应用程序通过消息总线相互连接,它允许它们通过消息无缝地通信。以下是一个消息总线的主要组件:
-
通用数据模型
-
常用命令集
-
消息基础设施:该组件允许各种系统通过共享的接口进行通信
消息总线概念与计算机中使用的通信总线概念非常相似。通信总线促进了计算机各个组件(如 CPU、内存、外围设备等)之间的通信。
命令消息模式
如果一个应用程序想要调用另一个应用程序提供的功能,最常用的方法是远程过程调用。但如果必须结合消息的概念使用远程过程调用,命令消息模式就非常有用。命令消息模式的图示如下:

命令消息是一种可靠地用于调用在另一个应用程序中运行的程序的消息。命令消息没有特定的类型。命令消息是嵌入命令的正常消息。
事件消息模式
几个应用程序通过事件相互通信。如果基于消息的事件通信发生,则使用事件消息模式。以下图示了事件消息模式:

在事件消息模式中,如果主题需要宣布一个事件,它将首先创建一个事件对象。然后,这个对象被封装在一个消息中,并通过一个通道发送。观察者将从通道接收事件并处理它。事件中的消息传递不会改变事件通知;它只是确保通知到达观察者。
请求-回复模式
当应用程序通过消息通信时,通常是单向通信。假设如果应用程序想要双向通信,那么将使用请求-回复模式。在请求-回复模式中,请求消息和回复消息将有自己的通道。请求-回复模式的图示如下:

基于内容的路由器模式
在许多企业中,单个功能分布在几个系统中。在这种情况下,确保消息通过包含该功能的每个系统非常重要。在这种情况下,基于内容的路由器模式非常有帮助。以下图示了基于内容的路由器模式:

基于内容的路由器模式检查消息的内容,然后根据消息中包含的数据将消息路由到正确的通道。消息路由的参数可能是以下之一:
-
某些特定字段中存在或不存在某些数据值
-
消息中某些字段的呈现或缺失
在内容路由器中,确保实现的路由功能易于维护非常重要。也可以将基于内容的路由器维护为一种规则引擎,该引擎根据一组预配置的规则计算目标通道。
消息过滤器模式
在许多场景中,我们可能会对接收某些促销消息/折扣消息感兴趣,例如来自一个你可能感兴趣购买产品的电子商务网站。但这可能不适用于所有消息。因此,在这种情况下,确保不希望的消息被阻止或过滤非常重要。在这种情况下,消息过滤器模式非常有用。以下图示了消息过滤器模式:

消息过滤器只有一个输出通道。如果消息中的数据与消息过滤器提到的特定输出标准匹配,则消息将被路由到输出通道,否则将被丢弃。
重新排序模式
当使用消息路由模式时,消息会根据某些标准或规则的满足情况进行路由。但是,当消息通过多个系统时,它们可能会出现顺序混乱。在这些情况下,重排序器模式就派上用场。描述重排序器模式的图示如下:

重排序器是一个有状态的过滤器,可以用来重新排序消息,以便它们可以按照特定的顺序发布到输出通道。重排序器包含一个内部缓冲区,用于存储一系列消息,直到获得完整的序列。顺序正确的消息会立即发布到输出通道。顺序不正确的消息将保留在内部缓冲区中,直到它们被放置在正确的顺序,然后发送到输出通道。重排序器只是确保消息的顺序,通常不会修改消息的内容。
轮询消费者模式
在某些情况下,应用程序可能并不总是准备好消费消息。在这种情况下,应用程序希望在开始消费消息之前达到一个准备就绪的状态。在这种情况下,轮询消费者模式非常有帮助。轮询消费者模式的图示如下:

在这个模式中,应用程序使用轮询消费者,它在准备好接收消息时进行调用。轮询消费者也被称为同步接收器。这是因为接收线程在接收到消息之前处于阻塞状态。大多数消息 API 都提供了一个receive方法,该方法会阻塞直到消息被投递。
通道适配器
如果应用程序通过消息传递进行通信,确保应用程序可以连接到消息系统以发送和接收消息是必要的。这就是通道适配器发挥作用的地方。描述通道适配器模式的图示如下:

通道适配器应该能够访问应用程序的 API 或数据,并根据这些数据在通道上发布消息。它还应该能够调用应用程序内的功能并接收消息。理想情况下,适配器充当消息系统的客户端。通道适配器通过应用程序提供的接口调用应用程序的功能。这有助于应用程序在拥有适当的通道适配器的情况下与消息系统保持集成。在下一节中,我们将关注移动集成模式,即用于将移动设备集成到企业系统中的模式。
移动集成模式
我们需要一个更快的方法来使移动设备与企业服务集成,这需要移动集成模式。当我们谈论移动服务与企业集成时,在集成过程中可能会出现两种主要可能性:
-
与企业某些功能集成的移动应用程序向企业系统发送请求消息,并得到相应的响应
-
企业系统向移动应用程序发送推送通知消息
以下图表显示了该流程:

请求-响应模式
为了定义请求-响应模式,必须确保在 ESB 中创建的企业服务中存在移动就绪的接口。此模式为在 ESB 架构中集成移动服务提供支持。一种专门为移动服务定制的适配器,称为移动集成适配器,有助于将移动应用程序与在 ESB 中运行的与移动相关的服务集成。以下图表展示了该移动集成涉及的主要步骤:

下面是如何进行集成的:
-
作为第一步,移动适配器将传入请求直接发送到企业服务。
-
然后,存在于 ESB 中的企业服务与所需的后端系统建立连接以处理传入请求。ESB 还与后端系统协作以获取响应。
-
最后,ESB 将响应发送到移动适配器,然后适配器将响应回传给移动应用程序。
定义推送通知模式
如果企业应用程序想要向移动设备发送推送通知,则使用推送通知模式。定义推送通知涉及的步骤在以下图表中展示:

企业应用程序通常使用在移动集成服务器上运行的后端服务来将通知消息推送到设备。以下是该流程的主要步骤:
-
企业应用程序使用 ESB 和移动后端服务向移动设备发送推送通知
-
一旦 ESB 收到通知,它就调用移动后端服务向移动设备发送推送通知
-
消息通过移动集成服务器传递,以到达移动应用程序和移动设备
在本章的开头,我们讨论了几种外部应用程序与企业系统集成的类型。在下一节中,我们将概述 API 管理模式。在本节中,我们将简要关注在架构中使用基于微服务/API 的设计概念时的集成方面。
API 管理模式
API 管理模式通过 API 将应用程序与企业系统和其他基于云的服务集成。以下是 API 管理模式的主要组成部分:
-
API 管理门户
-
API 用户
-
企业服务
每个 API 服务的消费者首先向 API 管理门户发送请求。API 管理门户在向消费者发送响应之前与企业服务进行交互。API 使用行业标准的消息格式,例如,对于 Web 服务使用 SOAP,对于表示状态转移使用 XML 或 JSON。API 管理门户充当简单的代理,并帮助将请求和响应消息转发到后端。
摘要
在本章的开始,我们检查了企业中存在的一些集成场景。企业中存在的一些关键集成场景包括以下内容:
-
信息门户
-
数据复制
-
共享业务功能
-
面向服务的架构
-
分布式业务流程
-
商业对商业集成
在涵盖这些主题之后,我们讨论了在应用集成中面临的主要挑战。同时也讨论了克服这些挑战的技术。在章节的下一段,我们详细讨论了几种消息模式。在消息模式之后,我们讨论了突出的移动集成模式。我们以对 API 管理模式的简要讨论结束了本章,这是行业中最新的趋势。
第五章:领域驱动设计(DDD)原则和模式
大多数商业软件应用都是通过一组复杂业务需求创建的,以解决特定的业务问题或需求。然而,期望所有软件开发者/架构师都是业务领域的专家,并期望他们了解整个业务功能也是不切实际的。另一方面,我们如何创建具有价值的软件,并让具有自动化业务需求的消费者使用该软件?软件应用不能只是技术卓越的展示品,但在大多数情况下,它们也必须具有真正的自动化业务卓越的便利性。领域驱动设计和模型是我们问题的答案。
本节将涵盖大多数 DDD 方面和模式,这些模式有助于成功实施基于 DDD 的软件。

上述图表是尝试通过领域和技术专家的协作努力来可视化由领域驱动软件模型。
DDD 的概念、原则和模式将技术和商业卓越结合到任何复杂的软件应用中,这些应用可以创建和管理。DDD 是由 Evan 提出的,本章的大部分内容受到了他的书籍《领域驱动设计 - 软件核心的复杂性处理》的影响,同时也受到了 Scott Millett 和 Nick Tune 的书籍《模式-原则-实践》的影响。
本节旨在涵盖 DDD 的一些基本方面,并详细讨论一些常见的领域驱动设计模式。
DDD 的原则、特性和实践
在我们深入各种设计模式之前,让我们先谈谈 DDD 的基本原则,然后是一些主要特性组成部分,以及一些最佳实践,这些实践有助于团队采用和遵循 DDD。
原则
DDD 的基本原则在以下章节中描述。
专注于核心领域
这一原则建议产品开发团队更多地关注核心领域,即对业务最重要的部分,这些部分比其他部分需要更多的关注。因此,我们需要通过提炼和分解一个大问题领域到子领域来识别核心领域。例如,在设计零售银行软件时,我们应该关注信贷和借记会计,而不是信用卡和借记卡的制造和分销,因为它们是支持功能,也可以外包。
协作和学习
正如我们在引言部分提到的,软件专家可能不了解领域,而领域分析师可能不了解技术和软件实现。因此,对于领域驱动设计(DDD)方面,相互协作和学习是不可避免的,没有这种协作,软件开发或开发根本不会发生。例如,为了开发一家投资银行的后台软件应用程序,风险管理专家和软件专家需要一起工作,学习系统、适用性、可用性、银行客户的意图等等。
在最近的日子里,传统银行正在与金融科技公司(fintech)合作,因为他们看到数据分析、人工智能(AI)和机器学习在核心银行系统中的显著益处,这将使他们能够做出准确的决策,更快地进行创新,并解决银行业日常问题。
建模领域
正如我们从上一节中理解到的协作和学习原则,协作、深入学习和获取核心领域的洞察力,以及基本功能,这是不可避免的。模型领域原则的预期输出是一个领域模型,它是在核心领域空间中组织良好和结构化的知识,包括基本概念、词汇、问题以及涉及实体的关系。你可以从不同的利益相关者那里寻求贡献,如分析师、领域专家、商业伙伴、技术熟练的用户和核心开发者,并构建这些领域模型,这样团队中的每个人都能理解功能概念和定义,以及当前问题是如何被解决和处理的。
演进
领域模型的关键方面之一是演进。领域模型需要通过迭代和反馈随着时间的推移而演进。设计团队从一个重要问题开始,随着生成模型的增量变化,迭代地穿越核心领域的不同范围。这至关重要,因为模型需要调整以适应领域专家的反馈,同时处理复杂性。
使用通用语言进行交流
协作、学习和定义模型会在软件专家和领域专家之间带来许多初始的沟通障碍。因此,通过在特定上下文中实践相同类型的沟通(讨论、写作和图表)来演进领域模型对于成功的实施至关重要,这种对话被称为通用语言。它是围绕领域模型构建的,并在有限上下文中被所有团队成员广泛使用。它应该是连接团队在软件开发过程中所有活动的媒介或方式。
设计团队可以建立深入的理解,并通过通用语言将领域术语和软件实体联系起来,以持续发现和演进他们的领域模型。
特征
以下特征是主要组成部分,可能作为我们将在此章节中讨论的项目词汇表。您将看到其中许多都被纳入了我们在此部分中提出的模式中:
-
领域模型:与特定问题相关的组织化和结构化知识。
-
边界上下文:一个系统满足现实世界复杂业务问题的基本目标,提供对什么是可以一致的以及什么是可以独立的清晰和共享的理解。
-
实体:这些是可以改变其属性而不改变其身份的可变对象(例如,即使员工的电子邮件 ID、地址和姓名发生变化,员工的 ID 也不会改变)。
-
值对象:这些是不可变对象(与实体不同),只能通过其属性的状态来区分。值对象的等价性不是基于其身份的。(两个位置对象可以通过其经纬度值相同。)
-
封装:对象的字段仅公开供私有访问,换句话说,只能通过访问器方法(设置器和获取器)检测到。
-
聚合:这是实体(例如,计算机是软件和硬件等实体的聚合)。聚合可能在没有这些对象的情况下无法工作。
-
聚合根:这是聚合的入口点,也是任何外部对象的已知引用。这有助于为聚合创建精确的边界。
最佳实践
我们列出了一些针对打算在软件开发产品开发中采用 DDD 的团队的最佳实践:
-
收集需求并捕获所需的行为
-
关注利益相关者想要什么、何时以及为什么
-
提炼问题空间
-
首先成为一个问题解决者,其次才是技术专家
-
使用抽象和创建子域来管理复杂性
-
使用上下文映射和边界上下文来理解现实世界的景观
-
建模解决方案,解决歧义,并划出安全区域
-
将隐含的概念明确化
DDD 模式
在本节中,我们将浏览一系列模式,从领域模型构建企业应用程序。将这些设计模式与面向对象概念结合应用于系统,有助于满足业务需求。
本节涵盖了 DDD 设计模式的重大方面,分为战略设计模式和战术设计模式。
战略模式
该小组的主要目标是促进业务和软件开发团队之间的理解和共识,更侧重于业务利益和目标。战略模式帮助软件开发团队成员通过识别核心领域来关注对业务更重要和关键的事情。核心领域是公司的一个特定领域,甚至是一个关键的特定部分。
战略模式的主要组成部分包括通用语言、领域、子领域、核心领域、边界上下文和上下文映射。我们将看到如何通过本章讨论的战略设计模式,如边界上下文、消息传递和 REST,将这些组成部分整合到不同的系统中。
通用语言
一个模型充当通用语言,以管理软件开发者和领域专家之间的沟通。以下表格展示了通用语言及其等效伪代码的示例:
| 通用语言 | 等效伪代码 | 注释 |
|---|---|---|
| 我们注射疫苗 | AdministerVaccines {} |
不是核心领域——需要更多具体细节 |
| 我们向患者注射流感疫苗 | patientNeedAFluShot() |
更好,可能缺少一些领域概念 |
| 护士以标准剂量向患者注射流感疫苗 | Nurse->administer vaccine(patient, Vaccine.getStandardDose()) |
更好,可能是一个好的开始 |
领域、子领域和核心领域
领域指的是软件团队试图为其创建解决方案的问题空间,并代表实际业务的工作方式。表中的疫苗示例可以被视为领域,具有端到端流程,管理疫苗接种、预防性药物、剂量、副作用等。核心领域是组织不希望外包的核心业务。因此,在这个上下文中,核心领域是疫苗接种,而其他如患者管理、疫苗成本、疫苗接种活动等职能是子领域,并且位于核心领域之外。核心领域与子领域相互作用。
边界上下文
边界上下文是独特的概念线条,定义了边界并将上下文与其他系统部分区分开来。边界上下文代表了精细的业务能力,并且是领域驱动设计(DDD)的焦点。它通过将它们划分为不同的边界上下文并明确它们的相互关系来处理大型分布式模型和团队。

在我们深入探讨模式之前,让我们先回顾一下边界上下文的概念。前面的图示显示了两个上下文中的账户;尽管账户没有差异,但上下文是有区别的。以下几节将讨论有助于整合任何 DDD 解决方案的边界上下文的模式。
集成边界上下文
边界上下文有助于识别子系统之间的关系,因此可以选择子系统之间的通信方法。选择适当的通信并建立与现有通信的关系是设计者的责任,这也有助于他们确保不会影响项目交付的时间表和效率。一个集成和建立通信的例子可能是将支付系统与电子商务销售系统集成。选择通信方法至关重要,我们将在以下章节中看到更多关于集成边界上下文的内容。
自主边界上下文
为了确保原子性,设计松散耦合的系统,减少依赖;解决方案也可以独立开发。
无共享架构
在保证边界上下文自给自足的同时,保持边界上下文的完整性也是至关重要的。无共享模式建议每个边界上下文都有自己的数据存储、代码库和开发者,如下面的图所示:

由于每个边界上下文在物理上是隔离的,它可以独立于内部原因进行演变,从而产生无妥协的领域模型,以及超级高效和更快的业务价值交付。
单一职责代码
按照业务能力对软件系统进行分区是一种最佳实践,即通过将不同的业务能力隔离到不同的边界上下文中。例如,业务中的运输代码不会受到添加到销售的新运输提供商的影响。
多个边界上下文(在解决方案内)
根据代码(语言)、部署和基础设施,存在不同边界上下文位于同一代码仓库或具有组合上下文的解决方案中,以描绘完整业务用例的整体图景的情况。

为了维护解决方案内的不同上下文,此模式建议保持命名空间区分或建议项目将边界上下文分开。
采用 SOA 原则
使用 DDD 和 SOA 概念和模式构建高度可扩展的系统。将边界上下文作为 SOA 服务构建,以解决边界上下文集成中的技术和社交挑战(集成团队和高速开发)。请参阅第七章,面向服务的架构 (SOA),以了解更多关于 SOA 原则和实践的细节。
与遗留系统集成
遗留系统在现实世界中总是存在,当我们试图将最新的行业改进融入其中时,它们会带来令人兴奋的挑战。在 DDD 中,这个问题更有趣,因为有许多实用的模式可以帮助限制遗留系统对系统其他部分的影响,管理复杂性,并帮助设计师避免在将新代码集成到遗留模块或组件时降低其显式性(违反 DDD 哲学)。
在本节中,我们将讨论气泡上下文、自主气泡上下文,并将遗留系统作为服务进行展示。
气泡上下文
如果一个团队想要开始将领域驱动设计(DDD)应用于遗留系统,但尚未熟悉 DDD 实践,那么可以考虑气泡上下文模式。由于遗留系统中的边界上下文可能是一个独立的代码库,气泡上下文模式提供了清晰的方向,帮助团队创建领域模型并不断演进。气泡上下文反映了 DDD 迭代哲学的最好方面,并通过完全控制领域模型来推进。
它被认为是最适合促进频繁迭代并在涉及遗留代码的情况下获得洞察力的。

当你需要与遗留代码集成,但又不想像气泡上下文那样创建任何依赖或紧密耦合时,这种模式建议使用一个名为自主气泡上下文的匿名气泡。气泡上下文从遗留系统中获取所有数据,而自主气泡上下文有自己的数据存储,并且能够在与遗留代码或其他边界上下文隔离的情况下运行。

上述图示展示了自主气泡上下文,你可能注意到气泡上下文与遗留上下文存在依赖关系。然而,自主气泡上下文有自己的存储,因此它可以独立运行。
反腐层
隔离层通过其现有的接口与其它系统进行通信,几乎不需要(对其他系统)进行修改,并为客户端提供其自身领域的功能。这一层负责在两个模型之间按需进行双向通信的转换。
作为服务公开
将遗留系统作为服务公开可能是一个好主意,特别是当遗留上下文需要被多个新的上下文消费时。这种模式也被称为开放主机模式。

每个新的上下文仍然需要将遗留系统的响应转换为内部表示;然而,通过简化的开放主机 API,可以减轻转换复杂性。
使用这种模式,需要对遗留上下文(与气泡上下文不同)进行一些修改;此外,由于有多个消费者,标准化可消费 API SLA 可能具有挑战性。
我们可以清楚地证明,现实世界中许多遗留系统都希望采用领域驱动设计(DDD);然而,由于缺乏合适的模式和考虑到成本和影响,有真正的理由和犹豫不决去转向 DDD。识别和利用这些模型应该会缓解情况,并鼓励组织为他们的遗留系统采用 DDD,并朝着更快交付的方向发展。
分布式边界上下文集成策略
在现代世界中,由于各种原因,分布是不可避免的,主要是为了系统能力,如可用性、可伸缩性、可靠性和容错性。本节简要介绍了分布式边界上下文的一些集成策略,例如数据库集成、平面文件集成、消息传递和 REST。我们将探讨这些模式如何帮助集成分布式边界上下文。此外,我们还将简要了解反应式解决方案如何帮助集成策略。
数据库集成
数据库集成模式是使用单个数据源的传统方法之一,允许一个应用程序写入特定的数据库位置,并允许另一个应用程序从中读取。另一个应用程序的访问可以通过一定频率的轮询来实现。这种模式对于原型或甚至对于最具可行性的产品(MVP)的交付可能很有用。

上述图示展示了数据库集成的一个示例,其中销售团队插入记录,计费上下文轮询相同的数据源。如果它找到销售记录,它将处理并更新同一行。
虽然此模式具有松耦合的优点,但也存在一些缺点,例如单点故障,需要有效的故障处理机制等。数据库宕机场景是一个单点故障的例子,为了缓解,可能需要采用集群数据库,购买更多硬件以进行扩展,或者考虑云基础设施等。
平面文件集成
平面文件集成模式类似于数据库集成;然而,它不是使用数据库来集成两个组件,而是建议使用平面文件。更新、插入和轮询的需求就像在其他模式中一样,但这一点更为灵活。然而,这也带来了一些缺点,如管理文件格式、并发性和锁定等问题,需要更多的参与和努力,从而导致可伸缩性和可靠性问题。

此图是平面文件集成的示例实现,涉及轮询、更新和删除。
事件驱动架构和消息传递
消息和事件驱动架构模式将分布式系统中边界上下文之间的建模发挥到极致。在本节中,DDD 旨在确保您理解 EDA 和消息模式在 DDD 上下文中的重要性。同时,强调在上下文之间实现异步消息和 EDA 模式的好处。这些好处包括即使在子系统失败的情况下也能提高可靠性。我们在第八章事件驱动架构模式和第九章微服务架构模式中已经很好地覆盖了 EDA 和消息模式,并鼓励您参考这些章节,以获得关于事件驱动和消息模式的见解。
战术模式
战术模式有助于管理复杂性,并在域模型的行为中提供清晰性。这些模式的主要重点是保护模型免受损坏,通过提供保护层来实现。
在本节中,我们将简要介绍一些有助于创建面向对象域模型的常见模式。
在本节的结尾,我们还将简要介绍事件源和域事件的兴起模式。
用于建模域的模式
本节将讨论一些战术模式,并解释它们如何表示问题域内的策略和逻辑。它们在代码中表达模型元素,对象与模型规则之间的关系,并将分析细节绑定到代码实现。
我们将详细讨论以下模式:
-
实体
-
值对象
-
域服务
-
模块
-
聚合
-
工厂
-
仓库
下图展示了各种战术模式及其逻辑流程:

实体
如介绍部分所述,实体是一个可变对象。它可以改变其属性而不会改变其身份。例如,产品是一个实体,它是唯一的,一旦设置,就不会改变其 ID(独特性)。
然而,其价格、描述等可以根据需要更改多次。

前面的图展示了实体及其示例。员工 ID 是唯一的,永远不会改变。然而,有一个可以通过访问器方法修改的联系方式。
实体具有以下属性:
-
它们由其标识符定义
-
标识符在其整个生命周期中保持不变
-
它们负责进行等式检查
值对象
与实体不同,值对象是不可变的,用作模型元素的描述符。它们只通过其特征为系统所知,并且不需要有唯一的标识符。它们始终与其它对象相关联(例如,销售订单中的交货地址可以是值对象),并且始终与销售订单上下文相关联;否则,它们没有任何意义。

上述图示展示了值对象的基本概念和示例,以下图示是实体和值对象的示例类表示:

以下列表描述了值对象的特征:
-
它们描述了问题域内的属性和特征
-
它们没有标识符
-
它们是不可变的,也就是说,对象的内容不能被更改;相反,作为值对象建模的属性必须被替换
领域服务
在通用语言中,存在某些操作无法归因于任何特定实体或值对象的情况,这些操作可以称为领域服务(不是应用服务)。
领域服务封装了可能无法建模为实体或值对象的领域逻辑和概念,并负责使用实体和值对象编排业务逻辑。以下是一些领域服务的特征/功能:
-
领域服务既没有标识符也没有状态
-
领域服务执行的任何操作都不属于任何现有实体
-
领域服务中的任何领域操作都携带特定领域模型的对象
以下类图展示了从一个账户到另一个账户的示例货币转账操作。由于我们不知道在哪个对象中可以存储转账操作,我们选择领域服务进行此操作:

模块
模块用于分解领域模型。命名模块是通用语言的一部分,它们代表领域模型的一个独立部分,并在独立时提供清晰性。模块帮助开发者快速阅读和理解代码中的领域模型,在深入进行类开发之前。请注意,分解领域模型与子域分解领域和边界上下文不同。

上述图示展示了示例模块名称和遵循的示例模板。
聚合
在 DDD 中,聚合的概念是一个边界,有助于将较大的模块分解为较小的领域对象集群,从而可以将技术复杂性作为高级抽象来管理。聚合有助于以下方面:
-
减缓和约束领域对象之间的关系
-
将具有相同业务用例的对象分组,并将它们视为一个统一模型
每个聚合体都有一个特定的根和边界,并且在这个特定的边界内,所有可能的不变量都应该得到满足。域不变量是始终需要遵守的陈述或规则,有助于保持一致性(也称为原子事务一致性)。

以下图表示了一个聚合体示例实现以及每个类及其与聚合体上下文相关的简要信息如下:
-
CreditReport:这包括用户信息和链接,并通过Customer ID(标识符)保存和存储外部链接。
-
CustomerID:这是一个独立的聚合体,用于保留用户信息
-
CreditScore:这包含信用评分估算规则并作为不变量。这个不变量根据信用修改历史进行修改/影响。
-
CreditHistoryEntry:这有助于在修改时实现事务一致性。
-
Inquiry:这可以处理第三方组织特定的信用评分请求。
工厂
工厂是一种模式,用于将对象的使用(对象)与构建(对象)分离。聚合体、实体和值对象在域模型中创建了一定程度的复杂性,尤其是在较大的域模型中。工厂有助于以更好的方式表达(创建和使用)复杂对象。

以下图可能有助于从领域驱动设计(DDD)的角度快速了解工厂创建的细节。以下是一些我们希望刷新的工厂特性:
-
将使用与构建分离
-
封装内部(并避免暴露聚合体的内部)
-
隐藏在创建类型域层工厂中的决策,以抽象要创建的类的类型
-
清理复杂的域模型

以下类图旨在给出创建汽车模型的工厂实现的示例视图;创建复杂性被抽象为域。
仓库
仓库是管理聚合体持久化和检索的模型,同时确保数据模型和域模型之间的清晰分离。仓库是充当存储和持久化门面的中介。

以下图描述了一个仓库模型的示例结构。它显示了客户端的保存和更新(持久化)操作,通过仓库与聚合体进行,同时存在对仓库的单独访问(上图中的处理聚合体);域和数据模型之间的清晰分离。
仓库在以下三个方面与传统数据访问策略不同:
-
它们通过允许检索和持久化聚合根来限制对领域对象的访问,同时确保所有更改和不变性都由聚合处理
-
它们隐藏了用于从外观中持久化和检索聚合的底层技术
-
它们定义了领域模型和数据模型之间的边界
我们有以下两种类型的存储库:
-
存储库作为集合
-
存储库作为永久数据存储

上述类图描述了存储库类及其底层层的示例结构。存储库位于基础设施层,并扩展了领域层接口(限制访问)。
新兴模式
在本节中,我们将介绍以下两种新兴模式:
-
领域事件:它们强制执行同一领域内多个聚合之间的致性
-
事件源:这是一种通过遍历保存状态的历史来持久化应用程序状态并找到当前状态的方法
领域事件
领域事件模式是触发同一领域内多个聚合的副作用的首选方式。领域事件是在特定领域发生的事件,该领域的其他部分(子领域)也应该了解并可能需要对其做出反应。

领域事件模式有助于以下操作:
-
明确表达事件的副作用
-
维护副作用的致性(要么执行与业务任务相关的所有操作,要么一个都不执行)
-
在同一领域内的类之间实现更好的关注点分离
事件源
事件源简化了各种事件,它是一种通过遍历保存状态的历史来持久化应用程序状态并找到当前状态的方法。一个例子可以是座位预订系统,它扫描完成的预订,并在新的预订请求到达时找出还有多少座位可用。
座位分配取决于各种事件(预订、取消、修改等),并且可以使用事件源模式以不同的方式处理。这在某些领域非常有帮助,在这些领域,审计跟踪是一个关键要求(会计、金融交易、航班预订等),并且该模式有助于实现更好的性能,因为事件是不可变的,并支持仅追加操作。
以下要求可能暗示我们需要在哪里使用事件源作为模式:
-
一个简单的独立对象,用于访问复杂的关联存储模块
-
审计跟踪(这是一个关键要求)
-
与其他子系统的集成
-
生产故障排除(通过存储事件并回放)
我们需要意识到关于事件源的一些一般性关注点,如下所述,以便我们可以进行权衡和缓解计划:
-
版本控制:由于事件源系统是只读模型,它们面临着独特的版本控制挑战。想象一下,我们需要将几年前创建/写入的事件读入事件源系统。因此,版本控制是必要的,以便在未来的某个时刻更改特定事件类型或聚合的定义,并且需要制定清晰和明确的计划与策略来管理事件源模型的多版本。
-
查询:这有点昂贵,因为它越深。它取决于要检索的状态的级别和时期。
-
超时:这是通过查询事件存储来加载聚合状态所需的时间,查询所有与聚合状态相关的事件。
其他模式
在结束本章之前,请查看以下列表,这些模式是作为 DDD 的一部分重要的,但本章没有涵盖。我们鼓励您查看我们的参考文献部分,以深入了解以下主题:
-
分层架构
-
服务层
-
应用服务
-
向更深入的洞察力重构
-
灵活的设计
-
将行为可视化(意图揭示界面)
-
无副作用的函数
-
表示状态转移(REST)
摘要
有时,软件设计专家会陷入困惑,不知道何时以及何时不使用领域模型。以下要点可能有助于您深入了解 DDD,以便进行有效的决策并决定是否实施 DDD:
-
业务案例和需求是特定的,特定于领域,与技术实现无关
-
作为一支独立的团队,他们希望在以下情况下转向 DDD:
-
团队从未做过那种类型的业务案例
-
团队需要来自主题专家的帮助
-
业务案例更加复杂
-
团队需要从零开始,并且没有先前的模型存在
-
-
当给定的设计问题对你的业务很重要时
-
技能、动机和热情的团队来执行
-
能够更容易地接触到与产品愿景一致的主题专家
-
愿意遵循迭代方法
-
对业务至关重要的非平凡问题域
-
对愿景有深刻的理解
-
业务目标、价值观、成功和失败因素,以及它将如何与早期实施不同
总结来说,本章简要介绍了团队为了提前采用 DDD 而需要了解的核心原则、特性和最佳实践。然后,我们详细介绍了战略模式,如通用语言、领域、子领域、核心领域和边界上下文。我们还涵盖了 DDD 的最基本方面,如自治边界上下文、无共享架构、单一职责代码、多个边界上下文,以及关于 DDD 方面的 SOA 原则的一些思考过程,作为集成边界上下文的一部分。我们还看到了泡沫上下文、自治泡沫上下文以及将服务公开作为与遗留系统集成的重要现实问题的部分。我们介绍了数据库集成、平面文件集成和事件驱动消息作为分布式边界上下文集成策略的一部分。
作为战术模式的一部分,本章涵盖了实体、值对象、领域服务、模块、聚合、工厂和存储库,并讨论了两种新兴模式:领域事件和事件溯源。
参考文献和进一步阅读材料
如需更多信息,您可以参考以下书籍:
-
领域驱动设计 - 软件核心的复杂性处理 - Eric Evans 著(Pearson)
-
领域驱动设计的模式、原则和实践 - Scott Millet 与 Nick Tune 著(Wrox)
您还可以参考以下在线资源:
-
DDD 快速入门:
www.infoq.com/minibooks/domain-driven-design-quickly -
三个指导原则:
techbeacon.com/get-your-feet-wet-domain-driven-design-3-guiding-principles -
DDD 入门:
dzone.com/storage/assets/1216461-dzone-rc-domain-driven-design.pdf -
www.infoq.com/articles/ddd-in-practice(DDD 的特性) -
www.codeproject.com/Articles/1158628/Domain-Driven-Design-What-You-Need-to-Know-About-S -
www.codeproject.com/Articles/1164363/Domain-Driven-Design-Tactical-Design-Patterns-Part -
www.slideshare.net/SpringCentral/ddd-rest-domain-driven-apis-for-the-web -
ordina-jworks.github.io/conference/2016/07/10/SpringIO16-DDD-Rest.html -
www.slideshare.net/canpekdemir/domain-driven-design-71055163
第六章:企业架构平台和工具
本章包含两个主要部分。本章的目标是概述目前在行业中使用的两个突出的企业模式。本章还涵盖了某些突出的企业架构平台和工具。第一部分重点关注目前使用的两个流行企业架构框架:
-
开放集团架构框架(TOGAF)
-
Zachman 框架
在第二部分,我们将重点关注组织使用的一些突出的企业架构(EA)平台和工具。我们将涵盖以下流行的平台:
-
企业架构师
-
Dragon1
-
ABACUS
企业架构框架概述
一个企业架构框架(EAF)有助于将企业内部所有与软件相关的开发过程映射到满足企业的目标和目标。EAF 还为企业提供了一个分析和理解其弱点和不一致性的框架。目前行业中有许多流行且建立良好的 EAF 框架。其中一些是为特定领域开发的,而另一些则具有更广泛的范围。市场上存在的一些 EAF 框架包括以下内容:
-
国防部架构框架(DoDAF)
-
联邦企业架构框架(FEAF)
-
财政企业架构框架(TEAF)
-
开放集团架构框架(TOGAF)
-
企业架构的 Zachman 框架
虽然在行业中存在四个或五个突出的企业架构框架(EAF),但最受欢迎和广泛使用的是 TOGAF 和企业架构的 Zachman 框架。因此,在本章中,我们的讨论将仅关注这两个框架。
开始使用 TOGAF
TOGAF 是一个非常流行的架构框架,用于设计企业架构。它提供了在企业架构的设计、生产和维护中使用的所有工具集和技术。它是基于一个使用行业最佳实践和一组可重用架构资产的过程模型开发的。
根据 TOGAF,架构被定义为 系统的基本组织,体现在其组件中,它们之间的关系以及它们与环境的关系,以及指导其设计和演变的原理(你可以参考pubs.opengroup.org/architecture/togaf9-doc/arch/ 获取更多信息)。简而言之,系统的架构为其实现提供了一个详细的计划。架构还突出了系统中存在的各种组件以及它们之间的相互关系。
TOGAF 旨在支持企业架构的四个架构域。以下图表中突出了这四个域:

前一图中列出的每个架构领域在定义企业架构中都发挥着至关重要的作用。角色如下列出:
-
业务架构提供了整体业务活动的蓝图,例如业务策略、组织、核心业务流程等。
-
数据架构提供了组织数据资产的蓝图,无论是逻辑的还是物理的。它还指定了组织的各种数据管理资源。
-
应用架构为组织必须部署的各种应用提供蓝图,包括它们与组织中存在的各种业务流程的交互和依赖关系。
-
技术架构提供了所需支持各种数据、应用和业务服务的硬件和软件资产的高级描述。技术架构主要关注基础设施组件、处理标准等。
架构开发方法 (ADM)
TOGAF 架构的核心是 ADM。它提供了一套经过测试和可重复的过程,用于开发企业架构。
以下是在 ADM 中捕获的关键活动:
-
建立架构框架
-
开发架构内容
-
提供架构实现的指导
所有的 ADM 活动都遵循一个迭代周期,包括架构定义和实现。这有助于组织以符合其业务目标和机会的逐步方式转换其架构。ADM 的阶段如下所示:

在 ADM 的每个阶段发生的活动如下所述:
-
初步阶段:进行架构能力建设所需的主要启动活动。本阶段进行的活动示例包括对 TOGAF 的定制、定义用于架构设计的原则等。
-
阶段 A - 架构愿景:在这个初始阶段,关键参与者参与范围的定义。其他一些活动包括利益相关者识别、获取架构设计和开发所需的所有必要批准等。
-
阶段 B - 业务架构:在这个阶段,达成协议以开发与组织架构愿景相一致的业务架构。
-
阶段 C - 信息系统架构:在这个阶段,达成协议以开发与组织架构愿景相一致的信息系统架构。
-
阶段 D - 技术架构:它主要涉及开发与组织架构愿景一致的蓝图。
-
阶段 E - 机会和解决方案:它涉及进行初始实施规划和识别不同格式的架构交付。
-
阶段 F - 迁移规划:它主要处理从基线迁移到最终目标架构的步骤。迁移涉及的各个步骤通常被捕获在实施和迁移计划中。
-
阶段 G - 实施治理:它提供了实施的整体概述。
-
阶段 H - 架构变更管理:它涉及制定一个变更管理计划来处理架构中出现的变更。
-
需求管理:它涉及管理在 ADM 各个阶段演变中的架构需求。
可交付成果、工件和构建块
在执行 ADM 的过程中,会产生几种类型的输出。其中一些是流程图、项目计划、合规性评估等。TOGAF 提供了一个架构内容框架,它为架构内容提供了一个结构模型。这个结构模型允许定义、结构化和以一致的方式呈现多种类型的工作产品。
架构内容框架基本上使用三种类型的类别来表示正在考虑的特定类型的架构工作产品。它们如下:

可交付成果是一种由利益相关者正式审查和同意的工作产品。可交付成果是项目的典型输出,它们以文档的形式存在。这些可交付成果在项目完成后要么存档,要么作为模型标准转移到架构存储库。
工件是一种描述架构某些特定方面的工作产品。
一些重要的工件类别如下:
-
目录(列出事物)
-
矩阵(显示各种事物之间的关系)
-
图表(描绘事物的图像)
一些常见的例子包括需求目录、用例图、交互图等。
构建块表示 IT 或架构能力的基本组件,它可以与其他构建块结合,以开发和交付架构。
构建块可以根据系统架构开发达到的阶段以不同详细程度进行指定。例如,在非常初级的阶段,构建块可能只是一个名称,这个名称可能后来会涉及到组件及其设计的完整规范。
有两种类型的构建块,它们是:
-
架构构建块(ABBs):它们描述了从架构中期望的能力。然后,这种能力描述了将用于制作解决方案构建块的规范。例如,客户服务可能是一个企业内部所需能力的例子,这可能包含多个解决方案块,如应用程序、流程、数据等。
-
解决方案构建块(SBBs):它们表示将在实现所需能力时使用的各种组件。
可交付成果、工件和构建块之间的关系在以下图中展示:

所有与架构相关的工件以某种方式相互关联。一个特定的架构定义文档可能引用几个其他互补的工件。这些工件可能属于构成所考虑架构的各个构建块。以下示例涉及目标呼叫处理过程。对其他构建块的引用在以下图中展示:

企业连续体
TOGAF 包含一个称为 企业连续体 的概念。这个概念解释了某些通用解决方案如何根据组织的特定需求进行定制和使用。企业连续体提供了一个架构存储库的视图,该视图提供了将架构和其他相关工件分类的方法和技术,这些工件从通用架构转变为适合组织特定需求的特定架构。企业连续体有两个与之相关的互补概念,它们是:
-
架构连续体
-
解决方案连续体
企业连续体的架构在以下图中展示:

架构存储库
TOGAF 的另一个重要概念是架构存储库。它可以用来存储各种类型的架构输出,每个输出在抽象级别上有所不同;这些输出是由 ADM 创建的。这个 TOGAF 概念有助于在组织内不同级别的实践者和架构师之间提供合作和协作。
企业连续体和架构存储库都允许架构师使用组织特定架构中可用的所有架构资源和资产。
通常,TOGAF ADM 可以被视为在组织内各个层面运作的过程生命周期。ADM 在整体治理框架下运作,并产生放置在架构存储库中的输出。企业连续性提供了很好的背景,以理解各种架构模型、构建块以及构建块之间的相互关系。以下图表展示了 TOGAF 架构存储库的结构:

以下列表显示了架构存储库的主要组件以及这些组件提供的功能:
-
架构元模型:该组件描述了架构框架,该框架根据组织的需要量身定制。
-
架构能力:该组件描述了支持架构存储库治理的参数、流程等内容。
-
架构景观:这是在任何时间点部署在组织内部的架构资产表示。景观总是存在于不同的抽象级别,这些级别与不同的架构目标集对齐。
-
标准信息库:该组件描述了新架构必须遵守的标准。在此上下文中,标准可能包括行业标准、组织内部部署的产品和服务标准等。
-
参考库:该组件提供指南、模板等,可以作为创建组织新架构的参考。
-
治理日志:该组件维护整个企业发生的治理活动日志。
使用 TOGAF 的优势
以下是使用 TOGAF 进行 EA 设计的主要好处:
-
TOGAF 框架提供了对将架构开发与与组织目标对齐的战略相结合的技术的好理解。
-
该框架提供了关于如何将架构治理与 IT 治理集成的明确指南。
-
该框架提供了许多清单,说明了如何在组织内部支持 IT 治理。
-
该框架提供了许多可重用的工件,可用于根据不同的需求创建组织多样化的架构。
-
该框架提供了许多选项来降低 IT 运营成本,并有助于设计可移植的应用程序。
TOGAF 的局限性
同样也存在一些限制,具体如下:
-
该框架在企业中扮演设计权威的角色,并为架构师提供很少的功能来维护企业范围内的描述、标准、原则等。
-
该框架为解决方案架构师提供了非常有限的指导。
-
该框架假设企业将拥有自己的流程,这些流程将与 TOGAF 集成
-
它只是一个框架,而不是一种建模语言或任何其他可以被视为替代架构技能的组件
-
它与其支持的元模型并不非常一致
在下一个主题中,我们将探讨 Zachman 框架的细节,该框架在企业架构领域也获得了很大的知名度和影响力。
Zachman 企业架构框架
Zachman 框架由 John Zachman 在 1987 年为 EA 发布。Zachman 受到信息系统设计中复杂性增加的启发,这迫使他思考一个逻辑结构来设计企业的架构,进而导致了 Zachman 企业架构框架的发展。该框架并不专注于提供任何形式的关于顺序、过程或实施的指导。核心重点是确保所有视图都得到良好建立,确保无论它们的建立顺序如何,都能形成一个完整的系统。Zachman 框架没有任何明确的合规规则,因为它不属于由专业组织编写的标准类别。
Zachman 框架最初是为 IBM 开发的,但现在已被标准化,可在企业间使用。Zachman 框架背后的主要动机是通过以一种便于企业管理并促进企业系统(如手动系统和自动化系统)的轻松开发的方式对企业的各种组件进行分类和组织,从而推导出一个简单逻辑结构。Zachman 框架的最简单形式具有以下描述:
-
在设计过程中描述的视角,即所有者、设计师和建造者。
-
产品抽象,例如它是由什么材料制成的以及它是如何(通过什么过程)工作的。
-
在哪里(组件之间相互关联的几何形状),谁(操作说明)在进行什么类型的工作,何时(事情发生的时间),为什么(由于工程方面导致事情发生)。在一些框架的较旧版本中,存在一些额外的视角,例如规划者、分包商等。
在 Zachman 框架中通常使用的各种视角,以及它们在企业架构领域的角色如下:
-
规划者:规划者将产品置于其环境背景中,并指定范围
-
所有者:所有者会对产品的商业效益感兴趣,包括它在组织中的使用方式以及它将为组织带来的增值
-
设计师:设计师会制定产品的规格,以确保它符合所有者的期望。产品设计的所有方面都由设计师负责
-
建造商:建造商管理产品各种组件的组装过程
-
分包商:分包商整合了由建造商指定的非上下文组件
请注意,根据企业景观的变化,Zachman 框架的视角也在不断变化。
框架的最简单描述包含以下组件:

优势
以下是 Zachman 框架的主要优势:
-
它提供了一个框架,用于提高组织内部多种类型的专业沟通
-
它提供了关于不使用任何架构视角的原因和风险的详细信息
-
它提供了探索和比较各种工具和/或方法的选择
-
它有选项将建议开发新的和改进的方法来生成各种架构表示
限制
Zachman 框架有以下局限性:
-
它可能导致过程密集/文档密集的方法,因为需要在用于捕获与框架相关的数据的单元格中填写大量数据
-
它没有提供设计新架构的逐步过程
-
它没有提供任何关于评估未来架构对组织适用性的指南
-
它没有提供在架构中实施治理的框架
选择 EAF 的指南
给定选择最适合您企业的架构的选项,您将使用哪些参数来做出决定?以下表格帮助您根据一些在行业景观中突出的常见参数(五点量表)来选择一个:

表格中使用的某些关键术语如下:
-
过程完整性:这一标准有助于找到框架为架构实施提供的逐步指导水平
-
业务重点:这一标准有助于我们找到技术选择灵活性,进而有助于与业务目标保持一致
-
分区指导:这一标准有助于判断框架为企业分区以有效管理复杂性的灵活性
-
时间价值:这一标准提供了关于使用此框架构建的解决方案为组织提供业务价值所需时间的指导
在下一节中,我们将检查可用于企业架构部署/设计的突出平台和工具。
企业架构平台和工具
以下是一些企业架构师在选择企业架构平台时需要考虑的主要参数:
-
创新:企业架构师将需要许多能够使他们以创新方式思考和工作的功能。同时,他们应能够访问任何 EA 环境中可用的所有工具和功能。
-
可视化:大多数 EA 工具也执行业务支持工具的功能。在这种情况下,工具提供大量丰富的可视化和动画功能变得必要,这些功能被视为正常业务支持活动的一部分。
-
映射和建模:EA 工具最重要的功能需求之一是建模。这些工具应能够提供多种类型的建模,如上下文建模、逻辑建模和物理建模。在当今以客户为中心的数字业务背景下,高级建模能力的需求变得更加突出。
-
分析和设计:任何 EA 工具的关键需求之一是支持分析和设计。现在,由于企业景观的变化,工具支持高级功能(如商业智能)变得必要。
-
加速价值实现:EA 工具应能够提供易于与许多第三方工具和接口集成的功能。这些能力将帮助它们快速实现业务价值。
-
业务架构设计:EA 工具应提供帮助适应快速变化特性的功能,作为架构设计的一部分。它们还应提供快速开发新型商业模式的功能。
在下一节中,我们将检查一些可用于企业架构设计和开发的流行平台和工具。
Sparx Systems 的企业架构师
它是一个提供以下核心能力的企业架构平台,这些能力与企业架构设计相关:
-
分析
-
建模
-
设计
-
建筑
-
测试和管理
此工具提供对所有任务、阶段、组件、领域和生命周期管理的企业架构的集成支持和完全可追溯性。企业架构师结合了丰富的 UML 工具集和高效且交互式的用户界面,为架构师提供了一套先进的工具集。
以下截图展示了企业架构师工具直观的用户界面:

以下是企业架构工具支持的主要行业:
-
航空航天
-
银行
-
网络开发
-
工程
-
金融
-
医疗
-
军事
-
研究和教育
-
运输
-
零售
-
公用事业
企业架构师也是全球标准组织广泛使用的工具,用于组织他们的知识、模型和消息。此工具根据 UML 标准的变更持续更新。
Enterprise Architect 是一个经过验证的、可扩展的、有效的且经济实惠的全生命周期开发平台,用于:
-
战略建模
-
收集需求
-
业务分析
-
软件设计
-
软件分析
-
软件测试和调试
-
业务流程的建模和模拟
-
系统和软件工程
-
企业架构设计
-
数据库设计和工程
-
设计和开发 XML 模式
-
企业架构设计和开发的各个阶段的项目管理活动
-
应用程序的测试和维护
-
报告
Enterprise Architect 针对以下活动进行了优化,这些活动是企业架构设计的一部分:
-
从多个利益相关者创建、捕获和使用丰富多样的架构需求
-
根据组织需求建模、设计和架构各种软件系统
-
业务分析、根据组织需求建模业务流程和战略建模
-
系统建模、系统架构建模以及组件设计
-
比较设计、构建、建模和更新数据库系统
-
根据 XSD 和其他标准定义和生成模式
-
基于领域特定建模语言(如 UML)创建架构设计
-
模拟和可视化各种系统、任务及其相关流程
-
设计、开发、执行、调试和测试用各种软件语言编写的代码
-
模拟行为过程,设计状态机及其各种交互
-
根据架构设计构建状态机的可执行代码,并提供支持这些可执行代码模拟的环境
-
协作和共享信息
-
提供对复杂架构系统进行质量控制和质量测试的能力
-
管理与企业架构设计和开发相关的任务
-
基于云存储库概念的基于团队的协作功能,这些存储库针对通过不同类型的 LAN 和 WAN 网络进行访问进行了优化
Dragon1
Dragon1 是一个非常受欢迎的企业架构平台,它提供了以下功能,这些功能对于企业架构的设计和开发是强制性的:
-
可用于根据组织业务目标导出架构的技术路线图
-
显示组织架构设计痛点的热图
-
提供能力图,展示组织中存在的各种能力
-
架构设计和开发中使用的术语表
-
架构描述文档
-
总概念决策矩阵草图
-
借鉴架构原则
-
企业架构蓝图
-
应用程序景观
-
模型图集
Dragon1 提供可用于组织各个级别的个人使用的功能。在组织中,将从使用 Dragon1 中受益的主要群体包括:
-
分析师:帮助他们进行影响分析
-
架构师:帮助各种类型的架构师(如业务、企业、信息、IT 等)根据其领域创建架构设计
-
设计师:帮助他们创建功能和技术设计
-
经理(IT 和业务):提供工具集,帮助他们通过如仪表板等特性可视化地监控和管理运营
-
项目和程序经理:通过可视化方式实时监控和管理他们的进度变化
-
CxOs(CIO、CEO、CFO 等):以易于理解的方式展示各种组织领域的仪表板视图
Dragon1 的一些核心能力如下:
-
发布和报告:可以使用 Dragon1 上传、存储和发布任何类型的文档/信息
-
数据管理:提供对任何类型数据的存储、更新和删除的支持
-
需求管理:提供全面的功能,用于从各种利益相关者那里收集需求
-
流程、应用和元建模:提供构建任何类型实体类(如流程、应用等)模型的能力和功能
-
系统设计:提供丰富的功能,允许在概念、逻辑或物理级别设计系统
-
用户管理:提供基于角色的功能,可供组织各个级别的员工使用
-
架构可视化:提供广泛的图形功能,有助于创建丰富的可视化效果
-
仪表板和场景:提供丰富的功能,能够创建仪表板功能和场景分析
要了解更多信息,您可以访问www.dragon1.com/products/enterprise-architecture-tool-comparison。
Avolution 软件的 ABACUS
根据 Gartner 的魔力象限,Avolution 的 ABACUS 套件是最佳 EA 建模工具之一。它包含大量适用于大多数常见平台的架构框架和模式库。它还支持从广泛的建模解决方案和第三方来源导入的数据。
ABACUS 有两种变体;如下所示:
-
标准版
-
专业版
ABACUS 的标准产品套件仅提供架构建模功能,而 ABACUS 的专业套件则提供架构建模和场景分析能力。ABACUS 基于组件、约束和连接框架提供企业建模能力。它还具备通过用户界面中的表格视图访问连接和组件属性的功能。
ABACUS 的架构
ABACUS 由元模型和多个架构以及每个架构的视图组成。该解决方案提供了一组来自行业标准框架,如 TOGAF 和其他几个框架的库。ABACUS 使用基于 XML 的文件格式作为对象数据库。任何添加到 ABACUS 的新文件格式都作为对象数据库中的另一个对象存储。这一特性对于创建新的架构模型或对现有元模型进行增强极为有用,因为这些方面可以通过右键点击完成,而不需要像市场上其他 EA 工具那样对内部数据库进行任何更改。
定义元模型的 ABACUS 方法基本上使用三个关键单元,它们是:
-
组件
-
连接
-
约束
这些关键单元符合 IEEE1471 标准。ABACUS 随附不同的库,其中包含这些关键单元。ABACUS 中存在的库列表包括超过 50 个突出的架构模式。与市场上其他 EA 平台相比,Avolution 的灵活性为更多的架构框架提供了支持。ABACUS 具有允许用户在几分钟内创建新库或合并现有库以创建新库的功能。
除了本节中讨论的工具之外,以下图像所示的 Gartner 的魔力象限提供了在企业架构领域中突出的企业架构平台的列表。任何企业架构师都可以将其作为决策的基础。有关更多信息,请访问 www.gartner.com/doc/reprints?id=1-2Q45NIB&ct=151020&st=sb。
摘要
在本章的第一节中,我们讨论了当今突出的 Zachman 框架和 TOGAF 框架,并检查了这些框架的组成部分以及每个框架的优缺点。最后,我们提供了一套可以用于根据各种参数评估和选择最适合组织的 EA 框架的指标。接下来,我们考察了用于企业架构设计和开发的各个流行的 EA 平台和工具。我们通过提供由 Gartner 的魔力象限支持的 EA 工具列表来结束本章。
参考文献
www.sparxsystems.com.au/products/ea/
www.avolutionsoftware.com/downloads/ABACUS%20TA001910ITM.pdf
第七章:服务导向架构(SOA)
你可能想知道许多网站有不同类型的仪表板,显示不同但相关的内容,以及在这个世界上如何将天气预报和股市报价结合在一个显示中。
天气预报和股票报价在功能上是不同的系统;一个是气象领域,另一个是国家证券交易所,但它们可以结合并在单个仪表板上显示。
因此,如果我们需要定义什么是网络服务,那么任何可重用、定制开发的软件代码,它能让异构应用程序相互通信,并使不同的系统以经济有效的方式集成,都可以是我们的定义。
通过在每个服务设计中采用基本的 SOA 原则和特性,我们可以设计一个软件系统,该系统可以整合不同的数据源和不同的生态系统,这些系统可以在时间上更好地发展和成熟,并且成本效益更高。
在本章中,我们将作为 SOA 的一部分介绍以下主题:
-
网络服务和 SOA
-
SOA 简介
-
SOA 生命周期
-
SOA 的主要特性
-
SOA 原则
-
SOA 设计模式
网络服务和 SOA
任何网络服务设计的第一步是从严格遵守 SOA 特性和原则开始。任何网络服务设计的基本构建块和垫脚石是 SOA 架构模式。
SOA(服务导向架构)是最受欢迎且经过验证的架构设计风格,它有助于高效地解决现代软件系统在处理不断变化用户期望时的一些关键问题。

最近,在许多实时云应用中,SOA 已成为云努力的基础,并且与私有云和公共云有很多融合。当然,SOA 在现实世界的应用中,在虚拟化、事件处理、业务流程管理等方面发挥着重要作用。
SOA 简介
SOA 是一种服务架构风格,而不是一种技术或任何编程语言。它定义了设计和开发服务的标准和方式。
服务是具有特定结果的重复性业务活动的逻辑表示。它是自包含的,为将服务与其他服务结合提供指导。它也是消费者消费它的一个抽象或黑盒。
*以下是一些具有特定结果的业务活动示例:
-
获取城市的天气预报
-
获取指定股票代码的股票报价
-
通过预订 ID 获取酒店预订详情
-
获取指定用户 ID 的用户配置信息
简而言之,SOA 本质上是一组服务,这些服务相互通信,而一个服务是一个定义良好、自包含且独立于其他服务上下文和状态的操作或功能。
SOA 生命周期
在我们讨论 SOA 的特征之前,让我们首先简要谈谈 SOA 的生命周期,并简要讨论生命周期中的每个阶段。

任何服务都可以通过具有清晰通信标准(如 WSDL、SOAP、REST 等)的方式被发现,因此它们被选中用于消费。
服务设计是我们接下来需要找到合适模式并按模型驱动、特定业务功能、可独立测试等方式提供服务的下一个关键项目,本章后面将详细讨论最常见的模式。
对于任何企业或组织,在功能设计阶段之后,拥有开发、部署和消费的服务非常重要。然而,与瀑布方法(客户等待所有组件开发完成)不同,如果服务开发和部署以迭代和敏捷的方式进行,那么客户可以更快地实现投资回报率。
对于任何不断发展的服务,治理和反馈至关重要,因为它们在服务采用中扮演着关键角色,并帮助企业在尽可能短的时间内实现投资回报率。
SOA 的主要特征
任何基于 SOA 的功能系统或组件都有其独特的特征。然而,在本节中,我们将涵盖在基于 SOA 的设计中不容妥协的基本元素。
具有明确定义接口的服务互连性
两个涉及系统之间的互操作性或互连性是 SOA 的一个关键方面。为了实现互操作性,架构师应该更深入地分析系统,并提出更详细的方案,以便他们可以定义明确定义的接口。SOA 中的这些接口体现了系统及其边界之间的交互点,这些点应该是标准化的、明确的、行为可预测的、可扩展的和可持续的。
标准接口和服务水平协议
接口应该经过深思熟虑并标准化。即使客户端请求(有效载荷)没有变化,天气预报的响应也可以更快地演变。在天气预报网络服务中,城市名称可以是一个关键元素;然而,城市内部可能存在不同的气候条件,为了获得精确的天气状况,接口需要经度和纬度以及城市名称。
事件驱动和消息传递
松散耦合是 SOA 的基本首要特性之一,可以通过将事件驱动和消息作为服务设计的一部分来轻松实现。我们设计的应该代表一个业务功能或领域,并考虑一个需要在用户预订酒店后立即发送电子邮件的应用程序。假设我们有一个可以预订酒店并向用户发送确认电子邮件的酒店预订服务。根据业务功能,我们可以有两个不同的服务;一个负责酒店预订,另一个负责预订后的过程,如电子邮件、手机确认等。电子邮件服务可以接收预订服务的事件,或者根据其事件驱动设计或消息驱动设计来监听来自其他系统的任何消息。
灵活
可重复和可重用是 SOA 的另一个基本特性,因此服务应该具有较少的政策约束,以实现可重用性和可重复性,同时不对已经使用服务的客户端产生影响。在这些情况下,设计者可能会对服务优化和性能改进表示担忧。然而,灵活性应该比优化更受重视。
让我们了解一下灵活性的见解。考虑一个客户端(消费者)通过城市名称访问给定城市的天气预报,给定城市可能响应多个结果(城市的机场、市中心等),因此潜在的结果可能不止一个。在这种情况下,我们如何设计有效载荷以只响应一行,也许请求有效载荷应该有一个占位符来接受经纬度,如以下 XML 片段所示,因此服务的响应只显示一个结果,而不是多个?

在另一个场景中,假设消费者想要搜索名为多佛的城市的天气条件,多佛是一个在世界各地重复的城市名称(世界上有超过 50 个城市的名称是多佛),因此为了找到独特的多佛,有效载荷也应该具有灵活性,可以提及州和国家或邮编。
要实现灵活性,不应在客户端有效载荷中硬编码任何容易变化的元素,还应评估产生优势并提高服务和其集中式功能的灵活性的替代方法。
我们如何证明在服务优化上的灵活性是合理的?如果我们考虑服务需要响应城市名称多佛的天气条件,可能涉及多个调用;一个用于查找名为多佛的城市列表,第二个用于调用具有特定州、国家或邮编的具体多佛。因此,对于消费者来说,预期的结果比减少对服务的调用次数更为重要。所以在这种情况下,考虑灵活性而非优化是一种更好的方法。
进化
软件产品开发的美丽之处在于,任何软件产品都可以在达到实际可行的最低阶段后迅速投入使用,而产品开发持续引入更多和更多的功能。
这种无缝的功能使用在其他主要行业中可能不可行。例如,在汽车行业,我们可能无法在所有方面完成产品后再发布产品。因为我们不能制造轮子或引擎并开始使用它们,我们必须等到它作为一个汽车出来并且经过质量认证。
在软件开发中,它非常美丽,我们可以为顾客创建仅包含几个功能的财务系统,同时我们继续开发和部署新功能到生产中,以便客户可以无缝地消费更多和更多的功能。SOA 设计可以创建软件和系统演变的完美示例。

让我们以相同的天气预报为例;服务可以从接受城市名称和邮政编码开始,后来增强为经纬度,然后是 IP 地址,然后是搜索的位置,不仅包括当前的天气详情,还包括每小时、每天和每周的预报。在我们介绍部分,我们提到,为了非常有效地处理不断变化和用户期望的高需求,服务应该具有演变和灵活性,以便管理需求,而不是强迫客户改变他们使用服务的方式。
进化的其他常见特征如下:
-
服务是传输无关的
-
服务是软件平台无关的
-
服务的编排与编排
-
显式调用
-
服务代表一个业务功能或领域
-
服务的位置是透明的、可发现的,并支持自省
然而,我们并没有详细涵盖所有这些内容,我们鼓励读者参考其他关于所有这些设计原则的材料,以获得更详细的讨论。
许多作者和参考资料指出,服务导向可以与关注点分离原则相关联,这是正确的,只要它不共享实体之间的状态并保持服务的原子性。
一个人必须面临实施这些实践时的挑战,特别是与遗留的、非服务基础的单一系统。它们可能仍然可消费并赚钱。然而,它们不可扩展且维护成本高。那么我们如何将这些遗留系统转变为独立、可扩展、高性能的服务呢?可以通过遵循 SOA 原则、实践和合适的 SOA 模式来实现。因此,让我们在接下来的章节中深入学习并深入了解 SOA 原则和模式。
SOA 原则
虽然没有全面涵盖 SOA 原则的规范或标准,但我们可以定义一些原则作为 SOA 的核心原则,这些原则有助于实现 SOA 的所有特性。遵守这些原则是建立任何服务和其消费的基础。
我们将在本节中简要介绍这些原则,并且在本章末尾还有一个实用的矩阵,展示了 SOA 生命周期、特性和原则之间的关系。
标准化服务合同
标准化是任何 SOA 的基本原则。服务通过服务合同展示其功能和能力,迫使 SOA 设计者关注服务粒度、要公开的数据类型、服务目的、服务优化、要公开的服务版本、服务端点以及所有服务标准化的各个方面。任何服务的服务级别协议(SLA)都是基于这一原则建立的,以提供清晰的消费、治理、安全、版本、请求和响应的视野和方向。标准化确保服务合同定义良好,并为其他原则的路径铺平道路,从而促进越来越多的服务消费。
服务互操作性
互操作性是 SOA 的另一个重要原则。服务之间共享信息的能力是互操作性,它有助于应用程序在分布式服务之间实现高效的通信,这些服务位于各种软件平台上。互操作性适用于不同的层面,如操作(业务流程)、信息和技术架构阶段,这些阶段决定了系统如何在每个层面上相互通信。
服务抽象
通过隐藏内部细节(复杂性)来提供服务的简化视图有助于更好地解释服务的功能和操作,帮助消费者关注服务的核心业务逻辑,并保护内部实现免受意外变更的影响。抽象可以在从语言实现到服务级别的每个层面应用。在本章的早期部分,股票报价服务仅讨论了获取给定股票 ID 的报价,没有提及它如何与客户请求的公司细节互动,也没有提及它如何连接到证券交易所的动态数据,以及如何将新的业务细节添加到系统中。作为服务的消费者,他们需要知道的是服务是否能够选择他们喜欢的公司的报价,而不是如何获取它。
服务自治
自主性是一种将服务的执行与其共享资源隔离的方式,并且发布服务时不对已使用服务早期版本的客户端造成影响。服务可以被开发、版本化、测试和部署,同时消费者可以继续使用之前版本的服务或无缝的服务变更,这对客户带来了巨大的好处。
服务可组合性
无论是组合的大小和复杂性如何,服务都是有用的组合参与者。服务可以是其他不同服务的编排者,而这个编排服务遵循所有 SOA 特性。
服务组合通常应用于遗留软件应用中,以避免返工的风险;通过保留现有的软件解决方案,应用定制化解决方案和持续的生产运营。
如果你遵循这一原则,就需要进行关注点的分离。在服务的生命周期中,我们清楚地认识到服务会随着更多功能的增加而演进。应用松耦合以及服务重用性,我们不可避免地需要为顾客提供越来越多的附加要求或解决越来越多的问题。回顾我们的演进特性,这一原则与演进相关。
服务可发现性
如果服务没有向内部或外部实体公开或发布,那么它们就失去了其目的。无论外部或内部客户是否消费,服务都是根据其使用情况和使用该服务的客户数量来评估的。即使在内部团队中找到可用的服务也存在挑战,但通过极大的关注和努力,我们可以引入最佳实践以实现可发现性。服务的标准化也有助于实现更好的可发现性。
如果服务没有向内部或外部实体公开或发布,那么它们就失去了其目的。根据使用情况和使用该服务的客户数量评估的服务可以是内部的或外部的。即使在内部团队中,找到可消费的服务仍然存在挑战,但通过极大的关注和努力,我们可以引入最佳实践以确保遵循这一原则,从而使服务演进,组织持续获得其投资回报。
服务松耦合
松耦合是帮助服务实现自动化、独立测试以及服务功能不受影响而演进的核心设计原则之一。这一原则旨在在不同层面上应用松耦合的各个方面,并且根据应用环境的不同可能会有所变化。
让我们以我们的电子邮件服务为例。预订服务在完成酒店预订后向电子邮件服务发送通知,无论电子邮件服务器状态如何(它甚至可能已经关闭,但预订服务不需要等待电子邮件服务器启动)。因此,电子邮件服务可以决定何时发送电子邮件;它可能是在非高峰时段,可能有不同的预定时间,也许是在电子邮件服务器完成其预定维护后开始运行,可能是重新发送失败的投递,等等。
因此,电子邮件服务的架构处理了松耦合原则,在这种情境下,这是最优雅且最可取的。我们大多数人都会同意,并不是在所有设计和所有层面上我们都能应用这一原则,因为它可能不会帮助业务功能。例如,在电子邮件服务和预订服务中,预订和电子邮件服务可以是独立的且松耦合的;电子邮件服务依赖于电子邮件服务器,应用松耦合原则是不可行的。我们提供的其他服务,如天气报告服务,依赖于位置服务,在这种情况下,耦合可能是一个可接受的设计。
服务可重用性
服务可重用性是核心原则之一,实现了面向服务的架构的灵活性和进化特性。设计方面应考虑一组业务功能或逻辑,可以在不复制代码到多个内部或外部客户端的情况下提供。
重用是强类型的面向对象原则,在服务级别也是必不可少的。具有无知的函数上下文,服务是资源,因此可以在最大程度上重用;重用越多,回报率越高。
在我们的例子中,位置服务、电子邮件服务、天气报告服务和股票报价服务都是可重用和业务功能的逻辑分离。
服务无状态
服务应该尽可能地无状态。无状态是另一个重要的原则,有助于服务降低资源消耗、独立测试和可重用性。为了在电子邮件服务中实现无状态,它需要发送电子邮件所需的所有必要信息,因此它不需要从数据库或其他资源中获取额外信息,因为它的重点是设置发送电子邮件的调度业务逻辑。模式可以包含更多详细信息(消息、电子邮件 ID、主题),而不是仅仅预订 ID,并让电子邮件服务为该预订 ID 从数据库中获取额外信息。
SOA 设计模式
在当前的软件设计世界中,我们已经有了针对特定重复问题的经过时间考验的软件解决方案。最佳实践以及软件设计以快速且经济有效的方式解决可重复问题,随着时间的推移形成了可重用的模式,这是一个经验法则,我们应该能够挑选并使用适合我们设计问题的正确模式。
SOA 处理许多设计模式,许多材料都深入讨论了每一个。我们想简要提及一些实时软件解决方案通常需要的重要模式。
在本章中,我们将处理以下模式:
-
服务消息传递
-
消息筛选
-
不可知服务
-
原子服务事务
-
认证代理
-
消息来源认证
-
服务外观
-
多个服务合约
-
服务回调
-
事件驱动消息传递
-
服务重构
-
元数据集中化
服务消息传递
服务消息传递提供了一个通信平台,通过该平台,消息作为独立的单元进行传输和路由。它带来了松散耦合的服务交互和数据交换的高效执行。
现成的、面向消息的中间件(MOM)队列是服务消息传递的最佳例子。MOM 队列可以有一个发送者或接收者,或者多个发送者和接收者,某些应用程序甚至需要使用多个队列来帮助解耦系统的离散和不同的组件。
大多数 SOA 实现使用 MOM 队列,很难找到一个没有消息系统的 SOA 兼容系统。
服务消息传递的好处如下:
-
在你的设计中采用服务消息传递模式,使你的设计解决方案最适合任何希望异步与服务通信的客户端
-
这是一种松耦合的实现,也是 SOA 的核心原则之一
-
通过服务消息传递,以下内容变得简单且优雅:
-
服务的容错和回环
-
服务版本控制
-
记录、延迟和重放
-
复用消息
-
-
最适合并发模型,因为不可变消息是线程安全的
服务消息传递的影响如下:
-
与立即接收客户端响应的服务不同,异步通信在某些情况下会导致可靠性问题
-
由于服务消息涉及与其他系统的异步通信,可能需要进一步参与管理和支持服务过程和执行的系统(需要操作和维护更多的系统)。
-
需要更多地依赖消息系统(对消息系统的依赖)
消息筛选
服务容易受到注入攻击:将恶意数据注入服务中,导致不希望的行为。服务可以在服务器端接收到数据时,甚至在服务使用之前,通过筛选数据来防止任何有害的消息内容。

服务应假定它接收到的所有输入消息都是有害的,因此所有这些消息都应该经过各种检查,以发现任何恶意内容的迹象,并保护服务免受任何有害内容的影响。
消息筛选的好处如下:
-
消除不同类型的注入攻击
-
防止注入攻击导致的资源耗尽
-
服务在消费之前就受到恶意内容的保护
-
无论客户端是否验证,服务都会验证消息
消息筛选的影响如下:
-
为每条消息的筛选逻辑会带来额外的运行时开销
-
处理二进制消息或二进制附件需要专门的逻辑进行筛选
-
通过消息筛选找到并限制所有潜在的有害内容很困难,甚至不可能
不可知服务
考虑金融银行的各种功能,如账户管理、人寿保险、贷款或贷款管理、财富管理等。每个服务可能需要共享其他服务的功能,而不是重复使用它们。

考虑一个需要了解借款人储蓄账户详情、其他零售贷款信息用于信用报告以及物业管理抵押信息的住房贷款管理服务。因此,这些能力是任何贷款服务共同关心的问题,不仅可以由住房贷款系统定义和使用,还可以由任何其他主要系统,如信用卡、人寿保险产品、账户管理服务、投资管理服务等定义和使用。
为一组定义良好且解决主要共同问题的能力实现业务逻辑,这些能力不仅不特定于一个问题,而是多个业务问题的共同点,被称为不可知服务。
将不可知业务逻辑或能力分离成独立的服务有助于企业实现服务重用和可组合性。

如前例所示,服务明确声明它们是不可知的,有助于未来的消费者和设计人员重用现有的不可知服务。
不可知服务的好处如下:
-
练习服务的重用性和可组合性
-
消费者从服务能力的迭代改进中受益,这些能力超出了初始服务定义
-
允许多用途功能,这些将是首选的传统功能
不可知服务的影响如下:
-
通过初步分析的优势提高服务能力需要大量的时间和考虑,并且需要更多的迭代来开发
-
在服务功能上达成普遍共识可能具有挑战性,因为服务的业务功能可能过于模糊或过于通用。
-
需要更多的设计规划和考虑,因为无差别服务设计迫使我们考虑许多设计部分,这些部分在短期或中期交付中不一定需要仔细考虑,因此可能会导致我们最终无法履行交付承诺。
原子服务事务
在分布式环境中,操作的回滚非常重要。当跨越多个服务的任何运行时活动失败时,迄今为止发生的所有事务都应该回滚,否则分布式服务可能会损害软件解决方案的完整性。

在典型的在线储蓄账户交易中,银行系统会有取款和存款服务,如果任一服务调用因任何原因失败,无论服务调用的顺序(先取款或存款,或反之),银行系统最终都会处于不一致的状态。
上述图示显示了对目标账户的信用交易失败,这导致从源账户的借记交易回滚。
因此,作为实现,运行时服务活动被包裹在一个具有显式反转逻辑的事务中,确保在当前操作失败的情况下,所有操作和更改都会回滚。
原子服务事务的好处如下:
-
帮助在基于消息的业务服务中传播回滚机制。
-
有效地实施无状态原则
原子服务事务的影响是,它可能需要更多的内存资源,这取决于要保留其原始状态直到提交或回滚通知的事务数量。
身份验证代理
服务消费者使用一种机制来验证调用资源的身份,调用者的身份基于该调用者提供的凭证进行验证。凭证可以是密码、证书授权机构提供的数字证书、生物识别、ATM PIN 码,或这些类型的任何组合。
在大多数情况下,身份验证是确定访问 Web 服务的资格的第一步,第二步是验证用户是否有权访问 Web 服务。
对于基于身份的授权,可以验证经过身份验证的用户凭证中包含的声明。根据提供给客户端的权限,服务可以授予或拒绝对底层资源的访问。令牌身份验证机制是细粒度授权的有用模型。

上述图示展示了一个在线银行用户通过联系身份验证服务来获取在线银行借记交易权限,该服务通过中央身份存储进行身份验证。然后,服务响应以令牌,以便用户可以消费取款服务和存款服务。
认证代理模式有助于通过集中身份存储实现认证和授权。认证服务承担全部责任并提供一个令牌,消费者可以使用该令牌访问服务。
以下示例展示了用于认证和授权其内容的数字签名和 x509 信息以及要验证的消息。认证服务使用该信息并验证消息是否被篡改,然后认证服务将不会生成有效的令牌,因此应用程序将拒绝访问该功能:
认证代理的好处如下:
-
集中管理的信任(认证)因此有助于消除每个客户端和服务独立管理其认证的需求
-
容易完成协议和更新发生在一个地方,而不会影响任何客户端
-
经纪认证的参与者不需要相互了解就可以进行通信
-
安全令牌可以在组织边界之间使用,并提供自主安全域
认证的影响是,它有时会创建一个单点故障,任何安全漏洞都可能影响整个服务的库存。
消息来源认证
想象一下,Rose 正在从她的银行账户向 Jack 的账户进行在线转账。然而,Jack 没有收到转账金额,但 Rose 的账户显示金额已被扣除。那么 Rose 转出的钱会发生什么?
有可能 Jack 的账户号码在中间层被入侵者的账户号码修改或篡改,因此所有钱都存入了不同的账户。

服务消费者发送的消息会由一个或多个中间层处理,例如路由器、消息队列等。攻击者可以在任何中间层操纵消息并影响服务行为以达到恶意目的。
消息来源认证(或数据来源认证)建议使用数字签名机制来传输敏感消息,因此服务可以验证签名以确保接收到的消息是由发送者发起的,并且在传输过程中没有被篡改。
将数字签名算法应用于有效载荷作为来源证明,提供防篡改的消息。接收此信息的服务通过使用算法验证签名,并且应该匹配。如果不匹配,则服务拒绝消息。
因此,消息来源认证验证了安全性的两个重要方面:
-
数据完整性:消息在到达服务的过程中没有被修改或篡改
-
已认证:服务端接收到的消息来自预期的发送者,而不是其他人
消息来源认证的好处如下:
-
检测接收到的消息的篡改
-
跟踪消息的来源到可识别的源头
消息来源认证的影响如下:
-
由于加密实现导致的性能问题
-
数字签名算法的选择以及密钥数量和类型的差异将增加额外的开销
-
数字签名算法的选择会影响达到的安全级别,因为它根据应用程序所需的安全程度而变化
服务外观
想象一个需要维护的建筑。建筑的外墙是可更换的,不会影响内部结构,这被称为外观。外部墙壁一次拆除并更换建筑的一翼,而另一翼仍在使用中。
大概来说,我们可以将相同的概念与 SOA 中的服务外观联系起来。虽然一些客户端使用现有的服务,但服务的任何增强都可以无缝迁移,不会影响消费者合约,因为它们继续使用较旧的服务版本。

将服务核心逻辑与服务合约分离的模式称为服务外观。服务外观促进了客户端合约之间的松散耦合,因此,在服务有任何变更的情况下,它不会影响其客户,并且他们不需要修改他们的代码。
在设计服务时,架构师需要留意任何负面耦合,例如合约到逻辑的耦合,它依赖于合约,因此每当服务发生变化时,合约也可能会发生变化,从而影响所有不期望有任何影响的服务的消费者。
服务外观通过在核心服务逻辑与服务合约之间建立接口来消除这种耦合。服务外观逻辑允许合约与底层逻辑保持解耦,并进一步保护其核心业务逻辑。它适用于功能和行为变更,因此有助于服务的演进。
服务外观位于服务和合约之间。服务外观可以支持多个合约。请注意,多个服务合约与同一个服务外观通信,只有服务外观与合约耦合,而不是实际的服务,因此服务是独立且松散耦合的。如果合约发生变化,它将最小化对服务的影响。

上述图示描述了一个为不同业务功能提供多个合约的服务。用户信息摘要搜索和用户信息部分更新是具有特定业务逻辑的合约特定服务外观的良例,这些服务外观在服务客户端时不会对其或服务产生任何影响。
服务外观的好处如下:
-
Façade 保护服务和消费者的服务免受规范模型变化的影响
-
Façade 隐藏了规范模型的复杂性
-
Façade 返回消费者同意的数据表示
-
Façade 使你的设计变得优雅
服务外观的影响如下:
-
由于服务外观具有非常用户特定的业务逻辑,它会产生额外的开发和维护成本
-
Façade 倾向于创建额外的物理服务分布,导致更多的复杂性和额外的处理开销
多个服务合约
一个标准合约可能不适合或适用于所有潜在的服务消费者。例如,一个服务合约应该允许更新完整的个人资料信息,而另一个合约则不应允许完全更新,只允许部分更新。尽管个人资料更新是一个单一的服务,但两个不同的消费者需要两个不同的合约。多服务合约模式有助于实现上述选项。服务外观和多服务合约是相关的,服务外观帮助系统实现多个或并发合约。
多个合约或并发合约有两个目的。一个是支持服务的向后兼容性,另一个是为不同的用途提供服务的不同视图。

前图中的圆形矩形表示多服务合约,它们都连接到相同的服务,但出于两个不同的目的。在前面的例子中,一个服务合约只允许更新个人资料的一些字段,而另一个合约可以更新个人资料的所有字段。因此,同一服务的多个合约有助于不同的消费者为不同的目的使用服务。
多服务合约的好处如下:
-
支持向前和向后兼容
-
多版本管理确保客户端不受服务任何新更改的影响
多服务合约的影响是这样的:尽管这个模式考虑了许多合约,但每个新的合约最终都会导致新的服务端点被库存,这可能会妨碍服务治理和高维护。
服务回调
假设你从电话中拨打客户服务中心。一旦接通,你会听到一个自动消息说所有的客户服务代表都很忙,因此要求你等待。你可能就是许多等待同一服务代表的人之一(并发和多线程)。现在,你有两个选择可供选择;一个是等待有人接听,另一个是在一段时间后挂断并再次尝试。然而,过一段时间再次尝试可能会让你陷入同样的情况。
那如果客户服务代表回拨给你呢?你拨打号码,系统接听你的电话,并说明当客户服务代表有空时将自动回拨,这样你就不需要等待。
想象一个需要较长时间才能完成任务的网络服务,但调用者或服务的消费者不想等待所有任务完成,同时消费者还需要知道所有过程/任务何时完成。这与我们之前的例子中客户调用客户服务代表但不希望等待排队类似。
服务回调模式实现是满足此类要求的最优方法。

上述图表描述了使用回调应用程序执行服务回调模式的多种调用系统(网页、电话和联系中心应用程序)。

服务回调模式建议服务的消费者与服务异步通信,并确保在消息中提供回调地址,服务可以使用相同的回调地址与客户端进行通信。
上述图表描述了一个消费者通过消息异步调用服务的场景。消息包含回调地址,因此一旦服务完成其处理,它将使用回调地址进行通信并做出响应。服务回调地址可以是电话号码、电子邮件地址,或者它可以是另一个可以进行进一步业务逻辑处理并响应消费者的服务端点。

在我们的第一个例子中,回调地址是客户的电话号码,服务将拨打该号码。第二个例子可能包含电子邮件地址或回调 URL(相同或甚至另一个服务)以及上传状态作为响应。
服务回调的好处如下:
-
在请求需要等待较长时间响应的情况下非常有用。
-
服务解耦的最佳实现。
-
满足消息广播需求的最佳选择。
服务回调的影响如下:
-
由于此模式主要处理异步通信,可能会引入可靠性问题。
-
可能需要更多基础设施升级以支持必要的回调关联。
-
处理请求和响应错误通常更具挑战性。
具有服务回调模式设计的消息的更多示例如下:
-
一个需要服务加载大文件并逐行读取其内容,然后(在验证每一行之后)可能上传到数据库的软件系统。由于它通常规模庞大,系统调用者不能等待较长的过程完成,同时,一旦上传完成,就会向调用者发送通知。
-
股票交易系统和股票报价行情服务。
-
预订完成状态、电子邮件通知等。
事件驱动消息
事件驱动架构的核心模式之一是事件驱动消息;当事件发生时,服务(发布者)会通过相关事件通知其消费者(订阅者),而消费者并不一定在等待或意识到该事件。
想象一个股票交易服务在特定股价上涨时通知其用户:

上一张图展示了当股价达到特定阈值时,通知流程的周期启动;订阅者告知事件管理员的意图,当事件发生时,发布者发布(通知)。$X 是预定义的限制或销售价格,在这里它是事件。下一张图展示了相同的样本负载。

事件驱动消息的好处如下:
-
跨职能边界和服务之间集成意图的最佳模式
-
以更少的复杂性实现流程的更高自动化程度
事件驱动消息的影响如下:
-
在将消息交换作为原子服务的一部分进行整合时,会创建额外的复杂性
-
取决于发布者和订阅者服务的可用性
-
需要通过结合事件驱动消息设计中的其他相关模式来解决可靠性问题的涟漪效应
服务重构
在许多情况下,服务经历了很多变化,但不会影响服务合同。这可能是一个简单的软件更新,提高了系统的性能,数据库更新,编程版本升级等。
服务重构通过改变内部结构而不改变其行为,有助于提高服务,并且不会对服务合同产生影响。

在上一张图(右上角圈出作为服务重构)中,身份管理系统已经经过重构以提高其响应时间性能,并已升级为快速失败功能。对银行客户端没有影响,它继续使用相同的身份验证服务,但具有改进的服务能力。
服务重构的好处如下:
-
在不影响任何消费者的情况下轻松更新高度依赖的服务
-
升级后功能行为无变化
-
在有限范围内最小化对服务消费者的不利影响
服务重构的影响如下:
-
可能会导致需要更多的治理努力
-
可能会引入潜在的负面影响(性能提升但处理并发请求可能导致可用性降低)
元数据集中化
对于任何组织来说,拥有集中的服务目录并提供正式的服务注册和发现流程是不可避免的,这样可以限制构建已存在或正在开发中的服务或功能的风险。
以下图展示了包含已发布服务信息的注册表,因此服务消费者将查找并绑定这些已注册的服务以进行运行时绑定和调用:

服务及其功能的信息可供企业受益
-
服务可发现性
-
库存标准化
-
服务重用性标准化
-
提供最小化冗余风险的方法。
-
发布具有功能和 QoS 元数据的服务。
此模式适用于单域服务目录,甚至适用于多个目录。


样本目录的好处如下:
-
最小化构建已存在功能的风险
-
有助于服务标准化
-
有助于强制发现和解释
-
运行时发现和绑定
-
确保元数据标准化
样本目录的影响如下:
-
由于元数据标准化,文档和注册需要成为服务交付生命周期的一部分(额外的治理)
-
服务注册需要足够成熟和可靠,以便进行严格的治理和维护
原则和模式交叉引用
以下表格列出了每个原则的 SOA 原则和相关 SOA 模式。当您想要参考一个常见的设计模式及其相关的 SOA 设计原则时,这个矩阵可能很有用:
| 原则 | 模式 |
|---|---|
| 标准化服务合同/服务互操作性 |
-
服务消息传递
-
消息筛选
-
不可知服务
-
多个合同
-
事件驱动消息传递
-
服务回调
-
服务外观
-
服务重构
|
| 服务抽象 |
|---|
- 服务重构
|
| 服务自治 |
|---|
-
事件驱动消息传递
-
服务消息传递
|
| 服务可组合性 |
|---|
-
不可知服务
-
消息来源认证
-
服务回调
-
认证代理
|
| 服务可发现性 |
|---|
- 元数据集中化
|
| 服务松耦合 |
|---|
-
服务消息传递
-
事件驱动消息传递
-
服务回调
-
服务外观
-
多个合同
|
| 服务可重用性 |
|---|
-
不可知服务
-
多个合同
|
| 服务无状态 |
|---|
- 原子服务事务
|
摘要
在本章中,我们学习了什么是SOA以及其基本特征,如服务互连性、事件驱动和消息传递、灵活性、服务演进,以及一些其他常见特征。在后续章节中,我们详细介绍了 SOA 原则,如服务契约标准、互操作性抽象、服务自治、服务可组合性、可重用性和无状态性。
我们还学习了最常见的 SOA 设计模式及其应用场景,以便构建符合 SOA 规范的服务。我们讨论的模式包括服务消息传递、消息筛选、无状态服务、原子服务事务、认证代理、消息源认证、服务外观、多重服务契约、服务回调、事件驱动消息传递、服务重构和元数据集中化。
第八章:事件驱动架构模式
为什么组织需要事件驱动架构(EDA)?全球的组织都在以敏捷的方式运营,并频繁地改变其结构。它们正在演变成为可以独立作为服务提供者和消费者的商业结构。这些服务提供者和消费者不一定存在于组织内部。一些商业服务外包给外部商业伙伴,而组织内部的其他商业服务正在寻求向外部组织提供其服务,除了内部业务线。所有这些新兴趋势都需要具有高度自主性的流程架构,换句话说,就是组织内部各种应用组件之间的高度松散耦合。对高度松散耦合架构的需求导致了 EDA 的演变。使用 EDA,组织可以快速重组其结构,而无需改变其应用程序结构。现在,让我们开始探讨 EDA 的细节。
在广义上,事件指的是任何对组织/企业/最终用户感兴趣的状态变化。汽车中指示汽油低量的信号、手机铃声以及家中烟雾报警器的铃声都是我们在日常生活中遇到的某些真实世界事件的例子。通过以下图例的帮助,理解事件的概念更容易一些:

该图描述了一个订单管理系统中的动作流程。一旦订单管理系统从网站或订单录入系统接收到订单,下一步就是通知其他系统关于该订单的信息。在这一步中,接收订单是一个事件。这个事件需要发布给其他可能对此事件感兴趣的系统。在这个例子中,可能对此事件感兴趣的其他系统是一个仓库管理系统,它会检查存储在仓库中的库存中的订单项以确保其可用性,以及一个财务系统,它会检查与订单相关的信用余额或支付机制。
每个系统都会依次向其他需要完成下一步订单处理的系统发布事件。因此,仓库系统可能会发布一个分配库存的事件,而财务系统可能会向运输系统发布一个支付验证的事件。运输系统随后将进行必要的安排,将订单发送给客户。在这个特定的事件流程中,这些是事件流程的一部分的组件系统。但根据每个步骤事件处理的结果,可能还有其他几个系统可以成为事件流程的一部分。例如,如果仓库管理系统检测到订单中放置的物品库存水平低,它将触发一个事件到采购系统以采购该物品。同样,如果财务系统检测到信用余额低或支付选项不正确,它将向客户发送电子邮件通知,告知信用余额低或支付未成功完成。
从这个例子中,我们了解到 EDA 的核心概念是发布/订阅。在先前的例子中,订单管理系统向两个已订阅该事件的感兴趣方发布订单事件,即仓库管理系统和财务系统。这两个系统随后将事件发布到运输系统等。在 EDA 模式背景下,有三个重要的定义如下:
-
事件:事件是由软件元素在运行时执行的操作,用于使某些信息(包括它发生的信息)可供潜在的非指定操作软件元素使用。
-
发布者:触发(或发布)一个事件就是执行它。可能触发事件的软件元素是发布者。可能使用事件信息的软件元素是订阅者。
-
上下文:在事件驱动设计中,上下文是在注册时由订阅者指定的布尔表达式,但在触发时评估,这样注册的动作只有在评估结果为真时才会执行。
事件驱动模式是一类近年来由于行业范式快速变化而获得大量关注的模式。许多人容易混淆面向服务的架构(SOA)和 EDA 模式。在下一节中,我们将尝试分析和理解两者之间的区别。
面向服务的架构和事件驱动架构(SOA 与 EDA)
世界各地的组织正在迅速改变其结构,并向按需商业模式转变。设置以网络为中心的商业结构趋势在增加,这将拥有自主的服务提供者和消费者。外包也非常突出,因为业务流程的许多部分也将外包给外部商业伙伴。组织内部存在的各个部门和业务单元正在承担服务提供者的角色。这些服务提供者的重点是越来越多地向外部市场实体提供服务。这要求组织足够敏捷,能够快速应对外部环境中的变化或事件。所有这些方面都要求从命令驱动、紧密耦合、服务驱动的 SOA 概念向更松散耦合的事件驱动模型转变。EDA 是一种发布/订阅类型的模式。在 EDA 的背景下,发布者对订阅者一无所知,反之亦然。EDA 模式中的组件耦合非常松散,它们之间只有消息的语义是共享的。现在,需要做出的决定是何时使用 SOA 和何时使用 EDA。
由于它们的工作性质,人们普遍倾向于将 EDA 和 SOA 互换使用。但情况不应如此。这两个架构选项之间存在明显的区别。对于需要业务流程强凝聚力的场景,SOA 是理想的架构选择。以下是一些命令/控制风格的 SOA 可能成为组织理想架构选择的场景:
-
如果存在组织内各种功能层级之间的垂直交互
-
如果存在功能请求和回复流程,例如人机对话,其中用户提出问题并等待答案
-
如果存在需要提交和回滚功能的交易性质流程
-
如果需要数据丰富化,以便以正式格式发布消息的全部内容
EDA 是那些需要在各种流程之间实现松散耦合的组织的首选风格。EDA 是联邦和自主处理环境中的架构选择。以下是一些 EDA 作为组织理想架构选择的场景:
-
如果存在属于流程链各层的横向通信
-
如果一个组织中有工作流程类型的流程
-
如果存在涉及组织跨职能边界的流程,例如,B2B 流程
在架构中追求松散耦合始终为现代组织提供必要的灵活性和敏捷性。因此,在设计组织架构时应遵循的规则是尽可能使用松散耦合,只有在必要时才使用紧密耦合的架构选项。在做出架构设计选择时,还应考虑设计的其他方面,如性能、响应时间等。在一个典型的企业级组织中,以下图展示了与 EDA 和 SOA 架构相关的流程的分支和关系:

在图中,顶部的圆圈表示松散耦合的系统,这些系统是作为解耦点或事件的理想选择。在这些解耦点上,各个系统组件可以连接或断开,而不会改变连接的相邻系统。组织内部各个领域之间的数据交换仅在解耦点上发生,而不是在紧密耦合的系统较低层级上。在重用领域(如图底部所示),由于组件之间紧密集成,需要精细粒度的 EDA 实现来解耦。EDA 实现越精细,IT 系统的灵活性就越大,但这也将减少领域的重用范围。
在前面的图中,如果在解耦点使用 Web 服务技术,并结合如企业服务总线这样的通用基础设施骨干,建立异构系统之间的连接就非常容易。下游存在的系统不必仅仅是 SOA;它们也可以是 SOAP 包装的遗留系统、商业现货软件(COTS)或其他如 ERP 等应用程序。以下图展示了 EDA 与 SOA 的集成。在这个图中,组件通过解耦点连接,这些解耦点是事件:

现在,我们已经清楚地了解了 EDA 和 SOA 之间的区别。在下一节中,我们将学习 EDA 模式的部分。这些组件应该是任何使用 EDA 模式的架构的一部分。
事件驱动模式的关键特性
如果一个系统中的组件发布和接受事件,你能将其视为 EDA 模式的一个例子吗?对这个问题的答案是明确的否定。在本节中,我们将检查 EDA 模式的特点。它们的主要特点如下:
-
多播通信:发布者或参与系统有向已订阅该事件的多系统发送事件的能力。换句话说,这不是单播通信,其中发送者只能向一个接收者发送数据。
-
实时传输:发布者将事件实时发布给订阅者。换句话说,这里涉及的处理或传输模式是实时,而不是批量处理。
-
异步通信:发布者在发送下一个事件之前不会等待接收者处理当前事件。
-
细粒度通信:发布者继续发布单个细粒度事件,而不是等待单个聚合事件。
-
本体:EDA 系统总是有一种根据事件的一些共同特征将事件分类为某种形式的组/层次结构的技术。这为订阅者提供了订阅特定事件或特定类别事件的灵活性。
EDA 模式的组件
EDA 模式的核心组件如下:
-
事件规范
-
事件处理
-
事件工具
-
企业集成
-
源和目标
所有这些组件以及各种其他子组件总结在下图中:

任何电子设计自动化(EDA)的核心组件都是强大的元数据架构。事件元数据架构的核心组件包括以下内容:
-
事件规范:这些事件规范应提供给事件生成器、事件处理引擎和事件转换器。目前还没有行业认可的事件定义和处理标准;它们正处于发展阶段。
-
事件处理:这是一种处理和分析事件数据流的技术,目的是从中得出某种结论,例如,一个主要功能是预测气旋发生的天气预测系统。为了得出这个结论,系统应该考虑几个模式,如风速、流向方向、大气压力、含水量等。所有这些参数构成了事件数据,这些数据应由事件引擎处理,以便得出特定的结论。因此,任何事件处理所需的必要组件如下:
-
事件引擎
-
事件数据
-
-
事件工具:事件开发工具在事件处理方面提供了以下关键功能:
-
定义事件规范
-
定义事件处理规则
-
管理事件订阅
-
它们还提供附加功能,如监控事件处理基础设施和事件流。
-
企业集成:这在 EDA 设计中扮演着关键角色。一些必要的集成服务包括以下内容:
-
事件预处理
-
事件通道传输
-
服务调用
-
发布和订阅
-
企业信息访问
-
-
来源和目标:来源指的是生成事件的企业的组件。这可能指的是系统、服务、自动化代理,甚至是负责创建事件的人。目标指的是基于事件发生或基于事件结果执行动作的组件。事件来源和目标拓扑由多个参数控制,如下所示:
-
事件流
-
事件发生量
-
来源和目标的位置等
-
事件流是 EDA 架构的一个重要组成部分。在下一节中,我们将看到事件流中存在的各种逻辑层。这些逻辑层组件需要仔细选择和设计,以确保 EDA 模式的成功实施。
事件流层
事件流中存在的四个逻辑层如下:
-
事件生成器
-
事件通道
-
事件处理
-
下游事件驱动活动
事件生成器
生成事件的来源被称为事件生成器。来源可以是应用程序、服务、业务流程、传感器、数据库,甚至是人类。一个生成的事件将通过事件过滤器进行显著性的评估,如果评估成功,则导致显著事件的生成。由于事件生成的来源多种多样,并非所有生成的事件都适合处理。对于此类事件,在将它们发送到事件通道之前,有必要确保它们被转换为兼容的格式。
事件通道
这充当了 EDA 的传输介质和消息骨干。它从事件生成器接收标准格式的事件并将它们发送到其他事件生成器、事件处理引擎和下游订阅者。
事件处理
一旦接收到事件,它们将根据存储在事件处理引擎中的某些规则进行处理和评估。根据评估结果,将启动特定的行动方案。事件规则是根据组织和其他相关方指定的标准创建的。事件处理可能导致多个行动方案,例如通知某个系统/机构、采取替代行动方案、启动业务流程等。
下游事件驱动活动
任何事件都可以触发一系列下游活动,这可能是对事件的响应。事件可以是事件处理引擎的推送通知或订阅者的拉取通知。在此上下文中,订阅者可以指应用程序、人类、服务或业务流程。
事件驱动模式的设计考虑因素
在本节中,我们将解释在选择架构实现前的 EDA 模式时需要考虑的各种设计因素。主要考虑因素如下:
-
敏捷性:敏捷性指的是应对环境快速变化的能力。在 EDA 模式中,组件是松散耦合的。这确保了某个组件的变化不会影响系统中的其他组件。因此,EDA 模式提供的敏捷度很高,使其成为设计需要持续变化且无需停机时间的系统的理想选择。
-
部署简便性:EDA 模式组件本质上是松散耦合的,这使得它们的部署非常容易。对于需要最大部署简便性的解决方案,事件代理拓扑比事件中介拓扑更好。这是因为事件中介拓扑中,事件中介和事件处理器之间存在相对紧密的耦合。
-
可测试性:由于需要特殊的测试客户端和测试工具来生成测试所需的事件,因此 EDA 模式组件的单元测试比较困难。
-
性能:EDA 能够并行执行异步操作,这为架构提供了非常高的性能,无论涉及的消息排队和出队的时间滞后如何。
-
可伸缩性:由于组件高度解耦,EDA 提供了高水平的可伸缩性。
-
开发简便性:由于模式的异步特性,使用此模式进行开发的简便性较低。
尽管 EDA 模式有明确的组件,但其实现风格根据系统功能类型和复杂度而变化。在下一节中,我们将了解 EDA 模式实现的多种风格。
EDA 模式的实现变体
EDA 模式实现的多种风格如下:
-
简单事件处理模式
-
事件流处理模式
-
复杂事件处理模式
简单事件处理模式
这些模式用于测量与特定可测量条件变化相关的事件。这些模式用于需要触发实时工作流而没有任何其他约束或考虑的场景。在架构中使用简单事件处理模式时,不考虑滞后时间和与业务相关的成本。此类模式的使用场景可能包括通过传感器检测温度/压力变化。让我们借助本章开头使用的订单管理系统示例来解释简单事件处理。以下是重复的图表,供快速参考:

在这个例子中,订单进入订单管理系统后,第一个事件是触发对仓库管理系统进行库存水平检查的通知,以及对财务系统进行支付验证的通知。为了简化,我们只考虑一个事件流:与仓库管理(与库存检查相关)相关的事件。一旦订单进入仓库管理系统,订单中的项目就会使用库存检查服务与仓库中现有的库存进行核对。库存检查服务分配与订单中现有项目相关的库存,然后检查剩余库存以确定库存阈值的最佳水平。如果仓库中的库存低于可用阈值,库存检查服务会生成一个低库存阈值事件。此事件由以下图中所示的单个事件处理引擎接收。在此示例中,事件处理规则将启动两组事件来处理低库存阈值情况:第一组是重新订购库存的过程,第二组是发布事件供订阅者消费。在这个特定的例子中,订阅者是库存买家,还会生成一个通知给库存控制员。所有这些活动都在以下图中展示:

事件流处理模式
在事件流处理中,发生的事件会被筛选出值得注意的部分,然后发送给订阅者。这种风格的使用是为了确保实时信息在企业内部和外部流动。这种模式促进了实时决策。
让我们通过本章中讨论的订单处理示例进一步演示这种类型的事件。在订单处理示例中,如果我们考虑仓库中的事件序列,RFID 传感器会为每个离开仓库的产品生成一个事件。在这种情况下,例如,假设一个零售商希望在高档产品离开仓库时得到通知。为了满足这一要求,已经设计了一个本地事件过滤器,其中包含过滤掉价格低于$5,000 的物品事件的规则。假设购买了一个价值$6,000 的高价值物品。这个事件,即高价值事件,被重新格式化为标准事件格式,并放置在事件通道中。事件处理引擎接收事件,将其映射到仓库中高档产品离开的规则,并发布它。订阅了此事件的订阅者会收到它;在这个例子中,它可能是一个库存经理的仪表板。
复杂事件处理(CEP)模式
在 CEP 中,考虑简单事件和普通事件的组合,以判断是否发生了复杂事件。考虑的各种事件可能需要在长时间内评估。各种事件之间的相关性可能发生在多个维度上,如时间、因果和空间。为了进行这种评估,CEP 需要以下组件:
-
事件解释器
-
事件模式定义
-
事件模式匹配
-
事件相关性技术
CEP 通常用于响应业务中的异常,以及评估机会和威胁。
EDA 模式有两种不同的风味或拓扑。每种拓扑只需要在特定场景中实现,因为它们的特性和特征不同。因此,了解这些拓扑非常重要,以便在它们的选择和实施方面做出明智的决定。在下一节中,我们将了解各种 EDA 模式拓扑。
事件驱动模式类型
事件驱动模式有两种拓扑类型:
-
事件中介拓扑模式
-
事件代理拓扑模式
当需要通过中央中介编排事件的一部分的多个步骤时,使用中介拓扑模式。当需要将多个事件链接在一起而不需要中央中介时,使用代理拓扑。接下来将讨论每种模式的架构和组件。
事件中介拓扑模式
中介拓扑模式用于设计需要一定程度的协调/编排以处理事件的系统/流程。这种场景的理想例子可以是订单处理示例,其中包含多个步骤,如订单录入、库存验证、财务验证等。所有这些步骤都需要一定程度的编排,以便评估它们是否可以串行或并行执行。中介拓扑中有四个主要组件:
-
事件队列
-
事件中介
-
事件通道
-
事件处理器
所有这些组件都在以下图中表示:

客户端发送一个事件,然后由事件队列接收。事件队列将事件传输到事件中介。事件中介接收事件并编排它。这是通过向各个事件通道发送额外的异步事件来完成的,这些事件通道随后将执行每个步骤。事件处理器从事件通道接收事件并应用业务逻辑来处理事件。在 EDA 中可以有任意数量的事件队列。事件队列可以实施为消息队列、Web 服务组件或任何适合考虑的系统的其他形式。此模式提供了两种类型的事件:
-
初始事件:这指的是中介者接收到的原始事件
-
处理事件:这指的是由中介者生成并发送到事件处理组件的事件
事件中介者主要负责对初始事件中存在的各个步骤进行编排。为了执行初始事件中的每个步骤,事件中介者会将特定的处理事件发送到事件通道。这个处理事件被事件处理器接收并处理。事件通道用于将每个步骤关联的处理事件传递给事件处理器。事件通道可以是消息队列的形式,也可以是消息主题的形式。处理事件所需的应用逻辑存在于事件处理器中。事件处理器通常是高度解耦的架构组件,与系统中的特定任务相关联。
事件代理拓扑模式
事件代理拓扑模式用于事件流相对简单且不需要任何中央事件编排的场景。事件代理拓扑模式的主要组件如下:
-
代理
-
事件处理器
事件代理拓扑模式的组件在以下图中展示:

事件代理组件包含所有事件通道,可以设计为集中式或联邦式。事件代理拓扑模式与事件中介者拓扑模式的主要区别在于缺少控制并编排事件的组件。而不是事件中介者,事件处理器执行处理和发布每个事件的角色,表明特定操作已完成。代理组件可以是集中式或联邦式,并包含事件流中使用的所有事件通道。代理组件中包含的事件通道可以是消息队列、消息主题或两者的组合。
在下一节中,我们将讨论一些事件驱动模式的变体。
集中辐射模式
集中辐射模式是事件代理拓扑模式的一种变体。在集中辐射架构中,中心作为集中式代理,辐射作为连接应用程序到中心的适配器。辐射与一个应用程序建立连接,并将应用程序数据转换为中心可以理解的格式。中心将传入的数据转换为目的地系统可以理解的格式,并相应地进行消息路由。存在单个中心使这种架构易于管理,但同时也限制了架构的可扩展性:

为了克服这一限制,联邦中心辐射式架构的概念已经发展起来。在联邦中心辐射式架构中,存在多个中心。每个中心拥有本地元数据和规则,以及全局元数据。对全局元数据和规则的任何更改都会自动传播到其他本地中心。联邦中心辐射式架构通过促进中心的集中管理,提供了可扩展性和灵活性。
广播模式
在广播模式中,也称为发布/订阅广播模式,信息被发送到网络中所有存在的各方。只有感兴趣的各方接收消息;其他人丢弃消息。如果网络中的系统具有丢弃不需要消息的效率,那么这种模式非常适合设计此类系统。当涉及到在网络级别实现这种模式时,一种称为用户数据报协议(UDP)的互联网协议(IP)变体允许我们向网络中的所有计算机发送一条信息。这是适用于网络的广播事件模式的一种变体。
轮询模式
在此模式中,订阅者联系发布者以了解他们是否有任何感兴趣的内容。这很少使用,因为它涉及大量的系统资源浪费。想象一下,当订阅者没有新内容时,他们向发布者轮询 50 次。
事件驱动模式近年来在实现方式上略有不同,以适应不断变化的技术环境。在下一节中,我们将了解系统中事件驱动模式的实际实现。
系统或过程中的 EDA 模式实现
在本节中,我们将讨论在过程中实现事件驱动模式。涉及此实现的主要组件如下:
-
事件队列
-
事件日志
-
事件收集器
-
回复队列
-
读事件与写事件
本节将解释这些组件以及该架构的整体功能。此实现的核心组件是一个中心事件队列。所有事件在处理之前都插入到中心事件队列中。以下图展示了基于队列的架构:

当事件被插入队列时,它们被放置在一定的顺序中,以便可以跟踪系统响应事件的顺序。
事件日志
需要对添加到中央事件队列的消息有一个备份和恢复机制。这是通过将所有事件细节写入事件日志来完成的,该日志通常放置在磁盘上。在系统崩溃的情况下,可以通过从事件日志中恢复其状态来重建系统的状态。因此,事件日志的主要目的是确保事件持久化。为了使备份机制更强大,可以备份事件日志,这相当于备份了系统的状态。这些备份副本也可以在它们实际部署到生产之前用于对新版本进行试点性能测试。以下是对事件日志的图表:

事件收集器
事件请求来自不同的来源,它们以 HTTP 请求或其他格式通过网络形式到达系统。这些事件通过事件收集器从不同的来源收集。以下图表展示了带有收集器的 EDA:

回复队列
在某些场景中,需要向事件请求发送响应。在这种情况下,需要有一个响应或回复队列来提供支持。以下图表展示了一个这样的例子。从图表中可以看出,响应需要发送回适当的事件收集器。例如,如果传入的请求是以 HTTP 格式发送的,并且是由 HTTP 收集器发送到事件队列的,那么响应必须通过 HTTP 收集器仅发送回源地址。这里需要注意的是,响应不会记录在事件日志中:

提高基于事件驱动架构(EDA)的过程/系统的性能
在持久化事件的情况下,所有推送到事件队列的事件都会持久化到事件日志中。这使得系统变慢。为了提高系统的性能,应该有一个机制来只持久化那些能够改变系统状态的事件,也就是说,读取事件不会改变系统的状态,而写入事件将会改变状态。因此,应该有一个机制来只持久化写入事件。
这可以通过事件收集器通过区分读取事件和写入事件来实现。还应该有单独的队列来处理读取和写入事件。使用这种机制,可以很容易地确保读取事件队列中的事件不被持久化,而只有写入事件队列中的事件被持久化。这一概念在以下图表中展示:

在实践中,将会有三个队列:读取事件队列、写入事件队列和回复队列。尽管看起来很复杂,但从实现的角度来看,它相当简单。
从事件日志中重新创建系统状态是使用 EDA 系统的最重要好处。
大多数 EDA 模式实现都是以 COTS 产品和/或自建解决方案的形式完成的。在下一节中,我们将看到 IBM WebSphere MQ,这是市场上最突出的 EDA 产品之一。
IBM WebSphere MQ
IBM WebSphere MQ 用于为应用程序提供消息支持。它具有在多种网络中传输消息的能力。当需要发送或接收消息时,应用程序可以连接到 IBM WebSphere MQ。IBM WebSphere MQ 可以处理不同类型的处理器、操作系统、子系统和其他通信协议,在系统之间传输消息时。另一个特性是在传输消息时,如果它发现处理器不可用,可以将消息放入队列,并在处理器或系统可用后再次传输。以下是 IBM WebSphere MQ 支持的不同操作模式,它被认为是一个消息和队列应用程序:
-
点对点传输
-
发布/订阅
-
文件传输
WebSphere MQ 的关键特性如下所述:
-
消息传递: 进程通过发送消息相互通信,而不是通过调用。
-
队列: 发送的消息被放置在队列中,然后按顺序处理,这样不同的进程可以独立工作,而无需任何直接连接和相关的开销。
-
点对点: 可以向一系列队列发送多播/广播消息。因此,发送者需要知道目标名称,但不必知道目标的位置。
-
发布/订阅: 所有对特定类型或类别的消息感兴趣的应用程序都将订阅由特定应用程序/进程发布的那些消息。
-
多播: 这加快了消息传输的速度。它使发布者能够同时向网络中的多个订阅者发送消息。
-
遥测: IBM WebSphere MQ Telemetry 设计用于支持设备消息传递。它建立设备与应用程序消息之间的连接。它提供了应用程序、互联网、服务等各种组件与仪器化设备网络之间的连接。IBM WebSphere MQ Telemetry 随带一个非常高效的协议,为通过网络连接的大量设备提供消息支持。此消息协议已发布,以便可以将其添加到设备中。
EDA 的新兴趋势
在本节中,我们将探讨事件驱动架构模式领域的一些最新进展。
事件驱动微服务
大多数组织正在从目前分立的单体应用程序转向微服务的概念,以实现敏捷性并在市场上获得竞争优势。使用微服务时出现的一个主要问题是分布式数据管理。每个微服务都有自己的私有数据库。设计更新多个微服务在多个不同数据库中拥有的实体的业务事务是一个主要问题。这给维护数据库中现有数据的一致性带来了极大的困难。以下图表展示了这一点:

EDA 为使用微服务时分布式数据库中出现的这个问题提供了一个解决方案。在 EDA 中,当有变化时,一个服务会发布事件。其他感兴趣的服务会订阅这些事件。一旦收到事件,服务通常会更新其自身状态,并发布更多事件,这些事件反过来可能被其他服务消费。事件驱动的方法提供了实现一致事务的功能。以下图表描述了 EDA 如何帮助实现多个服务使用的业务事务的一致性。图表中的示例是我们在本章开头使用的订单管理示例:

复杂事件处理
近期,许多有趣的用例在复杂事件周围发展起来。统计函数,如事件相关性和聚合,以及计算算法正在应用于事件数据,以揭示有意义的模式,为多个领域/行业提供有价值的用例。其中一个突出的用例是在银行领域检测交易欺诈。另一个有希望的应用是天气预报,其中几个大气参数被关联起来以预测台风、地震等。世界上许多用于天气预报的指挥中心都是基于 EDA 运行的。
物联网(IoT)与 EDA
物联网(IoT)指的是嵌入在计算设备中的所有对象的相互连接,这反过来又帮助它们发送和接收数据。在这种情况下,我们周围的任何物体都将变成智能物体,并且可以持续向已订阅接收其消息的其他物体发送消息。到 2020 年,预计将有 3 万亿个物体通过物联网相互连接。所有这些物体都通过 EDA 架构来运行。这表明 EDA 在未来几年具有巨大的潜力。
参考文献
tutorials.jenkov.com/software-architecture/event-driven-architecture.html
www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.pro.doc/q001020_.htm
摘要
在本章中,我们讨论了 EDA 模式的各个方面。我们首先介绍了事件和事件驱动模式的定义和描述。然后我们详细讨论了 EDA 的各种组件。EDA 模式有两种拓扑变体,每种变体根据系统需求都有特定的使用场景。这些模式和它们的组件都进行了详细讨论。
EDA 模式有多种变体。本章详细讨论了这些模式及其特性。EDA 模式在其工作中有多个层次,每个层次都包含特定的组件。本章讨论了这些层次及其组件。SOA 和 EDA 是相关概念,它们相互补充。本章详细讨论了它们的相似性、差异和使用场景。本章最后讨论了 EDA 领域的新兴趋势。
第九章:微服务架构模式
微服务架构(MSA)正被宣称为设计、开发、部署和交付下一代软件应用的最强大的架构模式。微服务显然正在成为构建企业级和关键任务应用的主要构建块。微服务是细粒度的、通常是单功能的、松散耦合的服务,便于独立部署和水平扩展。微服务是自我定义的、干净隔离的、自主的,并且本质上支持流行的多语言模型。多语言范式代表多种编程语言、数据传输协议和持久化机制。目标是构建和运行高度可靠、可扩展、可用、弹性、消息驱动和安全的微服务。微服务是互操作性的、技术无关的,并且可组合以产生以流程为中心的应用。微服务和 Docker 容器化在敏捷软件开发和快速 IT 服务交付中相辅相成。许多有成就的专业人士正在发现各种最佳实践、关键指南、设计和评估指标以及促进模式,以加快从单体工作负载到基于微服务的工作负载的迁移过程。此外,还有 API 网关、服务集成和编排的集成平台、如 Docker 容器等部署和交付环境,以提高 MSA 的采用率。产品供应商、系统集成商、云服务提供商、DevOps 工程师和其他 IT 专业人士正在合作,以加速服务在实现高度灵活、可扩展、弹性、可持续的应用中的使用。本章致力于向读者展示这个新领域中所有现有和新兴的模式。
微服务模式
几位 IT 专业人士,基于他们丰富的经验,提出了一系列促进基于微服务应用生产的模式。更进一步,还有一些模式专门用于从头开始构建新的服务。不仅限于开发,还包括测试、部署和交付,精致的分解模式正在被发现并普及。MSA 的一个战略影响是将遗留应用程序无风险地转换为基于 MSA 的现代应用程序。有促进将大型和单体应用程序分解为多个微服务的模式。在接下来的章节中,我们将详细讨论突出的模式。主要有两种模式:架构模式和设计模式。
分解模式
模式对于任何新范式的发展至关重要。微服务范式也需要通过许多新颖且具有增值的图案来相应地启用,以便维持并简化其漫长而艰巨的旅程。无论是设计、开发、部署和交付新的微服务,还是将遗留和单体应用程序分解成无数个交互式微服务,架构和设计模式的作用和相关性极高。毫无疑问,世界各地的 IT 团队都背负着许多不灵活、封闭、维护成本高且规模庞大的软件应用程序。在理解了通过 MSA 提议所预期的显著好处后,全球企业都热衷于探索利用它来清晰、自信地现代化当前应用程序的可能性。这种技术驱动的转型和变革使每个企业都准备好迎接数字经济和时代。微服务被吹捧为实现数字企业梦想的前进之路,并且有一个响亮的号召去发掘强大且变革性的模式来加速构建和维持以微服务为中心的应用程序。让我们从一些有趣的分解模式开始。
微服务架构模式对应于扩展立方体的y 轴缩放,这是一个如图所示的三维扩展模型:

x 轴缩放是为了在负载均衡器后面运行多个应用程序的克隆副本。这是实现横向扩展最常见的方式。y 轴缩放表示一个由功能、服务或资源分割的应用程序。每个服务负责一个或多个紧密相关的功能。z 轴缩放通常用于扩展数据库,因为数据被分割到一组服务器上。每个服务器运行相同的代码副本,每个服务请求都被路由到相应的服务器。z 轴缩放,就像x 轴缩放一样,可以提高应用程序的容量和可用性。然而,为了解决日益增长的开发和应用复杂性问题,建议使用y 轴缩放。y 轴缩放将应用程序分割成多个服务。
通过用例模式进行分解
将大型应用程序分割成动态的小型且协作的组件集合有许多基础和原因。众所周知,软件包和库正在被构建,目的是自动化和加速多个用例。因此,这种模式明确地指定了如何专业地将大型应用程序分割成许多小模块的方法;每个模块至少完成一个用例。我们知道,任何技术要生存下来,都必须在日益知识化的市场中击败各种竞争,这需要突破性的商业和技术案例。然而,用例通常是在使用任何技术支持的应用和服务时,用户(人类)、用户代理/服务(软件)或物联网和 I/O 设备所获得的好处。在这个模式中,关键是开始、识别和优先考虑用例。用例无疑是开发新应用程序以及现代化现有应用程序的关键因素和转折点。这种模式通过产生新的服务和提取大应用程序内部封装的隐藏微服务,有助于产生下一代应用程序。
基于资源的分解模式
在这种模式中,它是根据它们访问或控制的资源(服务器机器、存储设备、网络组件、软件基础设施、数据库等)来定义微服务的。这允许创建一组微服务,它们作为访问单个资源的通道。我们展望着应用程序感知基础设施和基础设施感知应用程序的时代。为了微服务展现其特殊能力,底层资源发挥着重要作用,这一点不容忽视。
基于业务能力的分解模式
功能性是另一种将单体应用程序分解成许多可互操作的微服务的选项。这些功能或责任通常是业务特定的或非特定的。也就是说,这些垂直以及水平功能可以很容易地被应用程序的多个部分使用。从粗粒度角度来看,许多细粒度服务可以由这些更大的功能/责任产生。这是 MSA 时代的一个有趣模式。
越来越多的业务应用正变得复杂和复杂。大量的第三方应用正在集成。单体和大规模应用是目前最普遍和突出的。面向服务的架构(SOA)模式主要用于通过特定的包装和面向服务的接口在不同和分布式应用程序之间建立和维持无缝和自发的集成。也就是说,企业级和云应用集成是通过 SOA 技术和技巧实现的。在理解了 MSA 模式战略意义之后,商业巨头正在制定战略,以平稳地进入 MSA 之路,以正确和适当地服务于他们的客户和客户。除了将大规模应用分解为易于管理、松散耦合且相对简单的服务集合之外,MSA 范式通过实现持续交付/部署来加速软件开发。
为了实现上述好处,必须非常小心地将应用程序分解为微服务。面向对象设计(OOD)世界的一个有用指南是单一职责原则(SRP),它将类的职责定义为改变的原因,并指出类应该只有一个改变的原因。面向对象设计中的另一个有用原则是共同封闭原则(CCP);一起改变的事物应该打包在一起,以确保每次改变只影响一个服务。
有前景的解决方案方法如下。定义与业务能力相对应的服务。业务能力是指企业为了创造价值所做的事情。业务能力通常对应于业务对象,例如:
-
订单管理负责订单
-
客户管理负责客户
这种基于业务能力的单体应用分解是为了长期造福企业。此外,通过业务能力服务的编排,可以实现更大、更好的业务能力。为了在运行时根据需要生成过程感知的复合应用程序,有 API 网关、分区最佳实践、用于托管微服务的 Docker 容器、编排工具和治理引擎。
子域模式分解
为了构建模块化软件应用程序,应用程序组件和服务需要松散耦合(每个服务都有一个封装其实施的 API,其实施可以更改而不影响其客户端)和内聚(一个服务应实现一组强相关的功能)。通过基于组件的软件组装和面向服务架构(SOA)方法,设置和维护模块化应用程序已经成为常态。这些组件和服务通常是粗粒度的。随着服务架构的日益普及和深入,创建细粒度服务正在积聚势头。MSA 的主要目标是通过对持续集成、部署和交付的支持,快速将软件解决方案推向市场。因此,对应用程序和粗粒度服务的系统化和明智的分解正在获得特别的关注。在上述模式中,我们讨论了业务能力是分解应用程序的基础。
此模式建议按子域进行分解。建议定义与领域驱动设计(DDD)子域相对应的服务。DDD 指的是应用程序的问题空间(业务)作为领域。一个领域由多个子域组成。每个子域对应业务的不同部分。在线商店应用的子域包括:
-
产品目录
-
库存管理
-
订单管理
-
配送管理
由于子域相对稳定,因此结果服务架构相当稳定。挑战在于精确识别子域。分解遵循分而治之范式。随着数字时代的到来,软件复杂性将上升,因此将分解技术纳入视野。大型和打包的应用程序需要分解,以便获得决定性和深入的理解。
微服务部署模式
微服务的部署方式和手段多种多样。包括一些运行时和执行环境,如裸机(BM)服务器、虚拟机(VMs)和容器。因此,部署选项也增多了。然后,一个服务器需要容纳一个或多个相同的微服务实例。部署模式的选取并不简单,而是取决于各种参数。
每个主机上的多个服务实例模式
微服务通常规模较小,因此可以快速构建、调整、组合和部署。微服务的可用性和吞吐量很重要。冗余是保证高可用性和吞吐量的一个广泛使用的方法。也就是说,每个服务都作为一组服务实例进行部署。
微服务的美丽之处在于服务可以使用不同的编程语言和框架来实现。正如一开始所阐述的,微服务可以独立部署和水平扩展。为了确保服务的安全和安全,服务实例必须彼此明确隔离。服务实例消耗的资源(处理器/核心/线程、内存、存储等)需要被细致地监控、测量和管理,以确保不同 IT 资源的优化利用。
在物理或虚拟服务器上运行不同服务的多个实例是可能的。可以将每个服务实例作为 JVM 进程部署,也可以在同一 JVM 中部署多个实例。随着密度的提高,资源以及服务的利用率必然会增加。与此模式相关的问题包括资源竞争、资源依赖和资源监控。
每个主机一个服务实例模式
这是另一种服务部署模式。存在一些需求和场景,其中服务的多个实例部署在单个服务器上。另一方面,也有只部署一个实例并在主机机器上运行的需求。这种方法的优点包括:
-
服务实例之间是完全隔离的
-
没有资源竞争,与依赖相关的问题也不再存在
-
服务实例最多只能消耗单个主机的资源
-
监控、管理和重新部署每个服务实例都很简单
缺点是资源利用率可能会降低。
每个虚拟机一个服务实例模式
服务实例部署有几种选择。BM 服务器、虚拟机(VMs)以及最近,Docker 容器是主流的部署和运行环境。此模式指定了在虚拟机中部署服务。云环境正日益虚拟化,因此托管在虚拟机上的服务正在蓬勃发展。由云服务提供商(CSPs)提供的自动扩展功能有助于快速且并发地提供新的虚拟机,以水平扩展服务实例的数量。此机制确保了所需的性能水平和服务的可用性。服务隔离发生在虚拟机级别。这里典型的难题是虚拟机配置需要几分钟。
每个容器一个服务实例模式
每个软件模块都通过 Docker 打包格式和开源平台进行容器化,该特定应用或服务的 Docker 镜像被存储在公开可发现和可访问的枢纽中。当 Docker 镜像被提交时,它自动成为一个可以立即部署和运行的 Docker 容器。容器开始向外界提供实现的服务,以便订阅和消费。原始的开源 Docker 平台正在通过一系列开创性的工具、引擎和框架迅速加强,以实现全方位的自动化。有 Docker 机器、容器集群管理平台、编排和网络工具、容器监控工具等等,以宣布 Docker 支持的容器化成为生产级技术。微服务和 Docker 范式的关键融合是为了为生产更大、更好的软件应用奠定坚实的基础。
与虚拟机不同,容器的创建和运行速度相当快。这意味着,通过利用容器,可以实现实时可伸缩性。作为最佳实践,每个容器都应该托管一个服务实例。通过多个容器,可以拥有多个服务实例。通常,由于容器的轻量级特性,可以在物理主机上舒适地运行数十个甚至数百个应用容器。
无服务器部署模式
无服务器计算,也被称为函数即服务(FaaS),正吸引着众多关注和市场份额。应用服务的开发、调试、部署、交付和退役是任何应用生命周期管理(ALM)过程中的主要部分。也就是说,需要运维人员建立并维护优化的基础设施来部署和运行软件应用。
这种无服务器部署模式推荐一种隐藏服务器概念(无论是物理的还是虚拟的)的部署基础设施。该基础设施运行应用服务的代码。用户必须根据消耗的资源为他的每个请求付费。性能、可伸缩性和可用性要求将自动满足。几乎所有的主流云服务提供商都在提供这种新的部署模式。这是一种新的云服务,确保每个功能都作为服务提供。
例如,从一个 AWS Lambda 函数开始,这是一个无状态的组件,用于处理事件。要创建 AWS Lambda 函数,用户必须将他的 NodeJS、Java 或 Python 代码打包成 ZIP 文件,并上传到 AWS Lambda。当发生事件时,AWS Lambda 会找到一个空闲的函数实例,如果没有可用实例,则会启动一个实例并调用处理函数。AWS Lambda 可以根据需要自动运行更多实例,以处理额外的用户和负载。
调用 lambda 函数有四种方式。一种选项是将 lambda 函数配置为在 AWS 服务生成的事件响应中调用。以下是一些事件的示例:
-
一个对象被存放在 S3 桶中
-
在 DynamoDB 表中创建、更新或删除一个条目
-
可以从 Kinesis 流中读取一条消息
另一种调用 lambda 函数的方式是配置 AWS Lambda 网关将 HTTP 请求路由到 lambda 函数。AWS 网关将 HTTP 请求转换为事件对象,调用 lambda 函数,并从 lambda 函数的结果生成 HTTP 响应。
还可以使用 AWS Lambda Web 服务 API 调用 lambda 函数。调用 lambda 函数的应用程序提供一个 JSON 对象,该对象传递给 lambda 函数。Web 服务调用返回 lambda 返回的值。调用 lambda 函数的第四种和最后一种方式是定期使用类似于 cron 的机制。可以告诉 AWS 每五分钟调用一次 lambda 函数。
优点很多;基础设施的配置、设置和管理时间,以及财力和人才都得到了显著减少。软件工程师可以冷静地专注于他们的核心优势,而无需为准备基础设施来运行他们的应用程序而烦恼。然而,也有一些限制。目前 AWS Lambda 支持的语言有限。它仅适用于部署快速响应请求的无状态应用程序。在无服务器模式下运行长时间运行的状态应用程序,如数据库或消息代理是不可能的。如果一个应用程序启动时间很长,那么这个应用程序不适合无服务器部署。同样,遗留的单一和大型应用程序也不适合无服务器计算。无服务器部署通常是反应性的,而不是主动性的,因此可能会出现高延迟的问题。
服务部署平台模式
市场上有一些自动化的软件部署工具。IBM UrbanCode Deploy 是一个应用程序发布自动化解决方案。该软件允许按需或按计划无缝部署到分布式数据中心和云环境。它可以扩展到企业级部署,处理数千台服务器。其他流行的软件部署自动化解决方案包括:
-
Docker 编排框架,包括 Docker Swarm 和 Kubernetes (
kubernetes.io/) -
无服务器平台,例如 AWS Lambda
-
PaaS 包括 Cloud Foundry
部署、发布和交付活动正越来越多地通过一系列工具实现自动化。为了更快地将软件推向市场,工具支持的持续集成、部署和交付是必不可少的,上述模式对于软件架构师和设计师来说非常有用。
微服务设计模式
设计能够与其他服务无缝且自发地工作的微服务对于 MSA 的预期成功至关重要。同样,通过微服务的力量优雅且高效地设计云、企业、移动、物联网、分析、运营和事务性应用程序的架构也必须如此。正如之前所述,微服务可以通过多种技术和工具实现。此外,辉煌的 MSA 架构范式在未来的意义上是,任何新技术都可以轻松用于生产下一代微服务,这些微服务易于发现、访问、评估、操作、替换、替代等。接下来的部分将列出所有主导的设计模式,以逐步迈向预期的 MSA 时代。
设计模式通常是细粒度的,并且对构建单个以及复合微服务做出了巨大贡献。不仅业务逻辑,设计模式也有助于附加数据连接性和持久性逻辑。因此,设计模式对于提供 MSA 架构预期的成功至关重要。以下部分将列举并解释关键的设计模式。
聚合器微服务设计模式
服务和数据聚合对于 MSA 模式的预期成功至关重要。由于服务相对较小,并且通常一个微服务实现单个任务,因此需要识别和聚合多个分布式和去中心化的服务,以提供全面的企业功能特性。因此,聚合器模式对于 MSA 时代至关重要。由于每个服务都是通过轻量级的 RESTful 接口暴露的,一个由许多微服务组成的应用程序可以通过使用此聚合器模式从不同的服务中检索数据,并相应地处理/显示它。
如果在数据显示之前需要对检索到的数据进行某种处理,存在可行的选项来引入所需业务逻辑:

如果聚合必须在服务级别发生以创建组合服务,那么聚合器将仅从每个参与的服务中收集数据,对其应用规定的业务逻辑,然后使用组合 REST 端点进行聚合和发布。这个以过程为中心的组合服务然后可以被需要它的其他服务消费。所有微服务可能都有自己的缓存和数据库。组合服务也可以拥有自己的缓存和数据库层。聚合器可以在x轴和z轴上独立扩展。
代理微服务设计模式
这种模式是聚合器的一种轻微变化。在这种情况下,客户端不参与聚合活动。根据业务需求,可以调用不同的微服务。代理模式也可以在x轴和z轴上独立扩展。其想法是每个微服务不需要暴露给消费者。代理可能是一个哑代理,在这种情况下,它只是将请求委派给其中一个服务。或者,它可能是一个智能代理,在向客户端提供响应之前,对某些数据进行转换。随着不同物联网和 I/O 设备的爆炸式增长,这种代理模式是有益的。
链式微服务设计模式
这是为了对一个请求产生一个单一的汇总响应。在这种情况下,客户端的请求由服务 A 接收,然后与服务 B 通信,服务 B 反过来可能与服务 C 通信。所有服务都可能使用同步的 HTTP 请求/响应消息。这里的关键问题是客户端在链中的所有服务完成处理之前被阻塞。也就是说,服务 A 到服务 B 再到服务 B 到服务 C 的链必须短且小,否则,同步通信可能会导致延迟。
微服务底盘模式
横切关注点众多,并且在任何应用程序的源代码中也是重复出现的。以独特的方式解决这些在企业级应用程序中普遍存在的横切关注点的面向方面编程模型是第一个。众所周知的例子包括身份和访问、数据库和网络位置、消息平台、日志记录、数据加密、评估指标等等。众所周知,微服务在规模上较小,在开发、测试、调试、部署和交付方面都很快。也就是说,一个小团队的开发者可以在一天或两天内构建一个服务。根据 MSA 模式,这些来自多个开发团队的小规模服务被有目的地挑选出来,并即时融合形成关键任务应用程序。生成基于微服务的流程感知应用程序的整个过程在短时间内完成。在这里,花费大量额外时间来附加各种横切关注点并不是一个逻辑上合理的论点。因此,微服务底盘框架被制定并推荐用于从应用程序的角度构建微服务。当开发者利用 MSA 模式时,还必须结合 MSA 特定的横切关注点,例如服务注册和发现以及断路器,以可靠地处理部分故障。因此,最佳解决方案是在创建微服务时,至关重要的是添加处理上述横切关注点的精简和清晰代码。这种嵌入横切关注点的方式是 MSA 世界中最明智的前进方式。
外部化配置模式
任何企业级应用程序通常使用一个或多个基础设施和第三方服务。例如,应用程序必须使用一些常见的基础设施服务,如服务注册、身份验证、授权和审计服务、消息代理和队列、文件系统、数据库、知识可视化平台、安全等。进一步来说,还有几个第三方应用程序和服务,如支付网关、电子邮件服务器等。因此,任何生产级应用程序都必须直接或间接地连接到本地和远程服务,以展示高度集成的功能。另一个相关的问题是,我们如何使服务能够在多个环境中运行而无需任何修改?
通常,一个服务必须提供配置数据,以告知它如何连接到其他服务。例如,为了连接到数据库,数据库的网络位置和凭证必须附加到配置数据中。此外,还有诸如 QA 数据库与生产环境数据库之类的变体。突出的解决方案方法是将所有以应用为中心的配置信息外部化,以便服务从外部源读取配置细节以完美地完成其功能。这种模式的优点是应用服务可以在多个环境中运行而无需修改和/或重新编译。
微服务数据库模式
数据持久性是任何微服务的重要因素。近期,为了存储原始和加工后的数据,出现了新的数据库管理系统。有大型、快速、流式、物联网数据,以及各种数据处理类型,如批量、实时、交互式和迭代处理。为了支持数据驱动的洞察和洞察驱动的决策,新鲜数据捕获、摄取、存储、处理、挖掘、分析和可视化技术和工具正在涌现并不断发展。在 MSA(微服务架构)世界中存在几个与数据相关的模式,本节专门准备来讨论这些模式。
每个服务一个数据库模式
MSA(微服务架构)模式正在被关键任务应用所采用,并且这些符合 MSA 规范的应用必然提供了各种业务、技术和用户优势。意识到 MSA 理念的战略意义后,全球的企业、组织和机构都热衷于制定可行的和获胜的策略和计划,以利用 MSA 范式独特的功能。正如我们所知,微服务可以使用多种语言进行编码,微服务的数据持久化需求可以由包括数据库管理系统(DBMS)、文件系统等在内的多个系统来满足。进一步来说,还有 SQL、NoSQL、NewSQL、内存中、数据库内数据库管理系统。因此,微服务支持多语言能力。此模式建议利用每个服务的一个数据库。
随着数据密集型应用(如电子商务、商业、供应链管理等)的日益增多,这些应用被分割成一组相互作用的服务的集合。在此,每个服务都需要持久化自己的数据。因此,每个微服务必须通过其自身的数据持久化机制相应地启用。当每个微服务使用自己的数据库时,会存在一些挑战。复杂的业务交易需要在多个服务、多个数据库之间工作。进一步来说,某些业务操作必须更新多个服务拥有的数据。有时,需要查询多个服务拥有的数据。为了扩展,数据库有时需要复制和共享。
为了确保所需的最大数据安全隔离,正在坚持 API 驱动的访问。服务的数据库实际上是该服务实现的一部分。数据库不能被其他服务直接访问。API 是数据库访问的前进方向。有一些不同的方法可以保持服务持久数据的隐私。首先,可以为每个微服务构建一个单独的表并分配给它。其次,可以为每个微服务生成一个单独的模式。最后,可以为每个服务分配一个单独的数据库服务器。每个服务都有一个数据库确保微服务是松散耦合的,并且可以根据每个服务的任务选择最佳的数据库解决方案。例如,执行文本搜索的微服务可以分配一个文本挖掘和搜索引擎。同样,执行社交媒体分析的微服务可以配备一个图数据库,如 Neo4j。
然而,众所周知,NoSQL 数据库不支持 ACID 属性,因此分布式和嵌套事务不适合涉及 NoSQL 后端系统的微服务。这里的选项是使用最终一致性和事件驱动架构(EDA)。服务生产者将他们的消息以主题的形式发布到消息队列中,而服务消费者订阅这些主题并使用它们。一些查询需要从多个数据库中联合数据。前进的方式是赋予应用程序执行联合操作的能力,而不是在数据库中完成。例如,API 网关或一种组合服务可以检索客户及其订单,来自客户和订单微服务。然后,联合操作可以由 API 网关或组合服务完成。另一种选择是利用命令查询责任分离(CQRS)模式。
共享数据设计模式
微服务是自我定义和自治的。也就是说,微服务拥有所有模块(表示逻辑、业务逻辑、集成逻辑、数据连接性和持久性逻辑),可以独立运行。进一步来说,服务可以轻松地利用经过验证的技术和工具,实现完全的多语言。也就是说,如今,有几种数据库管理系统,如 SQL、NoSQL、NewSQL 等,微服务可以选择其中任何一个来满足它们所需的数据持久性,以极其优雅地贡献于最初表达和设想的企业目标。
组织将遗留应用程序现代化,使其成为具有微服务功能的现代应用程序。这里的突出挑战之一是数据库规范化。也就是说,每个微服务都必须拥有正确数量的数据。在这个设计模式中,一些服务,可能是一个链中的服务,可能会共享缓存和数据库存储。如果这两个服务之间存在强烈的耦合,这是合理的。这种模式可能被归类为反模式,因为微服务假设并提出了无共享现象。对于以微服务为中心的绿色田野应用,这种模式无疑是反模式。这种模式可以在从单体到微服务的过渡阶段作为临时方面得到利用。
共享数据库模式
微服务架构的成功逃逸有几个独特的因素。我们熟悉共享数据库。现在,在大数据和 Web 规模应用时代,各种新的、功能不同的数据库已经出现,并为许多新一代应用做出了贡献。因此,之前讨论的模式建议为不同的服务使用专用数据库。然而,存在某些要求,如以 ACID 为中心的事务和事务型应用。解决方案是使用由多个微服务共享的单个数据库。每个微服务都能舒适且方便地访问其他微服务拥有的数据。共享数据库确保了数据的一致性达到极致。单个共享数据库的管理和运营复杂性较低。
如常,共享数据库模式存在一些缺点。首先也是最重要的是服务与数据库之间的紧密耦合。其次是与数据共享相关的问题。传统的 SQL 数据库不支持水平扩展,因此,数据量的激增无法由跨多个服务的共享 SQL 数据库处理。
命令查询责任分离(CQRS)模式
在微服务世界中,实现连接来自多个服务和它们自己的数据库的查询是一个真正的挑战。解决方案是将应用程序分成两部分;命令端和查询端。命令端处理创建、更新和删除请求,并在数据更改时发出事件。查询端通过执行一个或多个由订阅数据更改时发出的事件流来保持更新的物化视图来处理查询。这种模式有很多优点。这种模式对于事件驱动架构(EDA)环境尤其必要。这提供了更好的关注点分离,并支持多个非规范化视图。
微服务集成模式
微服务是自治和自定义的。然而,分布式和去中心化的服务应该相互交谈,以产生强大的以流程为中心和业务关键的应用。本节专门分配给您了解 MSA 环境中正在酝酿的集成模式。
远程过程调用(RPI)模式
微服务必须与多个微服务交互才能完成任何复杂的功能。为此,服务使用进程间通信协议。解决方案是利用 RPI 进行任何服务间的通信和协作。客户端使用基于请求/回复的协议向服务发送请求。知名的 RPI 技术包括 REST、gRPC 和 Apache Thrift。这种模式易于实现,无需任何中间代理来促进预期的通信。然而,这种模式有几个关键的缺点。那就是,服务之间紧密耦合,必须在线才能找到、绑定和交互。其他突出的交互类型,如通知、请求/异步响应、发布/订阅和发布/异步响应,这里不支持。
消息设计模式
消息通常是异步的,在服务间通信中被广泛使用。服务通过在消息通道上交换标准化的消息来相互交谈。市场上存在消息代理、中心节点和队列(如 Apache Kafka、RabbitMQ 等)。这种模式有以下优点:
-
消息使得参与和贡献服务之间松散且轻量级的耦合成为可能。依赖地狱在这里被消除。
-
消息代理通常将消息缓冲,直到订阅者/消费者能够接收和处理它们。这种基于中间代理的消息存储增强了消息的可用性。这种模式支持多种通信模式,如“发送即忘”,轮询、发布和订阅。
通过消息中间件解决方案实现的异步通信最终成为分布式计算时代的救世主。
异步消息设计模式
强调基于消息的异步通信,以建立和维护可靠的弹性微服务。微服务之间松散且轻量级的耦合以及通过传递标准化消息发生的交互被视为 MSA 模式的成功公式。高度流行的 REST 设计模式通常是同步的,因此会阻塞客户端服务。通过 RESTful 协议,仍然可以实现所需的异步交互,但这必须在应用层面实现。因此,在 MSA 世界中,消息代理和队列的使用显著增加。进一步来说,存在同步和异步通信的混合。例如,服务 A 可能同步调用服务 C,然后通过共享的消息队列异步与服务 B 和 D 通信。通过使用 WebSockets,服务 A 可以以异步方式与服务 C 通信,以实现规定的可伸缩性。精确地说,可以使用请求/响应(REST)和发布/订阅消息的组合来完成任何独特的业务需求。
领域特定协议模式
存在着更多种类的进程间通信协议。对于某些场景,推荐使用领域特定协议进行进程间通信。对于电子邮件服务,SMTP 和 IMAP 是首选的协议。对于媒体流需求,RTMP、HLS 和 HDS 正在得到应用。
API 网关模式
在 MSA 世界中存在一些挑战。微服务通常是细粒度的,并且每个微服务都拥有粒度化的 API。其他特点包括不同的服务使用不同的语言编写,以及许多数据传输协议和数据持久化方法。简而言之,服务支持多语言架构。进一步来说,存在多种客户端选项,如桌面、移动、可穿戴、便携式和固定设备。有明确的情况是,从不同的和分布式的微服务和数据服务中消耗数据和应用程序逻辑。精确地说,我们正走向分布式计算的时代。微服务需要找到适当的交互服务,并在规定的时间和 SLA 合规的范围内完成所需的业务功能目标。
网络拓扑和技术在塑造 MSA 应用中也发挥着至关重要的作用。WAN、MAN、LAN、CAN、PAN 和 BAN 等不同方法的延迟不同。也就是说,个人区域网络的延迟较低,而广域网络的延迟较高。微服务可以快速多次访问附近的微服务,而在远程服务的情况下,服务访问次数较低且耗时较长。
可行且增值的解决方案方法是将 API 网关作为所有类型服务的单一接触点(SPOC)以与本地和远程服务进行交互。所有类型的连接性、调解、经纪、聚合、消息丰富、协议和数据格式转换等均由这种标准化的 API 网关解决方案负责。通过此 API 网关服务,可以整洁地找到和组合多种服务和数据源,该服务还可以为每个客户端暴露独特的 API。通过网络通道传输的数据和消息的安全要求也由该产品完成。
前端后端模式
此模式建议并为每种类型的客户端定义一个独立的 API。通常,除了传统的 Web 界面外,移动和管理界面在当今也很常见。API 网关具有为不同客户端类型提供不同 API 的能力。API 网关能够隔离客户端与应用程序,应用程序可以被划分为多个协作的微服务。这样,任何类型的应用程序重构、重新平台化和改造都不会对接近客户端产生任何恶意影响。可以根据适当的客户端选择和使用的最佳 API。API 网关使客户端能够通过单次往返操作从多个服务和来源检索数据。更少的请求也意味着更少的开销,并改善了用户体验。可以根据需要编排多个后端微服务和数据源,以产生更大更好的应用程序。这种转型为用户代理提供了独特的体验。API 网关本质上负责所有类型的数据和协议转换。
微服务注册、发现和使用模式
为了在运行时找到并相应地利用服务,服务需要在公开可用的服务注册表中注册。在动态和分布式环境中,服务会移动,因此运行时服务发现的任务必须通过此类网络可访问的注册表和存储库来简化。不仅服务,它们的实例也必须注册,以简化服务高可用性的目标。
服务发现模式
微服务必须找到一个或多个适当的微服务,以启动一种对话,以满足已识别的业务功能。众所周知,有几种服务发现机制、服务注册表和存储库。在传统的 Web 服务世界中,我们曾经围绕 WSDL 和 UDDI 进行服务接口、发现和启动的实验。在早期时代,我们也曾尝试 RPC、RMI、CORBA、EJB、Jini 等。在最近过去,RESTful 服务交互是建立服务连接和服务实现的最常见方式。
然而,微服务在动态性、多样性和灵活性方面非常独特,数量众多。进一步来说,服务主要是为了在虚拟机和容器中运行而设计的。虚拟化和容器化环境具有动态性,固有地能够提供虚拟化资源和工作负载的实时迁移能力。API 网关是一种解决方案,可以适当地使服务能够发现服务以对应并完成业务功能。服务注册包含所有参与和贡献服务的必要信息,如位置、主机、端口等。这种机制有助于显著减少尝试涉及其他服务的服务的网络跳数。
对于企业级服务,连接通常通过集群负载均衡器来实现。负载均衡器的位置是预定义和确定的。服务将请求发送到负载均衡器,负载均衡器随后查询服务注册,该注册可能集成在负载均衡器中。然后负载均衡器将服务请求和查询转发到特定服务的可用实例。
流行的集群解决方案,如 Kubernetes (github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/services.md) 和 Marathon (mesosphere.github.io/marathon/docs/service-discovery-load-balancing.html) 在每个主机上运行一个代理。代理实际上充当服务器端发现路由器/负载均衡器。为了访问一个服务,客户端服务通过分配给该服务的端口连接到本地代理。然后代理将请求转发到集群中某处运行的服务实例。路由器、应用交付控制器(ADCs)、负载均衡器和其他网络解决方案模块在大规模 IT 环境中(如云)可用。
服务注册模式
服务注册和存储库对于任何软件开发组织都至关重要。随着微服务成为下一代应用构建块,服务和它们一站式注册的相关性正在上升。服务注册为环境中的每个服务提供所有正确的引用。也就是说,每个服务一旦开发完成,就必须在服务注册中注册,以便被发现、绑定并做出巨大贡献。因此,任何想要与其他服务连接的服务都必须首先连接到服务注册,以收集所有服务的发现、访问和利用细节。服务注册可能会调用服务实例的健康检查 API 来验证它是否能够处理请求。知名的服务注册技术包括:
-
Apache Zookeeper
-
Consul
-
Etcd
在服务世界中,服务注册表非常重要,它必须高度可用。如果它连短时间内都无法可用,那么业务连续性就处于危险之中。
服务注册模式
我们已经讨论了服务注册的重要性。由于微服务的动态性,服务注册表的作用变得特别重要。每个服务都必须在服务注册表中注册,以便对业务极为有益。也就是说,每个实例的详细信息必须在每个实例开始其漫长而艰巨的旅程时注册到服务注册表中。另一方面,当服务实例被退役或关闭时,服务实例将被注销。
微服务可以自行注册,或者可以指定第三方解决方案来注册每个服务实例。在第一种情况下,微服务完全负责将自己注册到服务注册表中。在启动时,服务会将自己(主机和 IP 地址)注册到服务注册表中,并使其可被发现和连接。不仅服务本身,而且这些服务的每个实例都必须有系统地注册到服务注册表中。如果一个服务实例失败,其他服务实例可以方便地维持业务运营、提供和输出。在第二种情况下,可以与第三方解决方案和服务提供商签订合同,以设置服务注册表来注册每个服务实例。
事件驱动架构(EDA)模式
随着大量数字化物品/智能对象/感知材料的出现,以及我们日常环境中成百上千的连接设备,每个人在决策、行为和交易方面都将变得更加明智。在预期的物联网世界中,许多决定性和更深入的自动化必将发生。我们周围的所有有形事物都将内外部获得权力,以便在适当的时候主动和预防性地对各种值得注意的事件采取行动。也就是说,我们周围和周围的每一个实体都将被事件驱动。在预期的事件驱动世界中,IT 的作用至关重要,具有突破性。IT 系统和业务应用程序/服务必须捕获、缓冲、处理、挖掘和分析所有传入的事件,以产生见解。未来的日子肯定是数字化的,我们的日常系统应该足够聪明和熟练,以便能够感知和反应。在这里,EDA 在使我们的 IT 和业务系统具有创新性、颠覆性和变革性方面发挥的作用和责任必将进一步增长。
在 MSA(微服务架构)世界中,每个服务使用数据库是主要的解决方案。但是,有一些特定要求,其中 ACID 事务对于保证数据一致性目标是强制性的。前进的道路是使用经过验证和潜在的事件驱动架构来实现数据一致性。也就是说,每个服务在更新其数据时都会发布一个事件。其他服务订阅这些发布的事件,并相应地更新它们自己的数据库。这保证了多个微服务之间的数据一致性,而无需通过传统的分布式事务。
为了实现更快交付周期的承诺,团队需要自主权。团队间的依赖是缓慢进步的配方。这就是为什么单体架构进步缓慢的原因。服务之间的隔离是团队保持自主权的方式——维持这种隔离至关重要。
每个团队都必须有权做出独立决策,甚至关于他们的数据层,而不会影响或依赖任何其他团队。甚至数据存储类型的选择也应该是独立的——这个概念被称为多语言持久性。数据如何建模也应该是一个自主决策,本地化到每个服务。团队应该完全控制对模式进行更改,即添加或删除表和实体,或列和属性。那么修改、添加或删除类和对象呢?在自主团队中,这些需要是对其他团队非破坏性的更改,以保护每个团队的自主权。确保每个团队都有权做出自己的数据层选择的最佳方式是不在微服务之间共享数据存储。
服务之间的隔离为每个微服务设定了边界,而事件驱动机制解决了服务如何通信的问题。事件驱动系统在架构的整体运行中起着至关重要的作用。
事件源模式
事件溯源是一种架构模式,其中应用程序的状态由一系列事件确定。序列中的每个事件都记录在只追加的事件存储库或流中。传统上,大多数软件应用与数据交互,并且应用必须通过在用户操作数据时更新数据来维护数据的当前状态。典型的数据处理过程是从存储中读取数据,对其进行一些修改,并使用新值更新数据的当前状态。事务是改变数据值的过程。然而,这种数据更新和数据一致性维护的方式有许多固有的局限性。在完成分布式事务时,需要两阶段提交(2PC)。任何 2PC 提交都会大幅度降低事务吞吐量。当有多个并发用户时,由于更新操作发生在单个数据项上,可能会出现数据更新冲突的可能性。进一步来说,还需要一个额外的审计机制,该机制记录每个操作的详细信息到一个单独的日志中,否则历史记录就会丢失。
事件溯源通过使用以事件为中心的方法,实现了所需的原子性,而不需要复杂的 2PC 过程。而不是存储实体的当前状态,应用程序存储一系列状态改变的事件。也就是说,每当业务实体的状态发生变化时,就会创建一个新的事件并将其附加到已捕获和存储的事件列表中。由于保存事件是一个单一操作,因此它是原子的。然后,软件应用可以通过回放事件轻松地重建实体的当前状态。
软件应用和服务通常将事件持久化存储在事件存储库(事件数据库)中,事件存储库公开了一个 API,用于添加和检索业务实体的事件。事件存储库还像是一个发布和订阅消息代理。订阅者可以订阅特定的事件。每当有新事件发生时,事件存储库将其发送给所有合法的订阅者。进一步来说,应用程序可以定期保存实体的当前状态快照。为了重建当前状态,应用程序将最近的快照和自该快照以来发生的事件进行回放。因此,在事件驱动世界中,事件溯源和存储变得尤为重要。
事务日志尾部模式
这是实现分布式事务的另一种选择。其思路是跟踪数据库事务日志,并将每个更改发布为一个事件。这种模式的优点是无需在应用层进行任何更改;所有操作都在数据库层完成。避免重复发布有点困难。这种模式确保了低级别的数据库更改,但确定业务级别的事件相当困难。
使用数据库触发器模式发布事件
这是解决多个微服务之间分布式事务挑战和关注点的另一种解决方案方法。一个或多个数据库触发器将事件插入到EVENTS表中,该表由一个独立的过程轮询,该过程将事件发布到消息代理,并且所需的微服务和它们的数据库消费它们并相应地更新。
应用程序发布事件模式
应用程序将事件插入到作为本地事务一部分的EVENTS表中。一个独立的过程轮询EVENTS表并将事件发布到消息代理。与这种模式相关的主要关注点是必须在应用程序上实施适当的更改。
将成为一个事件驱动的世界。形式化和标准化的事件将成为未来系统敏感、响应和弹性行动和反应的真实区分器。随着物联网时代的迅速到来,将有数万亿的事件和必须相应定义和设计的 IT 系统以及业务应用程序。在此,微服务在建立和维持此类适应性、以人为本、流程优化、面向服务和事件驱动的应用程序中的作用显著增长。EDA 模式正成为物联网世界的极其合适的实体。微服务能够捕获和处理事件消息以产生正确的输出。基于消息的异步通信模型也由微服务支持。
测试和故障排除模式
执行服务验证和验证以了解其提供分配功能的能力,以及非功能性需求(NFRs),是微服务宣称成功的重要参数和因素。本节将简要介绍服务测试、调试和故障排除。
访问令牌模式
我们讨论了 API 网关在实现微服务架构模式预期成功方面的贡献。API 网关是客户端服务的第一个入口点,它代表客户端服务工作。然而,挑战是如何进行用户识别、认证和授权。也就是说,如何将用户代理/请求服务的身份与请求的服务通信,以启动按表达意图执行的任务。
API 网关验证请求并传递一个访问令牌(例如,JSON Web Token,jwt.io/),该令牌在每个请求中安全地识别请求者。一个服务可以在它对其他服务的请求中包含访问令牌。
服务组件测试模式
测试微服务和它们的实例对于服务验证和验证非常重要。编写示例测试用例并利用自动化测试工具有助于检查服务是否按预期运行。对涉及许多分布式和去中心化微服务的应用程序进行端到端测试确实不是一件容易的事情。解决方案是使用经过验证的测试套件。微服务可以独立通过测试,但基于微服务的应用程序的测试带来了一些挑战。
日志聚合模式
任何微服务的每个实例都会以标准化的格式将其正在执行的操作信息写入日志文件。日志文件通常包含错误、警告、信息和调试消息。挑战在于理解应用程序行为,并使用单个日志来排除应用程序的故障。前进的方式是使用一个集中的日志服务,该服务本质上会聚合每个服务实例产生的所有日志。有日志分析自动化工具。一般来说,日志分析会在软件和硬件组件的功能出现任何重大偏差时发出预警。管理员和用户分别访问日志存储并从日志中搜索任何有用的信息,以便思考下一步的行动。
应用指标模式
这是理解并阐述应用程序行为的另一种方法。一直以来,我们都被大量的软件设计和评估指标所包围。为微服务最终确定所有正确和相关的指标是一个好的起点,以便达到了解应用程序行为的目标。推荐的解决方案是拥有一个集中的指标服务,该服务收集并存储每个服务操作的决策支持统计数据。微服务可以将它们的指标信息推送到指标服务。另一方面,指标服务可以从微服务中拉取指标。指标服务正在成为 MSA 世界中的一个重要组成部分。
审计日志模式
服务的可审计性非常关键。这有助于理解用户以及应用程序的行为。对所有用户交互进行审计将有助于设置和维持微服务环境。审计代码必须与业务逻辑交织在一起。
分布式跟踪模式
目前可用的软件测试和故障排除技术和工具被发现已经过时和无力,尤其是对于基于微服务的应用程序。随着我们从单体时代迈向有希望的微服务时代,我们需要一系列多功能的工具来检查独立的服务以及整体微服务应用程序。由于单个服务不能提供整体图景,新一代的测试和调试工具必须具有在应用层面做到同样事情的独特能力。也就是说,工具必须展示应用程序性能的完整图景,以及应用程序如何交付其功能。
因此,此模式建议利用分布式跟踪工具,该工具可以跟踪每个请求并在扫描多个微服务时捕获相关数据。然后,该工具将收集的详细信息汇总,以提供对应用程序行为和性能的全面和 360 度视图。解决方案方法是使用代码对每个微服务进行配置,为每个外部请求分配一个唯一的 ID。该代码使能够将 ID 传递给所有参与处理请求的服务,将 ID 包含在所有日志消息中,并最终记录如开始和结束时间等增值信息。此模式使开发者能够通过搜索汇总日志来查看单个请求的处理方式。
异常跟踪模式
微服务和它们的各个实例被部署在多个 BM 服务器、虚拟机(VM)甚至 Docker 容器中。当服务处理来自其他服务的请求时可能会发生错误。通常,服务会抛出一个包含错误信息和堆栈跟踪的异常。这里的需要是对异常进行去重、记录并自觉地调查它们,以理解和解决这些问题。方法是向集中式异常跟踪服务报告所有异常。开发者和调试专业人员可以查看异常并确保及时解决。
健康检查 API 模式
健康检查一直是 IT 行业的重要组成部分。各种软件和硬件系统都在定期进行健康检查。对于微服务也是如此。服务在运行,但有时由于各种原因,它们无法处理服务请求。在这种情况下,服务监控系统必须生成警报并将其实时发送给运维团队进行处理。负载均衡器也理解任何失败的服务实例,并相应地将请求路由到实时服务,以确保业务连续性。服务注册表也必须注意失败实例,以便任何客户端服务都能获得功能服务的访问详情。解决方案机制是为每个服务提供一个健康检查 API 端点以执行各种健康检查。
微服务组合模式
组合活动是通过两种方式实现的:编排和协奏。组合任务超出了服务组合的范围。也就是说,流程、UI 和数据组合对于服务工程也非常重要。服务网格是行业中的新术语,有平台、实践和模式用于创建服务网格,以设想以前未知且业务和流程感知的服务组合。
服务器端页面片段组合模式
有面向客户的软件应用,如 B2C 电子商务网络应用和公司门户网站。这些应用是通过使用多个服务(专用和非专用)设计和开发的。有经过验证的机制,如业务能力、技术优势、横切关注点、领域中心性、服务质量(QoS)等,可以将原始应用程序分割成许多微服务,或者从头开始构建微服务。这里的一个方面是一些 UI 屏幕/页面服务必须显示来自多个服务的数据。UI 设计师绘制整体外观,而网络应用开发者专注于实现网页特定区域的 HTML 片段。UI 团队负责开发页面模板,通过在服务器端聚合特定于服务的 HTML 片段来构建页面。
客户端 UI 组合模式
如前所述的挑战是实现一个显示从多个服务聚合数据的 UI 屏幕或页面。网络开发者构建客户端 UI 组件,最终实现网页的区域。UI 团队负责实现页面骨架,通过组合多个特定于服务的 UI 组件来构建页面/屏幕。
基于消息的微服务组合模式
即使服务是隔离的,服务之间的某些通信也是必需的。由于应用程序由多个微服务组成,微服务需要以某种方式协同工作作为应用程序的一部分。给定服务的状态变化可能对其他微服务感兴趣。一个微服务的数据可能需要另一个微服务。服务之间通信的原因有很多。好的架构通过使微服务 API 成为访问其服务的唯一入口点来管理通信。
微服务 API 可以是同步的或异步的。由于网络延迟和间歇性连接,同步模式可能会出现问题。因此,异步、非阻塞的消息正在兴起,因为它允许微服务在等待彼此之前继续处理。这些消息构成了微服务之间松散耦合的基础。异步消息需要在一致性上做出一些妥协——它是一个最终一致性的模型。因此,获得的松散耦合和性能使得这是一个很好的权衡。
一个异步的、基于消息的事件驱动系统通过使它们之间的必要通信非侵入性,满足了微服务之间隔离的需求。微服务可以产生事件,而无需知道哪些服务正在消费这些事件以及事件是如何被处理的。对于微服务开发团队来说,事件驱动架构允许每个团队专注于自己的问题域。
微服务通常包括完整的科技栈,包括用户界面、中间层应用程序和最后一级数据持久化。根据业务需求,每个层级和层都分别使用组合模式。集成视图是一个这样的需求。同样,数据存储需要逻辑上集成,以便检索数据以提供综合视图。最后,在某些情况和场景中,需要将多个离散和原子服务集成和编排,以创建强大的复合体。因此,组合模式在塑造和支撑微服务时代方面发挥着越来越重要的作用。
弹性和可靠的微服务模式
与复制整个应用程序不同,应用程序的一部分或多个服务可以独立扩展。这就是微服务的力量。可扩展性功能被强调用于处理额外的用户和数据负载。微服务实例可以轻松地适应 Docker 容器。创建额外的容器既容易又快,因此,为了实现实时可扩展性,容器内嵌入的微服务正成为适当的方法。在本节中,我们将讨论准备可靠、弹性、可用和以微服务为中心的应用程序的多种模式。
电路断路器模式
基于微服务的应用程序设计在软件应用程序的设计、部署和交付方式上带来了微妙而智能的改变。现在,应用程序变成了一个动态的服务集合,这些服务相互依赖以执行各种任务。高度复杂和精细的应用程序必然涉及大量相互依赖的微服务。更多的依赖意味着更多的复杂性和复杂性。这种模式之所以突出,是因为它极大地有助于避免级联服务故障。这种模式的理念是持续监控应用程序的微服务和它们之间的流量,以防止故障。当故障发生时,这种模式有助于最小化这些故障对应用程序的影响。这种模式还试图从一开始就防止故障。对于某些类型的错误条件,例如内存耗尽,有可能认识到故障即将发生,并采取适当的措施来预防它。
这通常是通过服务发出它正在变得不健康的信号来实现的,然后断路器给服务一个机会通过减少请求数量或完全重新路由它们来恢复。一旦服务恢复,断路器会缓慢地增加对服务的请求数量,以免立即压倒它并使其再次变得不健康。
对于微服务,断路器模式保证了自下而上的弹性。如果这种模式被正确实现,它可以通过确保即使在服务不可用的情况下服务的连续性来帮助避免级联故障。确切地说,可以构建使用此模式的应用程序来优雅地降低功能,当方法调用失败时。
共享缓存层模式
在任何时间点,任何微服务的所有实例都有相同的数据需求,因此在这些实例之间拥有和共享一个缓存层是非常有意义的。当每个实例在其内存中都有自己的内部缓存来存储会话状态时,这种做法通常不会被遵循。这种安排将数据分散到不同的实例中,而这些实例应该被视为一个整体。共享缓存层消除了由这种其他情况下分散的数据层产生的运营复杂性,但它对共享缓存层提出了要求。
应用层对用户数据有一个统一的视图,并且可以通过任何实例访问。当使用共享缓存时,数据的更新对所有微服务实例都是可用的。如果数据层不是共享的,那么每个服务都会对数据有一个狭隘的视角,并且架构必须设置得使得任何给定的用户总是被路由到同一个实例。因此,拥有一个共享缓存层提供了对数据的一个集成和统一的视图。共享缓存层为后端存储提供了隔离层。对后端存储的更改只需在一个地方进行,并且这些更改将惠及所有微服务实例。
如前所述,添加额外的实例立即为云原生应用程序提供了一种有效且高效的方式来扩展应用程序逻辑并提高性能。为了使整个系统从中受益,数据层也必须具备这种能力。如果数据层成为瓶颈,应用程序的性能和可扩展性可能会受到严重影响。引入共享缓存及其实时可扩展性对于确保应用程序性能非常有用。数据延迟也非常低。缓存层的可扩展性可以通过数据分布和复制来实现。
高可用性微服务模式
通过添加微服务的实例来扩展其规模,确保了服务的可用性和弹性。如果一个微服务实例出现故障,那么同一微服务的另一个实例可以简单地站出来替换失败的实例,从而通过这类技术解决方案确保业务连续性。根据不断变化的容量需求,可以随意添加或删除微服务实例。通过在每个不同的容器/虚拟机/裸机服务器上运行每个实例,可以确保更高的可用性。容错性是云时代另一个属性,这可以通过在云中心内的不同服务器或地理上分布的云服务器上运行每个实例来实现。共享数据缓存应该提供类似的容错性,以应对服务器故障或站点中断。
高可用性和容错性要求对于服务有益于企业级业务应用至关重要。与 Docker 容器结合的微服务可以通过在紧急和紧迫的情况下自动添加微服务的额外实例来满足水平扩展的需求。也就是说,服务集群和网格的形成是数字世界的关键区别。谷歌每天调整数百万个容器,以保持其对消费者、客户和客户的业务承诺。服务器故障被积极识别和解决,以确保业务连续性。微服务的可靠性和弹性在其采用和适应中起着重要作用。
如果运行微服务的服务器出现故障,系统会自动将工作重定向到微服务的备用实例,启动一个新的实例以恢复容量,并从新实例提供相同的数据访问。这种恢复场景对如何为适应各种类型的故障设置数据层有多个影响。
数据模式并发请求
运行多个应用程序实例将对共享缓存层产生重大影响,因为将会有更多并发请求来获取数据。因此,根据需要添加实例来加强共享缓存层也是必要的。也就是说,缓存层也必须具备弹性能力,以满足额外的请求。
事件存储模式
解决方案的关键组件是一个事件存储库。事件存储系统是不可变的、顺序的,并且是每个服务事件流的目的地。这些事件的消费者可以订阅并读取感兴趣的事件。事件存储本质上为每个消费者提供了事件源。消费者维护自己的逻辑,以确定事件是否感兴趣。每个消费者还维护自己的指针/偏移量,以顺序处理事件存储库中的事件。
事件可以从应用层或直接从数据层生成。从应用层生成事件可以提供对事件流的可见性和控制,但这也意味着必须管理和维护所有生产者和消费者之间的事件流。如果事件来自数据层,则可以解放应用层和开发者,使他们不必在应用中构建事件驱动系统的关键部分。
事件流和统一事件日志模式
统一事件日志是所有参与微服务中发生的所有事件(状态变化、阈值突破或任何值得注意的偏差、不足、干扰等)的收集点/仓库。每个参与服务也可以选择保留其自身状态变化的本地日志。然而,将所有类型的事件日志收集和存储在单个统一的事件存储库中,可以开辟一系列新的可能性和机会。统一事件日志中呈现的所有事件的完整和 360 度视图可以用于回放选定的事件,并以任何期望的方式创建信息投影。可以在实时事件数据上执行各种数据分析,以提取可操作的见解。可以从事件存储库中轻松推断出微服务的性能/吞吐量、可扩展性、可用性、可审计性、安全性、运营状态等。通过这种集中和整合的事件日志数据,还可以实现微服务的预测性和预防性维护。
在大量可能提供事件流的微服务存在的情况下,一个统一的日志可能对性能和可扩展性有较高的要求。Apache Kafka 的设计旨在追求速度、可扩展性、持久性和大规模并发,加上其只允许写入不可变记录的模式,使其成为统一日志的越来越受欢迎的选择。Kafka 通过分布式和复制的分区来维护消息流。
由于多方面、网络化和嵌入式设备的持续爆炸性增长,生成和捕获的事件数量正在迅速增加。无疑需要有一个高度可扩展的消息平台,能够接收来自不同和分布式源的大量事件。我们都知道,Apache Kafka 消息平台具有接收每秒数百万事件的内禀能力。然后,事件被分区,以满足批处理和实时处理的需求。由于服务架构模式要求智能端点和愚笨管道,Kafka 将满足大多数应用程序和系统集成用例的需求。
异步命令调用模式
将服务原子调用组合成复杂流程通常需要对异步操作进行适当的编排。这些通常是本地集成用例,连接必须交换消息并保证交付的关联微服务。在这个用例中,消息层的需求与事件流火管有显著不同,因为其消息是点对点的(队列而不是主题)。这通常需要保证交付,尽管仍然是异步的,并且是会话式的。这是一个传统的以代理为中心的用例,通过异步通信可靠地连接端点。通信流程通过各方之间交换的原子消息进行,而不是由多个进程处理的事件的持续流。
总结来说,基于微服务的应用的高度分布式特性引发了对如何处理数据层的几个悬而未决的问题。微服务促进了完全隔离和自主性。依赖相关的问题在这里简单地消失了。但在真正分布式环境中,如何找到、连接和聚合多个微服务以产生复合服务是一个挑战。在分布式环境中,性能和安全问题浮现出来,利用强大的和开创性的设计实践、模式和流程来产生下一代现代化应用。内存缓存层为读取和写入数据需求提供快速响应时间:
-
异步更新和事件驱动架构保护团队之间的自主性,并允许高速软件开发
-
服务的架构弹性和可扩展性与数据层的弹性和可扩展性密不可分
-
通过缓存隔离层,可以将遗留系统现代化并带入微服务世界
这是我们数字转型的时代。我们周围的一切都在系统地数字化,以使各种物理、机械、电气和电子系统能够加入主流计算。数字经济和时代正迎面而来。我们需要有竞争力的信息技术、敏捷的开发平台、实践和模式。微服务架构(MSA)是成熟稳定的服务导向架构(SOA)范式的衍生品,正成为开发、部署和交付数字服务和应用程序的前进方向。本章专门编写和制定,旨在讨论风险无忧采用和加速有前景的 MSA 范式的突出和主导模式。模式被认为是任何范式方便和自信使用的一个不可或缺的组成部分。读者将受到启发,制定新的模式,使 MSA 具有渗透力、参与性和普遍性。
摘要
在本章中,我们简要介绍了微服务架构模式,并学习了快速涌现和演变的微服务架构(MSA)的独特性以及相关的架构模式。我们还涵盖了与狂热发展的 MSA 相关的架构和设计模式。
本章节的参考文献和额外资源:
-
azure.microsoft.com/en-us/blog/design-patterns-for-microservices/ -
www.sumologic.com/blog/devops/top-patterns-building-successful-microservices-architecture/ -
content.pivotal.io/blog/messaging-patterns-for-event-driven-microservices -
blogs.oracle.com/developers/getting-started-with-microservices-part-three
第十章:容器化和可靠应用程序的模式
Docker 启用的容器化范式正在正确轨道上,有望成为一项有影响力和洞察力的技术,随着越来越多的第三方产品和工具供应商带来的关键进步,它正在取得成功。特别是,未来属于具有现成的容器开发、部署、网络和组合技术和工具的容器化云环境。与编排、治理、监控、测量和管理平台(如 Kubernetes、Mesos 等)结合的 Docker 容器将极大地促进建立和维持下一代容器化云环境,这些环境因其提供企业级、基于微服务、事件驱动、面向服务的、云托管、知识丰富、洞察力相关、人工智能赋能、以人为本、运营商级、生产就绪和基础设施感知的应用程序而闻名。除了容器之外,微服务和以微服务为中心的应用程序的概念也具有特殊意义。构建可靠应用程序的基本要求是更快地实现弹性微服务,这些微服务被定位为下一代应用程序的标准和优化构建块和部署单元。本章重点介绍以下主题:
-
容器化模式
-
弹性微服务模式
-
可靠的应用程序模式
简介
毋庸置疑,Docker 是目前信息技术(IT)领域最受欢迎和最强大的技术。在 Docker 生态系统中存在两个主要趋势。首先,开源的 Docker 平台正在不断被赋予更多权利和相关的功能,以便使其成为最典范的 IT 平台,不仅对软件开发者,也对本地和远程 IT 运营团队来说都是如此。第二个趋势是全球各地的 IT 服务和解决方案提供商前所未有的采用 Docker 启发的容器化技术,以向其尊贵的消费者和客户提供越来越多的优质产品。开发全新软件应用的简化、Docker 容器的自动化和加速部署,以及 Docker 容器的极端灵活性,被广泛宣传为其前所未有的成功的关键差异化因素。
我们希望进一步阐明 Docker,并展示为什么它被吹捧为即将到来的数字、理念、API、知识和洞察经济的下一件大事。
容器化的关键驱动因素
Docker 启用容器化的首要驱动因素是有效地完全克服虚拟化范式被广泛表达的局限性。实际上,我们已经对经过验证的虚拟化技术和工具进行了相当长一段时间的工作,以实现迫切需要的软件可移植性。也就是说,为了消除软件与硬件之间的抑制性依赖,已经出现了几个意外包括成熟的和稳定的虚拟化范式。虚拟化是一种有益的抽象,它通过在硬件资源和软件组件之间引入额外的间接层来实现。通过这个新引入的抽象层(虚拟机管理程序或虚拟机监控程序(VMM)),任何类型的软件应用程序都可以在任何底层硬件上无缝运行。简而言之,软件可移植性是通过这个中间件层实现的。然而,即使是通过虚拟化技术,广泛发布的可移植性目标也没有完全实现。虚拟机管理程序软件和来自不同供应商的不同数据封装格式阻碍了确保所需的应用程序可移植性。此外,操作系统和应用程序工作负载的分布、版本、版本和修补差异阻碍了工作负载在系统和位置之间的顺畅迁移。
类似地,虚拟化范式还伴随着各种其他缺点。在数据中心和服务器农场中,虚拟化技术通常用于将物理机转换为多个虚拟机(VM),每个虚拟机都有自己的操作系统(OS)。通过通过自动化工具和受控资源共享实现的这种坚实和合理的隔离,可以在物理机上容纳多个和异构的应用程序。也就是说,硬件辅助的虚拟化使得不同的应用程序可以在单个物理服务器上同时运行。在虚拟化范式下,各种 IT 基础设施(服务器机器、存储设备、网络解决方案)变得开放、可编程、可远程监控、可管理和可维护。然而,由于冗长和臃肿(每个虚拟机都携带自己的操作系统),虚拟机的配置通常需要几分钟。这对实时和按需可扩展性是一个很大的障碍。
另一个被广泛表达的缺点是与虚拟化紧密相关,那就是由于过度使用宝贵的昂贵 IT 资源(处理能力、内存、存储、网络带宽等),虚拟化系统的性能也会下降。由于从客户操作系统、虚拟机管理程序到底层硬件的多层结构,虚拟机的执行时间较高。
最后,计算虚拟化已经蓬勃发展,而其他与之紧密相关的网络和存储虚拟化概念才刚刚起步。确切地说,构建分布式应用程序和满足不断变化的企业期望需要更快和更灵活的资源分配、高可用性、可靠性、可扩展性和灵活性。计算、存储和网络组件需要协同工作以满足各种 IT 和业务需求。在 IT 环境中,随着虚拟化元素和实体的增加,运营复杂性必然会迅速增长。
转向容器化的世界;所有先前的障碍都一扫而空。也就是说,不断发展的应用程序容器化概念冷静而自信地贡献于软件可移植性目标的空前成功。容器通常包含一个应用程序/服务/进程。除了主要应用程序外,所有相关的库、二进制文件、文件和其他依赖项都被打包并压缩在一起,形成一个全面而紧凑的容器。应用程序容器可以轻松地在任何本地和远程环境中运输、运行和管理。容器异常轻量级,高度便携,快速部署,可扩展,水平可扩展,等等。此外,许多行业领导者聚集在一起,形成了一种联盟,开始了一次决定性和灵巧的系统化生产、包装和交付行业级和标准化容器的旅程。
这种有意识和集体的转变使得 Docker 深入且广泛地渗透。开源社区同时通过一系列协调活动领导着容器化难题,旨在简化并精炼容器化概念。容器化生命周期步骤正在通过各种第三方工具实现自动化。
为了在 IT 环境中尽可能实现自动化,Docker 生态系统也在快速发展。容器集群和编排正在受到越来越多的关注,因此地理上分布的容器及其集群可以迅速连接起来,产生更大、更好的过程感知和复合容器。容器化的新概念有助于分布式计算。容器能够形成联邦云环境,以实现特定的业务目标。云服务提供商和企业 IT 环境都准备好拥抱这种独特的分区技术,以提高资源利用率,并将基础设施优化提升到新的水平。在性能方面,有足够的测试表明 Docker 容器达到了裸金属服务器的性能。简而言之,通过 DevOps 方面的智能利用 Docker 功能容器,确保了 IT 的敏捷性,这反过来又导致了商业的敏捷性、适应性和可负担性。
Docker 容器的设计模式
带有 Docker 功能的容器化正在迅速兴起和演变。随着容器生命周期管理的复杂性不断升级,对启用模式的需要正在感受到。相关的专业人士和评论家正在齐心协力制定和巩固各种特定于容器的模式。在未来的日子里,我们将遇到更多模式。本节和即将到来的各节中,将简洁地呈现广泛阐述和接受的内容。
随着在云环境中(公共、私有和雾/边缘)Docker 功能容器的无与伦比的激增,Docker 爱好者、传教士和专家有意识地提出了一系列启用模式。读者们可以在本节中找到它们。让我们从容器构建模式开始。构建 Docker 镜像和容器受到许多挑战和问题的限制。Docker 模式需要达到一个稳定的水平。
容器构建模式
本节描述了构建 Docker 镜像的一些常见方法。根据 Alex Collins (alexecollins.com/developing-with-docker-building-patterns/) 的说法,有几种选择:scratch + binary、language stack 和 distribution+ package manager。scratch + binary - scratch 是最基本的基础镜像,它根本不包含任何文件或程序。我们必须构建一个 独立二进制应用程序 来使用它。以下是一个示例。首先,我们将使用 Docker 构建一个独立二进制应用程序。步骤如下:
- 创建一个空目录,然后创建一个
main.go应用程序:
package main
import "fmt"
// this is a comment
func main() {
fmt.Println("Hello World")
}
- 编译应用程序:
docker run --rm -ti -v $(pwd):/go/src/myapp google/golang go build myapp
- 为应用程序创建一个 Dockerfile:
FROM scratchADD myapp /CMD ["myapp"]
- 最后,构建并运行镜像:
docker build -t myapp:1 .docker run --rm -ti myapp:1
这将在终端中输出 Hello World。
这适用于可以打包为独立二进制文件的应用程序。因为没有语言运行时,较大的应用程序必然需要更多的磁盘空间。
Docker 为常见语言提供了许多预构建的运行时基础镜像。以下是一个示例:
- 创建一个新的空目录并详细说明
Main.java应用程序:
public class Main { public static void main(String[] args) { System.out.println("Hello World"); }}
- 现在,使用Java 开发工具包(JDK)编译此应用程序:
docker run --rm -ti -v $(pwd):/myapp -w /myapp java:8-jdk javac Main.java
- 使用Java 运行环境(JRE)创建以下 Dockerfile:
FROM java:8-jreADD Main.class /CMD ["java", "-cp", "/", "Main"]
- 最后,构建并运行此 Docker 镜像:
docker build -t myapp:1 .docker run --rm -it myapp:1
下载基础镜像后部署此应用程序会更快,如果许多其他应用程序使用相同的基镜像,那么所需的额外层非常小。
要构建一个不在支持的语言堆栈上的镜像,需要从一个发行版开始创建自己的镜像,然后就是使用包管理器添加必需的依赖项。Linux 总是包含一个包管理器。
这条注释安装了 JRE:
FROM ubuntu:15.10 RUN apt-get update && apt-get install --no-install-recommends -y openjdk-8-jre ADD Main.class / CMD ["java", "-cp", "/", "Main"]
现在,构建并运行此基础镜像:
docker build -t myapp:1 .docker run --rm -it myapp:1
优点是我们可以构建一个应用程序,并且有可能将多个应用程序放入单个镜像中(使用systemd)。
Docker 镜像构建模式
如我们所知,Docker 容器是优化和有机封装复杂构建过程的绝佳方式。通常,任何软件包都需要大量的依赖项。正如第九章《微服务架构模式》中所述,每个微服务都是作为一个 Docker 镜像开发和交付的。每个微服务都有自己的代码仓库(GitHub)和自己的 CI 构建任务。微服务可以使用任何编程语言进行编码。让我们在这里关注 Java 语言。如果一个服务是使用编译语言(Java、Go 等)构建和运行的,那么构建环境可以与运行环境分离。Java 服务的Dockerfile.build来自openjdk-7-jdk目录,其Dockerfile来自openjdk-7-jre目录,这个目录比 JDK 小得多。
对于 Java 编程语言,在它的微服务成为可执行之前需要额外的工具和流程。然而,当编译程序运行时,不需要 JDK。另一个原因是与Java 运行环境(JRE)相比,JDK 是一个更大的包。此外,开发和重用可重复的过程和统一的环境来部署微服务似乎是一种远见。因此,将 Java 工具和包打包到容器中至关重要。这种设置允许在任何机器上构建基于 Java 的微服务,包括 CI 服务器,而无需任何特定的环境要求,如 JDK 版本、分析测试工具、操作系统、Maven、环境变量等。
因此,对于每个服务,都有两个 Dockerfile:一个用于服务运行时,另一个包含构建服务所需的所有工具。首先,重点是制作Dockerfile.build文件,它可以加快 Maven 构建速度。现在,在任意机器(本地或远程)上编译和运行微服务变得非常简单。这种分离的方法在很大程度上简化了持续集成(CI)过程。
配方如下:
-
构建文件:拥有一个包含构建任何服务所需的所有工具和包的 Dockerfile。将其命名为
Dockerfile.build。 -
运行文件:拥有一个包含运行服务所需所有包的另一个 Dockerfile。将这两个文件以及服务代码一起保留。
-
构建一个新的构建器镜像,从它创建一个容器,并使用卷或
docker cp命令提取构建工件。 -
构建服务镜像。
因此,将构建过程与运行过程分离对于容器化范式的预期成功非常有利。一方面是执行构建,另一方面是在第一个镜像中不包含构建链和工具的情况下,将第一个构建的结果交付出去。Terra Nullius 在blog.terranillius.com/post/docker_builder_pattern/上发布了相关细节。构建器模式描述了开发人员必须遵循的构建容器的设置。它通常涉及两个 Docker 镜像:
-
一个安装了所有构建工具的构建镜像,能够创建生产就绪的应用程序文件
-
一个能够运行应用程序的服务镜像
构建器模式背后的基本思想很简单:创建包含所需工具(编译器、链接器和测试工具)的额外 Docker 镜像,并使用这些镜像生成精简、安全和生产就绪的 Docker 镜像。
多阶段镜像构建模式
最新版本的 Docker 发布版简化了创建单个 Dockerfile 的过程,该 Dockerfile 可以构建多个辅助镜像,包括编译器、工具和测试,并使用镜像中的文件来生成最终的 Docker 镜像,这在下文中有生动的说明。
Docker 平台可以通过读取 Dockerfile 中的指令来构建 Docker 镜像。Dockerfile 是一个包含构建新 Docker 镜像所需所有命令的文本文件。Dockerfile 的语法和核心原则非常简单直接,如下所示:
1 Dockerfile -> 1 Docker Image
也就是说,每个 Dockerfile 都创建一个 Docker 镜像。这个原则对于基本用例来说效果很好,但为了创建高级、安全和精简的 Docker 镜像,一个单独的 Dockerfile 就远远不够了。
多阶段构建是最新 Docker 版本中引入的新特性,这对于那些在保持 Dockerfile 易读和易于维护的同时努力优化 Dockerfile 的人来说非常有趣。构建 Docker 镜像时最大的挑战之一是保持镜像大小。Dockerfile 中的每条指令都会向镜像中添加一层。软件工程师必须在进入下一层之前清理掉所有不需要的工件。为了编写一个真正高效的 Dockerfile,他传统上需要使用 shell 技巧和其他逻辑来尽可能保持层尽可能瘦和轻,并确保每一层都从上一层获取所需的工件,而没有任何其他东西。
通常情况下,人们会为开发使用一个 Dockerfile,为生产使用一个精简版的 Dockerfile。维护两个 Dockerfile 并非理想的做法。使用多阶段构建,他可以在 Dockerfile 中使用多个 FROM 指令。每个 FROM 指令可以使用不同的基础镜像,并且每个都开始构建的新阶段。他可以选择性地将工件从一个阶段复制到另一个阶段,留下最终镜像中不需要的所有内容。最终结果是和之前一样的微小生产镜像,但复杂度显著降低。
容器之间文件共享的模式
Docker 是一种流行的容器化工具,用于打包和提供包含所需运行文件系统的软件应用程序。Docker 容器是短暂的,因为它们可以运行直到容器中发出的命令完成。有时应用程序需要访问数据、共享数据或在容器删除后进行数据持久化。通常,Docker 镜像不适合数据库;网站的用户生成内容和应用程序必须访问以进行必要处理日志文件。Docker 卷提供了所需的数据持久访问。在某个时候,生产就绪的应用程序文件需要从构建容器复制到主机机器。有两种方法可以实现这一点:
-
使用
docker cp -
使用
bind-mount volumes
Matthias Noback (matthiasnoback.nl/2017/04/docker-build-patterns/) 为这两者都提供了描述,并附带了易于理解的示例。
使用 bind-mount volumes
将编译步骤作为容器构建过程的一部分并不好。普遍的期望是 Docker 镜像需要高度可重用。如果源代码被修改,那么需要重新构建构建镜像,但人们希望再次运行相同的构建镜像。
因此,编译步骤必须移动到 ENTRYPOINT (docs.docker.com/engine/reference/builder/#entrypoint) 或 CMD 指令。源文件不应该作为构建上下文的一部分,而应该作为 bind-mount 卷挂载到正在运行的 build 容器内部。
这里有很多优势。每次运行 build 容器时,它都会编译 /project/source/ 中的文件,并在 /project/target/ 产生一个新的可执行文件。由于 /project 是一个绑定挂载卷,可执行文件会自动在主机机器上的 target/ 目录中可用。无需显式地从容器中复制它。一旦应用程序文件在主机机器上,就很容易将它们复制到服务镜像中,因为可以使用常规的 COPY 指令来完成此操作。
管道和过滤器模式
需要一个应用程序来对其接收到的信息执行各种不同复杂度的任务。一个单体模块可以做到这一点,但存在一些不灵活性。假设一个应用程序从两个来源接收并处理数据。每个来源的数据都由一个单独的模块处理,该模块执行一系列任务以转换这些数据,然后将结果传递给应用程序的业务逻辑。每个模块执行的处理任务或每个任务的部署要求可能会变化。一些任务可能是计算密集型的,可能需要运行在强大的硬件上,而其他任务可能不需要这样昂贵的资源。此外,未来可能需要额外的处理,或者处理任务执行的顺序可能会改变。
可行的解决方案是将每个数据流所需的处理分解成一系列单独的组件(或过滤器),每个组件执行单一任务。通过标准化每个组件接收和发送的数据格式,这些过滤器可以组合成一个管道。这有助于避免代码重复,并在处理需求发生变化时,便于移除、替换或集成额外的组件。
处理单个请求所需的时间取决于管道中最慢的过滤器的速度。一个或多个过滤器可能成为瓶颈,特别是如果来自特定数据源的请求流中出现大量请求时。管道结构的优势之一是它提供了运行慢速过滤器并行实例的机会,从而使系统能够分散负载并提高吞吐量。
构成管道的过滤器可以在不同的机器上运行,这使得它们可以独立扩展并利用许多云环境提供的弹性。计算密集型的过滤器可以在高性能硬件上运行,而其他要求较低的过滤器可以托管在成本较低的通用硬件上。
如果一个过滤器的输入和输出都结构化为流,那么可以并行地对每个过滤器进行处理。管道中的第一个过滤器可以开始工作并输出其结果,这些结果在第一个过滤器完成其工作之前直接传递给序列中的下一个过滤器。如果一个过滤器失败或运行它的机器不再可用,管道可以重新安排该过滤器正在执行的工作,并将这项工作指向该组件的另一个实例。
通过结合使用经过验证的管道和过滤器模式以及补偿事务模式,可以采用一种替代方法来实现复杂的分布式事务。分布式事务可以被分解为单独且可补偿的任务,每个任务都可以通过使用也实现了补偿事务模式的过滤器来实现。管道中的过滤器可以实施为在它们维护的数据附近运行的独立托管任务,从而出现新的可能性。
对于容器世界来说,前面的模式是有益的。也就是说,为了将生成的文件从容器中取出,利用前面的管道和过滤器模式将文件流式传输到stdout被视为一个有趣的解决方案。这种流式传输也有许多优点:
-
数据不再需要最终存储在文件中,因为它可以保持在内存中。这提供了对数据的更快访问。
-
使用
stdout允许通过管道操作符(|)直接将输出发送到其他进程。其他进程可以修改输出,然后执行相同操作,或者将最终结果存储在文件中。 -
文件的确切位置变得无关紧要。如果我们只使用
stdin和stdout,则不会通过文件系统进行耦合。构建容器不需要将其文件放在/target中,构建脚本也不需要查找/target,它们只需传递数据。
容器化应用程序 - 自动驾驶模式
部署容器化应用程序并将它们连接起来是一个明确的挑战,因为通常,云原生应用程序由数百个微服务组成。微服务架构为组织提供了一个管理开发过程日益增长的复杂性的工具,而应用程序容器提供了一种管理依赖关系的新方法,以加速微服务的部署。但是,部署和连接这些服务仍然是一个挑战。
将基于微服务应用程序投入运营会带来一些挑战。开发人员必须在内部嵌入一些东西以简化部署和交付。自动导航应用程序是解决这些问题的强大设计模式。自动导航模式在代码中自动化了应用程序重复且乏味的操作任务,包括启动、关闭、扩展以及从预期的故障条件中恢复,以提高可靠性、易用性和生产效率。通过将独特的责任和操作任务嵌入到应用程序中,运维团队成员的工作量必然会有所减少。
自动导航模式面向开发人员和运维人员。它是为了让运维人员的生活变得有序,以及为了让开发人员使他们的应用程序易于使用。它主要用于微服务应用程序和多层应用程序。最重要的是,它旨在与我们的应用程序在开发和运营的所有阶段共存和成长。
自动导航模式自动化了应用程序每个组件的生命周期。任何应用程序都可以有多个组件。Web 和应用服务器、数据库服务器、内存缓存、反向代理等,是任何应用程序最突出的组件。这些组件中的每一个都可以容器化,每个为应用程序贡献的容器都有自己的生命周期。大多数自动导航模式实现都采用单用途或单服务容器。自动导航模式确实要求开发人员和运维人员思考在组件生命周期的关键点如何操作应用程序。该独特模式的作者在 autopilotpattern.io/ 提供了一些有效的问题,这些问题在设计自动导航模式时非常有用。
一些应用正在出现,其中至少包含了一些内置的逻辑。Traefik 是一个代理服务器,它使用 Consul 或其他服务目录来自动发现其后端。Traefik 在这些服务目录中不会自我注册,以便其他应用可以使用它。ContainerPilot 是一个用 Golang 编写的辅助工具,它位于容器内部,可以帮助完成这项工作。
ContainerPilot 为微服务架构提供应用程序编排、依赖管理、健康检查、错误处理、生命周期管理和有状态服务的线性及非线性扩展。此外,它提供了一个设计用于容器内部的私有 init 系统。它充当进程管理器,回收僵尸进程,运行健康检查,在服务目录中注册应用程序,监视服务目录的变化,并在容器生命周期的相关事件中运行用户指定的代码,以确保一切正常工作。ContainerPilot 使用 Consul 在应用程序容器之间协调全局状态。
使用一个小型配置文件,ContainerPilot 可以在容器内部触发事件,从而自动化对这些事件的操作,包括 preStart(之前称为 onStart)、health、onChange、preStop 和 postStop。
这里是一个示例场景(读者可以在 autopilotpattern.io/example 找到详细信息)。本例的作者从两个服务开始,即销售和客户服务。Nginx 作为反向代理。对 /customers/ 的请求会转发到客户服务,对 /sales/ 的请求会转发到销售服务。销售服务需要从客户服务获取一些数据来处理其请求,反之亦然。这里有几个关键问题。配置是静态的。这阻止了添加新实例,并使得处理失败的实例变得更加困难。通过配置管理工具配置此堆栈意味着将新的依赖项打包到该应用程序中,但静态配置意味着每次添加新实例时都需要重新部署大多数容器。需要一个机制让应用程序能够自我组装和自我管理日常任务,因此 autopilot 模式越来越受欢迎。
启用 autopilot!这个 autopilot 设计模式的作者为客户服务推出了适当的 Dockerfile。这是一个监听端口 4000 的小型 Node.js 应用程序。他使用 Consul 进行服务发现,每个服务都会向 Consul 发送 TTL 心跳。所有节点都知道所有其他节点,因此不需要使用外部代理或负载均衡器来在节点之间进行通信。图表生动地展示了所有内容。
然而,需要让每个服务都意识到 Consul 的存在。为此,作者使用了 ContainerPilot。源代码和其他实现细节可以在 github.com/autopilotpattern/workshop 找到。
根据 autopilot 模式实现了可重用的 Nginx 基础镜像,用于自动发现和配置。目标是创建一个可以在不同环境中重用的 Nginx 镜像,而无需重建整个镜像。Nginx 的配置完全通过 ContainerPilot 作业和 watch 处理器进行,这些处理器通过 consul-template 更新磁盘上的 Nginx 配置。相关细节可以在 github.com/autopilotpattern/nginx 找到。类似地,还有其他流行应用程序(如 WordPress)的 autopilot 实现。将大量自动化引入各种基于微服务的软件应用程序正在获得很大的动力。
如前所述,许多手动任务正在不同层次和级别上实现自动化,特别是某些关键的自动化需求越来越多地在应用层实现。随着 Docker 平台的快速成熟和稳定,Docker 容器正在迅速扩展其翅膀。随着容器管理软件解决方案的广泛可用,基于微服务应用程序正在获得大量的市场份额和心智份额。此外,还有一些服务网格框架,因此弹性微服务和可靠应用程序的日子并不遥远。越来越多的自动化能力被附加到这些应用程序上,这种进步使得应用程序能够表现出适应性。现在,自动驾驶模式在添加额外的自动化功能和设施方面发挥着关键作用。
容器 - 持久化存储模式
通常,容器空间起源于非永久存储数据的应用程序容器。也就是说,当容器崩溃时,存储或缓存在容器中的数据会丢失。然而,出于几个原因,包括实现有状态应用程序,数据持久性方面被强调,因此正在开发新的机制以确保在容器中安全地持久化数据。因此,为了持久化数据,引入了额外的容器类型,例如数据或卷容器。
持久化存储的上下文
广泛表达的一个担忧是,容器非常适合无状态应用程序,但并不适合持久化数据的具有状态的应用程序。因此,持久化存储模式在容器世界中获得了特殊的重要性。以下段落简要介绍了无状态和有状态应用程序。
随机数生成器是无状态的,因为我们每次运行它都会得到不同的值。我们可以轻松地将其 Docker 化,如果实例失败,我们可以在另一个主机上瞬间启动它以继续服务,而不会出现任何中断和延迟。在新主机上,实例的行为也保持不变。然而,我们的银行账户并非如此。如果银行账户应用程序需要在新的服务器上重新部署,它必须具有来自第一个服务器实例的原始数据。
这是一个有状态的数据分类。通常,配置数据,包括密钥和其他秘密,经常被写入各种文件中。在配置实例时,这些数据很容易恢复。用户生成的内容包括文本、视频或银行交易。存在动态配置细节。合适的例子是服务 A 和 B 之间的连接。将应用程序/服务连接到其后端数据库系统是另一个突出的例子。通常,应用程序/服务将这种发现和连接视为配置数据,以及其他配置细节。为了使应用程序可扩展和具有弹性,在应用程序运行时更新此配置信息是必要的。也就是说,当我们添加或删除服务的实例时,我们必须更新所有连接到该服务的其他服务实例。否则,预期的性能提升就不会发生。其他相关的配置细节可能包括性能调整参数。这些配置细节可以存储在应用程序仓库中,以方便应用程序/服务版本控制和更容易的跟踪。配置信息的另一种选择是利用动态存储,这样它们可以在不重新构建和重新部署应用程序的情况下进行更改。使用像 git2consul 这样的工具自动复制仓库内容到配置存储也是可能的。最佳实践是将配置数据和模板保存在一致的分布式键/值数据存储中。
持久性存储选项
容器旨在是短暂的,因此对于无状态应用程序来说,扩展得相当好。然而,有状态容器需要被不同对待。对于有状态应用程序,容器概念要正确且相关,必须存在持久性存储机制。容器可以在没有数据持久性的情况下开发和拆卸。数据位于容器内。如果发生任何变化,则数据会丢失。对于某些情况,这种数据丢失不是一个大问题。对于某些场景,数据丢失是不被接受的;必须存在数据持久性功能。Docker 提供的解决方案在下一节中给出。
在容器的可写层中存储数据是可能的,但有一些缺点:
-
当该容器不再运行时,数据不会持久化,如果另一个进程需要这些数据,从容器中获取数据可能会很困难。
-
容器的可写层与容器运行的宿主机紧密耦合。将数据移动到其他地方是一件困难的事情。
-
向容器的可写层写入需要存储驱动来管理文件系统。存储驱动通过使用 Linux 内核提供联合文件系统。这种额外的抽象与使用直接写入宿主机文件系统的数据卷相比会降低性能。
Docker 提供了三种不同的方式将数据从 Docker 宿主机挂载到容器中:卷、绑定挂载或tmpfs挂载。卷几乎总是正确的选择。卷是用于持久化由 Docker 容器生成和使用的数据的首选机制。虽然绑定挂载依赖于宿主机的目录结构,但卷完全由 Docker 管理。卷相对于绑定挂载有以下几个优点:
-
卷比绑定挂载更容易备份或迁移
-
使用 Docker CLI 命令或 Docker API,卷易于管理
-
卷可以在 Linux 和 Windows 容器上工作
-
卷可以在多个容器之间更安全地共享
-
卷驱动允许在远程主机或云提供商上存储卷,加密卷的内容,或添加其他功能
-
新卷的内容可以被容器预先填充
卷通常比在容器的可写层持久化数据是一个更好的选择,因为使用卷不会增加使用它的容器的尺寸,并且卷的内容存在于特定容器的生命周期之外。
如果容器生成非持久状态数据,那么考虑使用tmpfs挂载来避免永久存储数据,并通过避免写入容器的可写层来提高容器的性能。
所有三种选项如下所述:
-
卷存储在宿主机文件系统中由 Docker 管理的部分(在 Linux 上为
/var/lib/docker/volumes/)。非 Docker 进程不能修改文件系统的这部分。 -
绑定挂载可以存储在宿主系统的任何位置。它们甚至可能是重要的系统文件或目录。Docker 宿主机上的非 Docker 进程或 Docker 容器可以在任何时间修改它们。
-
tmpfs挂载仅存储在宿主系统的内存中,并且永远不会写入宿主系统的文件系统。
让我们更深入地讨论它们。
卷
我们可以使用docker volume create命令显式创建卷,或者 Docker 可以在创建容器或服务时创建卷。当我们创建卷时,它存储在 Docker 宿主机上的一个目录中。当我们将卷挂载到容器中时,这就是挂载到容器上的目录。这与绑定挂载的工作方式类似,只是卷由 Docker 管理,并且与宿主机的核心功能隔离。
某个卷可以同时挂载到多个容器中。当没有正在运行的容器使用卷时,该卷仍然对 Docker 可用,并且不会自动删除。您可以使用 docker volume prune 命令删除未使用的卷。卷还支持使用 volume drivers,这允许在远程主机、云提供商等地方存储数据。
绑定挂载
当我们使用绑定挂载时,主机机器上的文件或目录会被挂载到容器中。文件或目录通过主机机器上的完整路径进行引用。文件或目录不需要在 Docker 主机上已经存在,并且可以在需要时创建。绑定挂载性能非常好,但它们依赖于主机机器的文件系统具有特定的目录结构。无法使用 Docker CLI 命令直接管理绑定挂载。
tmpfs 挂载
tmpfs 挂载在 Docker 主机或容器内部都不会持久化到磁盘。它可以在容器生命周期内被容器使用,以存储非持久状态或敏感信息。例如,内部,swarm 服务使用 tmpfs 挂载将秘密挂载到服务的容器中。
Docker Compose 配置模式
我们越来越频繁地听到、阅读,甚至体验到多容器应用。也就是说,复合应用是通过多容器组合来实现的。这种组合技术由于两个关键趋势而具有特殊意义。首先,强大的微服务概念正在逐渐改变 IT 行业。也就是说,大型单体服务正在逐渐让位于小型和自主的微服务集群。不同的分布式微服务正在被发现、检查并连接在一起,以创建和运行业务级、生产就绪、流程感知、任务关键、企业级复合应用。第二是 Docker 容器化不仅改变了服务的架构,也改变了创建它们的环境的结构。现在,软件被系统地容器化、存储和分发,开发者获得了选择首选应用程序的完全自由。结果,即使是像 持续集成 (CI) 服务器这样的复杂环境,带有数据库后端系统和分析基础设施,也可以在几秒钟内实例化。简而言之,软件开发、部署和交付变得更加容易和快速。
Docker Compose 是一个用于定义和运行复杂应用的 Docker 工具。使用 Compose,可以在单个文件中定义一个多容器应用,然后通过一个命令启动应用,该命令会完成所有必要的操作以使其运行。使用 Compose 基本上是一个三步过程:
-
使用 Dockerfile 定义您应用程序的环境,以便它可以在任何地方重现
-
在
docker-compose.yml中定义构成应用程序的服务,以便它们可以在隔离环境中一起运行 -
最后,运行
docker-compose up,Compose 将启动并运行整个应用程序
我们可以通过 Docker Compose 传递环境变量,以实现一次创建容器镜像并在任何环境中(开发、测试和生产)重用。采用这种方法,可以开发以 Compose 为中心的容器,这些容器需要一些配置管理来处理基于环境变量值的启动前事件。该模式的作者详细介绍了源代码在github.com/jay-johnson/docker-schema-prototyping-with-mysql。
作者构建了这个项目,用于使用 MySQL Docker 容器快速原型设计数据库模式,该容器部署自己的 ORM 模式文件并在启动时填充初始记录。通过设置几个环境变量,我们可以为我们自己的 Docker 容器提供一个可用的 MySQL 实例、浏览器就绪的 phpMyAdmin 服务器以及我们的数据库,包括表,初始化成我们想要的样子。有兴趣的读者请访问前面的页面,以获取有关这种独特模式的更详细信息。
Docker 容器反模式
我们在上一节中讨论了大多数可用的容器特定模式。许多 Docker 容器化的倡导者和专家基于他们在开发、部署和交付容器化服务和应用程序方面的丰富经验,引入了一些反模式。本节专门用于传达 Docker 实践者发现和传播的反模式。
随着开源和商业级工具的随时可用,容器创建和部署正变得越来越容易和快速。DevOps 团队成员应该学习一些技术和技巧,以避免在迁移到 Docker 时犯错误。
在 Docker 容器内安装操作系统
使用 Docker 在容器内托管整个操作系统很少有一个合理的理由。有平台可以生成和运行系统容器。Docker 平台专门设计和微调,用于生成应用程序容器。也就是说,应用程序及其运行时依赖项被组合在一起,打包并传输到目的地。
选择优化的 Docker 镜像
当构建容器镜像时,我们应该只包含容器将要托管的应用程序绝对必需的服务。任何额外的服务都会浪费资源并扩大潜在的攻击向量,最终可能导致安全问题。例如,在容器内运行 SSH 服务器是不好的,因为我们可以使用 Docker 的exec调用来与容器化应用程序交互。相关的建议是创建一个新的目录,并将 Dockerfile 和其他相关文件包含在该目录中。还应该考虑在创建镜像之前使用.dockerignore来删除任何日志、源代码等。此外,养成在解压后删除任何下载的工件的习惯。
在开发、测试、预生产和生产环境中使用不同的镜像或甚至不同的标签是不正确的。作为真相来源的镜像应该一次性创建并推送到仓库。该镜像应继续用于不同的环境。任何系统集成测试都应该在将要推送到生产的镜像上进行。
由 Docker 镜像生成的容器应尽可能短暂。这里的“短暂”是指它可以被停止和销毁,并且可以以绝对最小的设置和配置来构建和部署新的容器。
最佳实践是不在容器中保留关键数据。有两个主要原因。当容器意外或故意崩溃时,容器内的数据会立即丢失。第二个原因是容器的安全性不如虚拟机,因此将机密、关键、客户和公司信息存储在容器中并不是一个好的发展方向。对于持久化数据,有可用的机制。流行的 ELK 堆栈可以用来存储和处理日志。如果在早期测试过程中使用了管理卷,那么建议使用docker rm命令的-v开关来删除它们。
此外,不要在 Dockerfile 中存储任何安全凭证。它们是明文形式,这使得它们完全易受攻击。不要忘记使用-e来指定密码作为运行时环境变量。或者,可以使用--env-file从文件中读取环境变量。此外,选择CMD或ENTRYPOINT来指定脚本,该脚本将从第三方获取凭证然后配置应用程序。
仅在容器注册表中存储容器镜像
容器注册表专为托管容器镜像而设计。将注册表用作通用存储库来托管其他类型的数据是不合适的。
仅在容器内托管一个服务
在微服务世界中,应用程序正被划分为一组动态的、交互式、单用途、自主的、API 驱动、易于管理和可组合的服务.*容器成为微服务最佳运行时环境。因此,在容器内有一个服务是合乎逻辑的。因此,为了运行一个应用程序,需要利用多个容器来运行多个服务。例如,一个容器可以安装并使用 MySQL、WordPress,甚至可能还有 phpMyAdmin、nginx 和一个 SSH 守护进程。此外,可以在不同的容器中托管一个服务的多个实例。通过容器实现的冗余能力在确保通过容错、高可用性、水平扩展、独立部署等确保业务连续性方面发挥了重要作用。现在,随着强大的容器编排平台的兴起,分布式和多个容器可以连接起来,形成复合应用程序。容器化的一个优点是在出现安全问题时能够快速重新构建镜像,例如,并快速推出一套全新的容器。而且因为容器是单关注点,所以无需每次都重新部署云基础设施。同样,可以从基础镜像构建多个 Docker 镜像。此外,容器还可以转换为新的镜像。
我们可以在制定 Dockerfile 时使用 CMD 和 ENTRYPOINT 命令。通常,CMD 将使用一个脚本,该脚本将执行一些镜像配置,然后启动容器。最好避免使用该脚本启动多个进程。这将使得管理容器、收集日志和更新每个单独的进程变得困难。也就是说,我们需要在创建 Docker 镜像时遵循关注点分离模式。将应用程序拆分成多个容器并分别管理是未来的发展方向。
最新不代表最佳
在编写 Dockerfile 时,获取每个依赖项的最新版本是非常诱人的。然而,黄金法则是创建具有已知和稳定版本的系统和依赖项的容器,这些系统和依赖项是我们知道我们的软件将能够运行的。
带有 SSH 的 Docker 容器
一种相关且同样不幸的做法是将 SSH 守护进程烘焙到镜像中。在容器内拥有 SSH 守护进程可能导致对容器基础设施的未记录、不可追踪的更改,但 Docker 容器被吹捧为不可变的基础设施。
有几种情况需要 SSH 到容器中:
-
更新操作系统、服务或依赖项
-
Git pull 或以其他方式更新任何应用程序
-
检查日志
-
备份一些文件
-
重启服务
除了使用 SSH 之外,建议使用以下机制:
-
在容器的 Dockerfile 中做出更改,重建镜像,并部署容器。
-
使用环境变量或通过卷共享可访问的配置文件来执行更改并可能重新启动容器。
-
如前所述,使用
docker exec。docker exec命令在运行的容器中启动一个新的命令,因此必须是最后的手段。
容器的 IP 地址
每个容器都会分配一个 IP 地址。在容器化环境中,多个容器必须相互交互以实现业务目标。此外,容器经常被终止,新的容器正在被创建。因此,依赖于容器的 IP 地址来启动容器通信面临着真正的挑战。首选的方法是创建服务。这将提供一个逻辑名称,可以独立于容器数量的增加和减少而被引用。它还提供了基本的负载均衡。
此外,不要使用-p来发布所有暴露的端口。这有助于运行多个容器并发布它们的暴露端口。但这也带来了一定的代价。那就是,所有端口都将被发布,从而带来安全风险。相反,使用-p来发布特定的端口。
Root 用户
这是一个安全缓解技巧。不要以 root 用户身份运行容器。主机和容器共享相同的内核。如果容器被入侵,root 用户可以对底层主机造成更大的损害。相反,创建一个组并在其中创建一个用户。使用用户指令切换到该用户。每个用户在镜像中创建一个新的层。此外,避免来回切换用户以减少层的数量。
容器之间的依赖关系
通常,应用程序依赖于容器以特定顺序启动。例如,数据库容器必须启动,应用程序才能连接到它。应用程序应该对这种变化具有弹性,因为容器可能随时被终止或启动。在这种情况下,让应用程序容器在继续之前等待数据库连接成功。不要在 Dockerfile 中使用wait-for脚本来指定容器的启动顺序。
总之,容器是开发、部署和执行的新颖而强大的单元。业务应用程序、IT 平台、数据库和中间件正式容器化并存储在公开可用的和可访问的镜像存储库中,以便软件开发人员可以挑选并利用它们来满足他们的软件开发需求。系统可移植性是一个关键优势。容器镜像的更容易、更快的机动性、可测试性和可组合性被吹捧为容器化的最有希望和最有潜力的优势。分布式计算的概念极大地简化了分布式计算的必然性。跨集群的多个容器可以轻松连接,以实现智能和复杂的应用程序。
高可靠性应用的模式
IT 系统对于业务自动化是不可或缺的。我们 IT 和业务应用广泛面临的挑战是展示高可靠性。系统应该具有响应性、弹性、可伸缩性和安全性,以内在地展示所需的可靠性。系统越来越多地是多模态和多媒体的。系统必须捕捉、理解和展示适当的行为。此外,系统必须在任何情况下都能随时响应。此外,随着大数据时代的到来,分布式计算已经成为主流的计算模型。在本节中,我们将讨论构建可靠系统的突出模式,以满足专业和个人需求。有希望的方法包括:
-
反应性和认知编程技术
-
弹性微服务
-
容器化云环境
在分布式系统中,由于多个移动部分和参与系统模块之间令人恶心的依赖关系,故障是不可避免的。硬件可能失败,应用程序可能崩溃,网络可能发生瞬态故障。很少,整个服务或区域可能会出现中断。云正在成为一站式 IT 解决方案。
弹性是系统承受和容忍故障以持续运行的能力。即使它失败了,它也有能力反弹回原始状态。确切地说,这关乎的不是避免故障,而是它从故障中恢复的速度有多快,以便在没有中断和减速的情况下提供服务。此外,系统组件中的故障不应级联到其他组件,以使整个系统崩溃。有弹性策略、模式、最佳实践、方法和技术。
高可用性(HA)是应用程序在健康状态下继续运行的能力,没有显著的中断时间。也就是说,应用程序继续响应用户的请求。
灾难恢复(DR)是从罕见但重大的事件中恢复的能力:非瞬态、广泛范围的故障,例如影响整个区域的服务中断。灾难恢复包括数据备份和存档,可能包括手动干预,例如从备份中恢复数据库。
弹性必须设计到系统中,以下是一个通用的模型供参考:
-
定义基于业务需求的应用可用性要求。
-
设计具有弹性的应用程序架构。从一个遵循既定实践和架构决策的架构开始,然后确定该架构中可能出现的故障点。注意处理依赖关系。同时,选择支持弹性的最佳架构模式和风格。
-
开发应用程序时使用适当的设计模式,并纳入检测和从故障中恢复的策略。
-
通过模拟故障和触发强制故障转移来构建和测试实现,并彻底调试识别出的问题。
-
根据需要决定基础设施容量并提供它们。
-
部署 应用程序到生产环境,使用可靠且可重复的过程。
-
监控 应用程序以检测故障。监控活动有助于评估应用程序的健康状况。健康检查在提供即时响应时非常有用。
-
响应 如果发生需要任何手动干预的事件。
弹性实现策略
随着弹性要求的坚持,各个商业企业的 IT 部门正在探索各种方法和手段,以构建和发布弹性应用程序服务。在不同的级别(基础设施、平台、数据库、中间件、网络和应用程序)上,弹性价值正在被强制执行,以便整个系统和环境变得弹性。
在本节中,我们将深入探讨,描述如何努力实现和阐述弹性目标,以了解现实情况。有一些值得注意的故障。其中关键的一些包括以下内容:
-
重试短暂故障:短暂故障可能由许多原因、缺陷和干扰引起。通常,通过重试请求可以简单地解决临时故障。然而,每次重试都会增加总延迟。此外,过多的失败请求可能导致瓶颈,因为挂起的请求在队列中积累。这些阻塞的请求可能持有关键系统资源,如内存、线程、数据库连接等。在这种情况下,一个可行的解决方案是增加每次重试尝试之间的延迟,并限制失败请求的总数。
-
跨实例负载均衡:这是 IT 环境中常见的事情。位于应用程序前面的负载均衡器(LB)实例有助于添加更多应用程序实例,以提高弹性。
-
复制数据:在数据库和文件系统中处理非短暂故障已经是一种标准方法。数据存储技术本身提供内置的复制功能。然而,为了满足高可用性要求,副本正在被制作并放置在地理上分布的位置。因此,如果一个区域发生故障,另一个区域可以处理业务连续性。然而,这显著增加了跨区域复制数据的延迟。通常,考虑到区域之间的长距离,数据复制以异步方式进行。在这种情况下,我们无法期望实时和强一致性。相反,我们需要满足最终一致性。如果副本失败,企业必须容忍潜在的数据丢失。
-
优雅降级:如果一个服务失败且没有故障转移路径,应用程序可能能够在仍然提供可接受的用户体验的同时优雅降级。
-
限制高流量用户:有时,少数用户会创建过度的负载。这可能会对其他用户产生不良影响。应用程序可能会在一定时间内限制高流量用户。限制并不意味着用户正在恶意操作。如果请求数量超过阈值,则开始限制。
弹性测试方法
测试人员必须测试在仅偶尔发生的故障条件下端到端工作负载的表现,有以下两种类型:
-
故障注入测试:这是在故障期间测试系统弹性的方法之一,可以通过触发实际故障或模拟它们来实现。
-
负载测试:有开源和商业级的负载生成工具,通过这些工具进行应用程序的负载测试。负载测试对于识别仅在负载下发生的故障至关重要,例如后端数据库过载或服务限制。使用生产数据或尽可能接近生产数据的合成数据进行峰值负载测试。目标是观察应用程序在真实世界条件下的行为。
弹性部署方法
软件部署是建立和维持弹性重要的一环。在应用程序部署到生产级服务器后,软件更新也可能成为错误源。任何不完整或错误的更新都可能导致系统崩溃。有一些经过验证的部署和更新方法可以避免任何形式的停机。在部署和后续更新之前必须进行适当的检查。部署通常包括提供各种服务器、网络和存储资源,部署经过精选和优化的应用程序代码,以及应用所需的正确配置设置。更新可能涉及所有三个任务或这三个任务的一个子集。因此,建议实施一个辅助工具、自动化和幂等的过程。与弹性部署相关的有两个主要概念:
-
基础设施即代码是使用代码来提供和配置基础设施的实践。基础设施即代码可能使用声明性方法或命令性方法,或者两者的结合。
-
不可变基础设施符合基础设施在生产后不应被干扰或修改的原则。
部署模式
蓝绿部署是一种技术,其中更新被部署到一个与实时应用程序分开的生产环境中。在部署得到验证后,然后切换流量路由到更新版本。
在金丝雀发布的情况下,我们不必将所有流量切换到更新版本,而是可以通过将部分流量路由到新部署来将更新推出给一小部分用户。如果有问题,就退回到旧部署。否则,将更多流量路由到新版本,直到它获得 100%的流量。
无论采用何种方法,都必须确保我们可以在新版本不符合预期的情况下回滚到最后已知的好部署。此外,如果发生错误,应用程序日志必须指出是哪个版本导致了错误。
监控和诊断
对应用程序进行持续和工具辅助的监控对于实现弹性至关重要。如果出现拖沓、滞后或失败的情况,运营团队必须立即被告知,并附带所有正确和相关的细节,以便采取正确的行动。正如我们大家所同意的,监控大规模分布式系统是一个更大的挑战。随着“分而治之”技术的广泛接受,任何企业级应用程序的移动部件数量稳步且急剧增长。今天,作为模块化的一部分,我们已经广泛接受和采用虚拟化和容器化概念。任何 IT 环境中的虚拟机数量都在增长。此外,由于轻量级特性,用于运行任何关键任务应用程序的容器数量也在迅速且显著地增加。简而言之,精确监控裸金属服务器、虚拟机和容器对于运营团队来说确实是一个挑战。此外,各种软件和硬件都会生成大量的日志文件,导致大量运营数据。将各种运营数据用于提取可操作见解已成为一种常见做法。不仅 IT 系统是分布式的,而且它们也非常动态。明天数据中心和服务器农场监控、测量和管理复杂性持续上升。
监控并不等同于故障检测。例如,我们的应用程序可能检测到一个短暂错误并重试,从而避免了停机时间。但同时也应该记录重试操作,以便我们可以监控错误率,从而获得应用程序整体健康状况的全面了解。
弹性策略对于确保 IT 系统和业务应用程序的服务弹性至关重要。随着企业越来越多地采用云模式,云服务提供商正专注于增强其云服务器、存储和网络的可恢复能力。应用程序开发者也在快速学习技巧和技术,以便推出具有弹性的应用程序。结合弹性基础设施、平台和应用程序,实现弹性 IT 的日子,这对于敏捷、动态、高效和适应性强的企业来说是越来越近了。
弹性实现模式
模式始终是挖掘和阐述针对各种重复性问题的高效解决方案的一种流行且无与伦比的机制。我们将探讨一系列有前景且经过验证的设计模式,以实现最重要的目标——弹性。
电路断路器模式
电路断路器模式可以防止应用程序反复尝试可能失败的操作。电路断路器封装了对服务的调用。它可以处理在连接到远程服务或资源时可能需要不同时间恢复的故障。这可以提高应用程序的稳定性和弹性。
问题描述——远程连接在分布式应用程序中很常见。由于网络速度慢、超时、服务不可用或服务负载过重等大量短暂故障,对远程应用程序服务的调用可能会失败。这些故障通常是短暂的,通常在短时间内自行纠正。重试模式策略建议,一个健壮的云应用程序可以轻松处理这些短暂故障,以满足服务请求。
然而,也可能存在故障是由于更大问题的情况。严重程度从暂时性连接丢失到由于各种原因和原因导致的服务完全失败不等。在这里,不断重试建立已损坏的连接是不合逻辑的。相反,应用程序必须理解和接受这种情况,以优雅地处理失败。
假设请求的服务非常繁忙,那么整个系统崩溃的可能性就存在。
通常,调用服务的操作被配置为实施超时,并在服务未能响应指定的时间段内回复失败消息。然而,这种策略可能导致许多并发请求同一操作的请求被阻塞,直到超时期间结束。这些阻塞的请求可能会占用关键系统资源,如内存、线程、数据库连接等。最终,资源可能会耗尽,导致其他相关甚至无关的系统组件失败。其理念是使操作立即失败,并且只有在可能成功的情况下才尝试再次调用服务。这里的要点是智能地设置超时,因为较短的超时可能有助于解决这个问题,但较短的超时可能会使操作大部分时间都失败。
解决方案方法—解决方案是经过验证的断路器模式,它可以防止应用程序反复尝试执行可能失败的操作。这允许它在等待故障修复或确定故障持续时间较长时,不浪费 CPU 周期继续运行。断路器模式还使应用程序能够检测故障是否已解决。如果问题似乎已经修复,应用程序可以尝试调用该操作。
重试模式允许应用程序在预期操作将成功的情况下重试操作。另一方面,断路器模式防止应用程序执行可能失败的操作。应用程序可以通过使用断路器通过重试模式调用操作来结合这两种模式。然而,重试逻辑应该对断路器返回的任何异常高度敏感,如果断路器指示故障不是瞬时的,则应放弃重试尝试。此外,断路器充当可能失败的操作的代理。代理应监控最近发生的失败次数,并使用这些信息来决定是否允许操作继续,或者简单地立即返回异常。代理可以作为一个具有以下状态的状态机实现:
-
关闭状态:这是断路器的原始状态。因此,断路器向服务发送请求,并有一个计数器持续跟踪最近失败的次数。如果在给定的时间段内,失败计数超过阈值水平,则断路器切换到打开状态。
-
打开状态:在此状态下,断路器打开并立即失败所有请求,而不调用服务。应用程序必须使用缓解路径,例如从副本数据库读取数据或简单地向用户返回错误。当断路器切换到打开状态时,它启动一个计时器。当计时器到期时,断路器切换到半开状态。
-
半开状态:在此状态下,断路器允许有限数量的请求通过到服务。如果它们成功,则假定服务已恢复,断路器切换回原始关闭状态。否则,它将恢复到打开状态。半开状态防止恢复中的服务突然被一系列服务请求淹没。
断路器模式确保系统在从故障中缓慢而稳定地恢复的同时保持系统稳定性,并最小化对系统性能的影响。它可以通过快速拒绝可能失败的操作的请求,而不是等待操作超时,来帮助保持系统的响应时间。如果断路器每次改变状态时都引发一个事件,则可以使用这些信息来监控由断路器保护的系统部分的健康状况,或者在断路器跳转到开启状态时提醒管理员。
该模式高度可定制,可以根据可能出现的故障类型进行调整。例如,可以将一个增加的超时计时器用于断路器。我们最初可以将断路器置于开启状态几秒钟,如果故障尚未解决,则将超时时间增加到几分钟,依此类推。在某些情况下,与其让开启状态返回一个故障并引发异常,不如返回一个对应用程序有意义的默认值。
总结来说,此模式用于防止应用程序尝试调用远程服务或访问共享资源,如果这种操作高度可能失败。此模式不是:
-
用于处理应用程序中对本地私有资源的访问,例如内存中的数据结构
-
作为处理应用程序业务逻辑中异常的替代方案
断路器模式在微服务中变得越来越常见,成为分割大型应用程序和将应用程序呈现为有组织的微服务集合的最优化方式。
Bulkhead pattern
问题描述——云应用通常由多个相互关联的服务组成。一个服务可以作为服务实例在不同的和分布式的服务上运行。对于每个服务实例,可能有多个消费者请求。当消费者向一个配置错误或未响应的服务发送请求时,客户端请求使用的资源可能无法及时释放。
随着对服务的请求持续不断,这些资源可能很快就会耗尽。占用的资源包括数据库连接。最终结果是,对云应用中其他服务的任何请求都会受到影响。最终,云应用可能无法向消费者提供服务。其他消费者也是如此。简而言之,来自一个客户端的大量请求可能会耗尽服务中的可用资源。这是级联效应,而此模式在克服这一问题中非常有用。
解决方案方法——解决方案是将服务实例智能地分区到不同的组,基于消费者负载和可用性要求。这种设计有助于隔离故障,并允许在故障期间为某些消费者维持服务功能。消费者还可以分区资源,以确保用于调用一个服务的资源不会影响用于调用另一个服务的资源。例如,为不同的服务选择不同的连接池是一个可行的选项。因此,一个连接池的崩溃不会停止其他连接。
这种模式的优点包括以下内容:
-
这隔离了服务消费者和服务,防止级联故障。这种隔离坚决防止整个解决方案崩溃。
-
实例级别的隔离有助于保留服务的其他实例。因此,服务可用性得到保证,同样地,应用程序的其他服务继续执行其分配的功能。
-
这有助于识别消费应用的需求,并相应地允许部署提供不同服务质量(QoS)的服务。也就是说,可以配置一个高优先级的消费者池来使用高优先级的服务。
总结来说,一个子系统的任何类型的故障有时会级联到其他组件,导致系统崩溃。为了避免这种情况,我们需要将系统分区成几个隔离的组,以便一个分区的故障不会渗透到其他分区。容器化与多语言微服务的结合是拥有分区和无忧系统的强大选择。
补偿事务模式
这是一个撤销另一个已完成事务效果的交易。在分布式系统中,实现强事务一致性可能非常困难。补偿事务是通过使用一系列较小且独立的交易来实现一致性的方法,这些交易可以在每个步骤中撤销。
问题描述——典型的业务操作由一系列独立的步骤组成。当这些步骤正在执行时,系统的整体状态视图可能是不一致的,但是当操作完成并且所有步骤都已执行时,系统应该再次变得一致。最终一致性模型中的挑战是如何处理失败的步骤。在这种情况下,可能需要撤销操作中之前步骤完成的所有工作。然而,数据不能简单地回滚,因为其他并发应用程序实例可能已经更改了它。即使在数据没有被并发实例更改的情况下,撤销一个步骤可能不仅仅是恢复原始状态的问题。这要求应用各种特定于业务规则。如果一个实现最终一致性的操作跨越几个异构数据存储,撤销操作中的步骤将需要依次访问每个数据存储。必须在每个数据存储中可靠地撤销执行的工作,以防止系统保持不一致。
在面向服务的架构(SOA)环境中,一个操作可能会在服务中调用一个动作并导致该服务持有的状态发生变化。为了撤销操作,这种状态变化也必须被撤销。这可能涉及到再次调用服务并执行另一个动作,以逆转第一个动作的效果。
解决方案方法——解决方案是实施一个补偿事务。补偿事务中的步骤必须撤销原始操作中步骤的效果。补偿事务可能无法简单地用操作开始时系统的状态替换当前状态,因为这种方法可能会覆盖其他并发应用程序实例所做的更改。相反,它必须是一个智能过程,考虑到任何并发实例完成的工作。这个过程通常将是特定于应用程序的,由原始操作执行的工作的性质驱动。
一种常见的方法是使用工作流来实现需要补偿的最终一致操作。随着原始操作的进行,系统记录有关每个步骤的信息以及该步骤执行的工作如何被撤销。如果在任何点上操作失败,工作流将回滚到已完成的步骤,并执行逆转每个步骤的工作。
建议仅在使用失败时必须撤销的操作中使用此模式。如果可能,设计解决方案以避免需要补偿事务的复杂性。
健康端点监控模式
问题描述——应用程序及其服务需要持续监控,以获得对其可用性和性能水平和模式的牢固把握。与任何本地服务相比,在本地、按需和在线环境中运行的监控服务相当困难。有许多因素会影响云托管应用程序,例如网络延迟、底层计算和存储系统的性能和可用性,以及它们之间的网络带宽。服务可能会完全或部分失败,这可能是由于任何这些因素造成的。因此,我们必须定期验证服务是否正常运行。
解决方案方法——我们需要通过向应用程序的端点发送请求来进行健康监控。应用程序应执行必要的检查,并返回其状态的指示。健康监控检查通常结合两个因素:
-
应用程序或服务在响应健康验证端点请求时执行的分配检查。
-
执行健康验证检查的健康监控工具对结果的分析。
健康监控工具正在检查几个参数和条件,以便完全且简洁地了解应用程序的状态。
从不同的本地或托管位置运行这些检查以测量和比较响应时间也是有用的。由于客户在地理上分布,检查必须从靠近客户的位置启动和实施。
另一点是要公开至少一个应用使用的核心服务的端点,以及另一个用于低优先级服务的端点。这允许为每个监控结果分配不同的重要性级别。同时,考虑公开更多端点,例如为每个核心服务公开一个端点以实现额外的监控粒度也是好的。越来越频繁地,数据库、存储和其他关键服务都在进行健康验证检查。正常运行时间和响应时间决定了应用程序的质量。
这种模式对于检查网站、Web 和移动应用程序以及云托管应用程序的健康状况非常有用。
领导选举模式
问题描述——典型的云应用程序有许多任务以协调的方式工作。这些任务可能都是运行相同代码的实例,需要访问相同的资源,或者它们可能并行工作以执行复杂计算的各个部分。任务实例可能大部分时间都是独立运行的,但有时也可能需要协调每个实例的动作,以确保它们不会冲突,不会对共享资源产生竞争,或者意外地干扰其他任务实例正在进行的工作。
例如,云系统通过扩展或扩展来保证可伸缩性。在扩展(水平扩展)的情况下,可能会有多个相同任务/服务的实例。每个实例服务于不同的用户。如果这些实例写入共享资源,那么协调它们的行动以防止每个实例覆盖其他实例所做的更改是必要的。同样,如果任务正在并行执行复杂计算的各个单独元素,那么结果需要适当汇总以给出最终答案。任务实例都是对等的,因此没有自然领导者可以充当协调器或聚合器。
解决方案方法——应该选举一个单独的任务实例来充当领导者,并且这个实例应该协调其他下属任务实例的行动。如果所有任务实例都在运行相同的代码,它们各自都能充当领导者。因此,选举过程必须得到妥善管理,以防止两个或多个实例同时接管领导者角色。系统必须提供一种强大的机制来选择领导者。这种方法必须应对网络中断或进程故障等事件。在许多解决方案中,下属任务实例通过某种心跳方法或轮询来监控领导者。如果指定的领导者意外终止,或者网络故障使领导者对下属任务实例不可用,它们必须选举一个新的领导者。这就像在传感器网络中选择集群头节点一样。
这种模式在分布式应用程序中的任务,例如云托管解决方案,需要仔细协调且没有自然领导者时表现最佳。避免将领导者作为系统瓶颈是谨慎的做法。领导者的目的是协调下属任务的工作,它本身并不一定必须参与这项工作——尽管如果任务没有被选为领导者,它应该能够这样做。
基于队列的负载均衡模式
应用程序可能会经历突然的交通高峰,这可能会轰炸后端系统。如果后端服务无法快速响应请求,可能会导致请求排队(积压),或者可能导致服务限制应用程序。为了避免这种情况,我们可以使用队列作为缓冲。当有新的工作项时,不是立即调用后端服务,而是应用程序将工作项排队以异步运行。队列充当缓冲区,可以平滑负载的峰值。
问题描述—为了达到以业务为中心、流程感知的综合应用,云应用之间必须相互交互。服务可以是本地可用或远程访问。各种热情的软件开发者带来了现代应用,并以小额费用或有时免费的方式向全球订阅者提供。同样,还有独立软件供应商(ISVs)与托管服务提供商签订合同,以运行其软件,使其被发现和绑定。也就是说,各种云服务必须与其他许多服务连接和协作,以便对消费者来说是正确和相关的。在这个错综复杂的环境中,如果某个服务受到间歇性重负载的影响,可能会引起性能或可靠性问题。在特定时间服务用户数量的可预测性也是一个难题。因此,静态容量规划已不再适用。动态性是 IT 领域的新热门词汇。
如前所述,应用程序可以被分割成多个服务。每个服务可以作为单独的实例在不同的容器中运行。也就是说,可以在 IT 环境中运行多个服务的实例。在服务世界中,一切都可以通过 API 启用,以便其他服务发现和利用。一个服务可以被多个任务同时使用。一个服务可以是与其使用的任务相同的应用程序的一部分,也可以由第三方服务提供商提供。例如,该服务可以是资源服务,如缓存或存储服务。
一个服务可能会经历需求高峰,导致其过载,无法及时响应请求。如果服务无法处理这些请求造成的竞争,向服务发送大量并发请求也可能导致服务失败。
解决方案方法—建议重构解决方案,并在任务和服务之间引入队列。任务和服务异步运行。任务将包含服务所需数据的消息发布到队列中。队列充当缓冲区,存储消息,直到服务检索它。服务从队列中检索消息并处理它们。来自多个任务(这些任务可以以高度可变的速度生成)的请求可以通过同一个消息队列传递到服务。
此模式提供了以下好处:
-
它可以帮助最大化应用程序的可用性,因为服务中出现的延迟不会立即直接影响到应用程序,即使服务不可用或当前未处理消息,应用程序也可以继续向队列发送消息。
-
它可以帮助最大化可伸缩性,因为队列的数量和服务的数量都可以根据需求进行调整。
-
这有助于控制成本,因为部署的服务实例数量只需足够满足平均负载,而不是峰值负载。
重试模式
问题描述—我们之前已经讨论过这种模式的一些内容。应用是以服务的形式表达和暴露的,并且从不同的 IT 环境中(私有、公共和边缘云)进行分发。通常,IT 跨越嵌入式、企业和云领域。随着设备生态系统的快速增长,连接性已经扩展到地面层级的各种设备。这就是我们经常听到、读到甚至体验到网络物理系统(CPS)的原因。此外,企业规模的应用(无论是传统还是现代)相应地进行了现代化改造,并迁移到云环境中以获得云理念的独特优势。然而,由于某些特定原因,某些应用仍然保留在企业服务器/私有云中。随着嵌入式和网络设备的加入主流计算,边缘/雾设备被启用以形成某种临时的云,以促进实时数据捕获、存储、处理和决策。需要注意的是,应用服务应该连接到附近的其他服务,并在远程网络上持有服务。可能会发生故障,导致应用调用激增。正如之前所述,存在暂时性的故障,影响服务的连接性、交互和执行。然而,这些故障通常是自我纠正的,如果在适当的延迟后重复触发故障的动作,连接性和可访问性可能会恢复。
解决方案方法—在云环境中,暂时性故障很常见,应用应该设计得能够优雅且透明地处理这些故障。这最小化了故障对应用正当执行的业务任务可能产生的影响。如果应用在尝试向远程服务发送请求时检测到故障,它可以采用以下策略来处理故障:
-
取消:如果故障表明失败不是暂时的(即持续更长时间),或者如果重复尝试,则可能无法成功,应用应取消操作并报告异常。
-
重试:如果报告的具体故障不寻常或罕见,可能是由于一些不寻常的情况,例如在网络传输过程中数据包被损坏。在这种情况下,应用可以再次尝试,因为后续的请求可能会获得所需的成功。
-
延迟后重试:如果故障是由更常见的连接或繁忙失败引起的,那么应用必须等待一段时间后再尝试。
应用程序应将所有尝试访问远程服务的尝试封装在实现重试策略的代码中,该策略与之前列出的策略之一相匹配。发送到不同服务的请求可以受到不同策略的影响。一些供应商提供了实现重试策略的库,其中应用程序可以指定最大重试次数、重试尝试之间的时间以及其他参数。应用程序应记录故障和失败操作的详细信息。这些信息对操作员很有用。如果一个服务频繁不可用或繁忙,通常是因为该服务已经耗尽了其资源。我们可以通过扩展服务来减少这些故障的频率。例如,如果一个数据库服务持续过载,可能有益于对数据库进行分区并将负载分散到多台服务器上。
总结来说,在理解了下一代 IT 系统的弹性、鲁棒性和可靠性对于满足所有 QoS(服务质量)和服务质量体验(QoE)特性和原则的重要性之后,IT 行业专业人士、学术教授和研究人员正在投入他们的才智、财富和时间,挖掘大量易于理解且实用的技术、技巧和窍门,以简化并优化软件和基础设施工程任务。我建议读者访问docs.microsoft.com/en-us/azure/architecture/patterns/category/resiliency以获取更多阅读材料。
摘要
无论是传统应用还是现代应用,都应被修复为微服务的集合。微服务可以在容器内托管和运行。每个微服务可以有多个实例。每个容器可以运行一个微服务实例。因此,在典型的 IT 环境中,可能会有数百台物理机器(也称为裸机服务器)。每台物理机器反过来又能够运行数百个容器。因此,将会有数万个容器。管理和运营的复杂性因此必然会增加。这种模式在成功运行托管微服务的容器方面非常有用。有一些技术,如 Istio 和 Linkerd,可以确保微服务的弹性。这种弹性最终确保了应用程序的可靠性。与软件定义的云基础设施一起,可靠的应用程序确保了云环境在托管和交付下一代业务负载时的可靠性。
接下来的章节将讨论各种软件定义的云应用程序设计和部署模式。
第十一章:软件定义云 - 架构和设计模式
云范式正在快速发展。云计算领域有许多颠覆性的进步,因此云概念的采用率持续上升。传统应用程序正相应地修改并迁移到云环境(私有、公共和混合)。云迁移、集成、编排、经纪、部署、交付和管理等方面涌现出大量支持工具,推动战略相关的云之旅。有集成流程、最佳实践、关键指南、评估指标、高度同步的平台等,使云理念深入人心、参与广泛、无处不在。此外,还有不断增长的架构和设计模式家族,用于生成优化的云环境和应用程序。本章专门准备,以充分阐明在云领域中出现的和演变的模式。本章将阐述这些模式如何被用来简化并简化云的采用。
反映云之旅
随着云计算的演变和革命性特征,数据中心优化和转型的章程已成为主要关注点。为了实现 IT 工业化,简化标准化措施正受到越来越多的关注。各种 IT 资源,如内存、磁盘存储、处理能力和 I/O 消耗,正被关键性地、认知性地监控、测量和管理,以实现其最大程度的利用。IT 解决方案和服务的池化和共享在战略 IT 优化中占据着至关重要的地位。同时,拥有动态的计算、存储和网络资源池,使 IT 服务提供商以及企业 IT 团队能够满足客户和用户在资源需求方面的任何波动和紧急情况。
因此,迷人的云范式已成为当今 IT 的主流概念。由于其云理论的广泛接受和采用,其核心和辅助技术正蓬勃发展。云化运动如今正蓬勃发展,大多数 IT 基础设施和平台,以及商业应用程序,正被系统地修复,以云就绪,以便充分利用云理念的最初预期好处。新的热门词汇云赋能迅速流行起来,有协作和协调的举措来挖掘技术、最佳实践、模式、指标、产品和其他使能器,以了解云的适用性,并使 IT 资产和软件应用程序适应即将到来的知识时代。
即使在云领域取得了前所未有的进步,对于 IT 教授和专业人士来说,在漫长的旅程中将云概念提升到下一个层次,仍然充满了未来和丰富的机会与可能性。因此,软件定义云环境(SDCEs)的概念在当今时代获得了广泛的认可。产品供应商、云服务提供商、系统集成商和其他主要利益相关者都热衷于为他们的客户、顾客和消费者提供这样先进和备受赞誉的环境。实现和维持软件定义云环境的正确和相关的技术正在迅速成熟和稳定,因此 SDCEs 的日子不会太远。
总结来说,各种技术演变和革命在世界范围内显著提升了人类生活的质量。精心选择并巧妙利用成熟稳定的技术解决方案和服务,以实现备受期待和赞誉的数字化转型,对于构建一个安全、智能和可持续的地球是必要的。
传统应用架构与云应用架构
如前所述,我们正朝着包含软件定义计算(SDC)、软件定义存储(SDS)和软件定义网络(SDN)的 SDCEs(软件定义云环境)迈进。虚拟化和容器化使得软件定义云能够实现工作负载感知和弹性基础设施。与僵化的基础设施相比,软件定义云的可操纵性或可编程性、可消费性、可访问性、可持续性和简单性都更优越。云基础设施和应用正在引入新的模式(架构和设计)。云概念的兴起对应用架构产生了显著影响。在本节中,我们将讨论云应用架构与传统的应用架构有何不同。
传统应用架构
大多数传统应用都是使用成熟的分层应用架构模式(表示层、中间层和数据层)构建的。每一层都运行在专用的服务器上,并且静态配置了它所依赖的其他层服务器的主机名和 IP 地址。这些应用对它们运行的基础设施了解甚少。如果基础设施发生变化或失败,这些应用也会失败。因此,这些应用必须托管在高度可靠和弹性的网络和服务器上。当负载(用户和/或数据)增加时,这些应用无法自动扩展或扩展。扩展是通过购买和安装额外的服务器机器手动完成的,这是一个耗时且复杂的过程。在 Web 和应用服务器前面设置了负载均衡器,以引入所需的自动扩展。然而,在传统的应用架构中,真正的可扩展性并没有得到实现。
云架构
如前所述,虚拟化的概念引入了可编程的基础设施。也就是说,应用的扩展性是通过基础设施组件的内在弹性来实现的。通过有意识地采用虚拟化基础设施,资源利用率显著提高。虚拟化理念如今已经渗透到每个基础设施模块,为 IT 环境带来了创新、颠覆、转型和优化的浪潮。这不仅包括服务器虚拟化,还包括网络虚拟化、存储虚拟化、服务虚拟化、数据库虚拟化等等,这些正在系统地实现,以带来原本预期的虚拟、开放、灵活和自适应的 IT 基础设施,这些基础设施本质上能够预见并应对业务变化和挑战。云技术、工具和技巧的智能使用正在导致业务感知的 IT 基础设施。工具生态系统正在稳步增长,以自动化诸如资源分配、软件部署、基础设施监控、测量和管理、编排、安全、治理等任务。
云管理层还为开发人员和架构师提供了用户界面,以便通过编程设计并构建他们运行应用程序所需的基础设施。云管理层提供的云 API 还允许应用程序控制其运行的基础设施。云应用程序可以动态地扩展或缩减,在基础设施上部署或移除应用程序组件。虚拟化和容器化的颠覆性概念使得可编程基础设施成为可能。也就是说,硬件模块正被表达为可被发现、使用甚至组合的服务。随着云运动的推进,硬件编程正变得日益真实。这样的场景正在使灵活和可操纵的基础设施时代成为可能,这些基础设施保证了工作负载感知、生产力和高利用率。
云应用程序架构
如前所述,为了获得云的好处,传统应用程序需要相应地进行现代化。现代应用程序的可扩展性和其他需求需要被嵌入到应用程序中。存在某些编程语言和架构模式,以便将非功能性需求(NFRs)附加到应用程序中。传统应用程序通常使用单个数据库来存储所有应用程序信息。该数据库根据需要向各种应用程序客户端(用户以及其他应用程序组件)提供存储在其内的信息。然而,随着数据的爆炸性增长,传统的数据库可能需要扩展。
SQL 数据库的横向扩展(可扩展性)面临着许多挑战。然而,由于云基础设施的规模庞大,云数据库必须使用新的数据库类型进行设计和开发,例如 NoSQL、NewSQL、内存数据库和数据库内数据库,用于数据存储和分析。对象存储在云时代非常流行。每个云服务提供商都在押注和投资云存储以满足不断增长的存储需求。除了数据库之外,还有企业级的数据仓库和数据湖。数据存储选项正在增加。缓存存储就是这样一种受到大量支持的选择。此外,还有分布式文件系统,如 HDFS 用于大数据存储和分析。在文件系统上存在数据库抽象,以便为开发人员、数据库管理员和业务提供多种可能性。此外,还有数据备份和归档选项,以确保数据和灾难恢复(DR)。以下图表生动地说明了云应用程序架构与传统应用程序在何处以及如何偏离和不同。随着多渠道、设备、媒体和模式客户端的出现,云应用程序正在有条不紊地进步:

云应用具有独特的差异。随着面向服务的应用成熟度和稳定性的提高,越来越多的应用正趋向于服务导向。在最近过去,为了应对新的需求,已经进行了进一步的改进和优化。多语言编程正在兴起。也就是说,有几种编程和脚本语言可以构建动态的微服务集合作为云应用。此外,还有大量的数据库管理系统。每种数据库类型都适用于某些应用需求。因此,通过最流行的微服务架构(MSA)促进多种技术、工具和技术链接以构建云应用的灵活性正在得到提升。随着容器(Docker)作为高度优化的应用程序承载和运行环境的广泛应用,多种技术正在迅速汇聚,以实现敏捷和加速的软件工程、部署、交付和管理。由容器化运动引领和引导的多容器和多主机云应用成为了热门话题。
简而言之,随着云迁移,下一代应用广泛讨论的服务质量(QoS)和用户体验质量(QoE)因素和方面正在被精确实现。云基础设施正在被巧妙地调整,以应对基础设施层面的潜在挑战。另一个突出的设计要求是设计云应用以处理延迟问题。也就是说,容错性是云应用、平台和基础设施的一个重要因素。需要从萌芽阶段开始阻止故障和错误的级联效应。由于云是基于通用服务器构建的,其故障率相当高。此外,还可能出现网络拥塞/中断、资源冲突、请求竞争和存储系统的 IOPS 挑战。此外,还可能出现硬件和软件故障。云环境正变得越来越复杂,因此需要实施可行的复杂度缓解和调节技术。系统必须优雅地应对任何类型的约束和级联问题和限制。解决延迟和故障的一个流行设计模式是请求/响应队列,其中请求和响应存储在队列中。此外,云和应用程序接口必须高度直观、信息丰富和指导性强。即使云资源和资产不响应,用户体验也必须得到保持。
云集成模式
在云计算领域,正在发生许多值得注意的进步。模式对于复杂且不断发展的云计算主题非常有用。正在挖掘模式,目的是简化对云范式的深入理解和采用。在云空间中,许多潜在领域,如基础设施即服务(IaaS)、平台即服务(PaaS)、软件即服务(SaaS)、业务流程即服务(BPaaS)等,正在被重新审视,以提出新鲜和有能力的模式。正在为云应用开发准备特殊的模式。存在云集成平台(集成平台即服务(IPaaS)),用于实现不同和分布式云应用及数据源之间的一种无缝和自发的集成。因此,正在形成和阐述特定的集成模式。
这些天,云概念已经成熟并稳定下来,为企业和个人提供了数百种新颖的服务。在数据服务方面,我们有数据库即服务(DBaaS)、数据仓库即服务(DWaaS)、数据湖即服务(DLaaS)等。出现了新的数据库,以应对不同的需求。我们都听说过、阅读过,甚至体验过 NoSQL 和 NewSQL 数据库。然后还有内存数据库和内存数据网格(IMDGs)。数据分析在数据库内部进行,因此我们了解到数据库内分析。同样,云环境被指定为各种其他应用领域的最佳环境。各种操作、事务和分析应用都通过云基础设施和平台托管、管理和交付。然后还有新一代的 Web、移动、游戏、可穿戴、嵌入式、企业、物联网和区块链应用正在通过云基础设施和实例开发和交付。一切都被表达和暴露为服务,毫无疑问,云是优雅的、启用的和执行环境。在最近过去,我们听到了更多关于云编排、配置、部署、迁移、治理和经纪服务。DevOps是云景观中的另一个热门词汇。随着如此众多的云服务,许多人和集体呼吁创建有益的云中心模式,以满足各种 IT 和业务能力。
基于层级的分解
此应用程序的复杂功能被划分为多个离散的、易于管理和松散耦合的组件。每个组件都被指定执行一项任务。这种应用程序功能的分区或组件化导致了原始应用程序的逻辑分解。这些逻辑上分离的组件在服务器集群的多个层级上运行,这种分割是在基础设施级别进行的。
基于过程的分解
下一个是基于过程的分解。企业级和复杂的应用程序通常是过程中心的。在这里,我们可以引入基于过程的分解。每个过程内部包含许多需要按一定顺序执行的任务。每个任务单独完成,并按所需顺序聚合以获得应用程序功能。有许多自动化工具可以启用这种分解、自动化,最终实现编排。
基于“管道-过滤器”的分解
第三种分解类型是基于“管道-过滤器”的分解,它侧重于应用程序的数据中心处理。每个过滤器提供一种在输入数据上执行并在处理后产生输出数据的函数。多个过滤器通过管道相互连接,即通过消息传递。
这些分层和分解模式恰当地将应用程序分解为逻辑层,使得独立部署和水平扩展成为可能。应用程序和云基础设施的分层正在被吹捧为开发、部署和交付下一代分布式应用的最重要需求。
服务消息模式
消息作为统一机制:消息是不同且分布式的云服务中最统一的因素。云服务集成的目标通过消息传递来实现。下文将列出并详细说明各种服务消息模式。服务消息可以通过认证、路由、丰富、过滤、安全化和组合来满足联邦云的期望。云中介和修复可以通过智能消息传递来完成。通过创新地使用服务消息,可以构建和部署具有突破性和以前未知的服务。
不同的分布式和去中心化的云服务如何以松散耦合和去耦合的方式找到、绑定、访问和协作?
| 问题 | 服务可以在一个虚拟机上运行,或者在云环境中的不同虚拟机上运行。服务甚至可以在地理上分布的云上运行。有公共、私有和混合云,还有一些通信协议。传统的协议可能导致服务之间紧密耦合的可能性。这些反过来又对服务的可重用性、可测试性和可修改性施加了某些限制。 |
|---|---|
| 解决方案 | 从现在开始,松耦合和解耦是可行且有价值的解决方案方法。即使松耦合也有一些限制,服务之间的解耦被吹捧为最有希望的解决方案,而消息是建立解耦通信的方式,这反过来又消除了传统通信方法的缺点 |
| 影响 | 消息技术带来了一些 QoS 问题,如可靠交付、安全性、性能和事务。 |
问题:不同的应用程序通常使用不同的语言、数据格式和技术平台。当一个应用程序(组件)需要与另一个应用程序交换信息时,必须尊重目标应用程序的格式。直接向目标应用程序发送消息会导致发送者和接收者之间紧密耦合,因为格式变化直接影响两者实现。此外,直接发送还紧密耦合了应用程序,使其可以通过地址到达。
云应用程序和服务使用各种协议进行通信。远程过程调用(RPC)、远程方法调用(RMI)、Windows Communication Framework(WCF)以及服务协议(HTTP 上的 SOAP 和 REST)是云资源连接和协作的一些主要机制。然而,所有这些都导致了一种紧密耦合,这反过来又成为服务无缝和自发合作以实现更大更好事物的障碍。因此,迫切需要松耦合和解耦。云应用程序服务如何在位置和消息格式上松耦合的情况下通过消息进行远程通信?另一个正在酝酿的要求是使服务之间实现完全解耦。
解决方案:背景是分布式应用程序或其服务组件通过消息交换信息。消息作为可行的替代通信方案,不依赖于持久连接。相反,消息作为独立的通信单元被传输,通过底层基础设施路由。也就是说,只需通过一个中介连接应用程序;面向消息的中间件隐藏了通信伙伴的寻址和可用性的复杂性,并支持不同消息格式的转换。
通信伙伴现在可以通过消息进行通信,而无需知道通信伙伴使用的消息格式或其可到达的地址。面向消息的中间件提供消息通道(也称为队列)。消息可以写入这些队列或从中读取。此外,面向消息的中间件包含组件,这些组件在通道之间路由消息到目标接收者,并处理消息格式的转换。
消息框架必须具备以下能力:
-
保证每条消息的投递或保证失败投递的通知
-
在传输之外保护消息内容
-
在服务活动之间管理状态和上下文数据
-
将消息高效地作为实时交互的一部分进行传输
-
协调跨服务事务
如果没有这些类型的扩展,服务的可用性、可靠性和可重用性将施加限制,可能会损害与云托管服务相关的战略目标。
消息元数据模式
| 问题 | 服务通常以无状态方式工作。也就是说,它们不存储任何状态数据以方便后续操作。由于消息是中介,以便不同的和分布式的服务能够共同交互以完成业务交易和操作,它们需要拥有或携带所有状态数据(元数据)。 |
|---|---|
| 解决方案 | 因此,消息信封内封装的内容必须补充以活动特定的元数据,这些元数据可以在运行时单独解释和处理。 |
| 影响 | 对消息元数据的解释和处理会增加运行时性能开销,并增加服务活动设计复杂性。 |
问题:在传统方法中,当前服务交互的状态和上下文数据被放置在内存中。然而,在服务环境中,服务被设计、开发和部署为无状态资源,以实现高度可重用性。因此,在服务之间传输的消息必须携带正确和相关的数据,以依次启动正确的操作,从而完成业务流程任务。
解决方案:由于消息携带状态数据、业务规则甚至处理指令,服务可以以非常通用的方式设计。服务复杂性将降低,可重用性水平将提高,可修改性将更容易,丰富性将更快,等等。
虽然通过避免持久二进制连接减少了整体内存消耗,但服务在运行时解释和处理元数据的要求增加了性能需求。特别是无状态服务可能会施加更多的运行周期,因为它们可能需要配备高度通用的例程,能够解释和处理不同类型的消息头,以便有效地参与多个组合活动。由于存在广泛的技术标准,这些标准本质上支持并基于消息元数据,因此可以设计出各种复杂的消息交换。这可能导致过于创新和复杂的消息路径,可能难以管理和演变。
服务代理模式
如何将事件捕获和处理逻辑分离并独立管理?
| 问题 | 服务组合(编排和协调)可能会变得庞大且效率低下,尤其是在需要调用多个服务中的细粒度能力时。 |
|---|---|
| 解决方案 | 事件驱动的服务组合正成为构建复合服务的一个重要因素。事件驱动的逻辑可以轻松地延迟到不需要显式调用的事件驱动程序中,从而减少服务组合的大小和性能压力。 |
| 影响 | 当组合逻辑分布在服务中时,其复杂性会增加,并且事件驱动代理和依赖服务代理可以进一步将库存架构绑定到专有供应商技术。 |
问题:分解和组合是简化并简化软件工程的非常成功的方法。在服务环境中,应用程序是通过组装各种服务来构建的。在软件工程中,要实现的应用程序是从一系列业务流程(简单和复合)开始的,每个流程反过来又通过利用多个服务(流程元素)来实现。也就是说,应用程序被分解为一系列互操作和交互式服务,并且服务被智能地组合成下一代应用程序。
服务组合逻辑由一系列服务调用组成,每个调用都要求一个服务执行整体父业务流程逻辑的一部分。较大的业务流程可能非常复杂,尤其是在需要通过补偿和异常处理子流程包含许多“如果...怎么办?”条件时。因此,服务组合可以相应地变得很大。此外,每个服务调用都会带来性能损失,这是由于必须显式调用并与服务本身进行通信。较大的组合可能会因为需要调用多个服务来自动化单个任务而产生的总体开销而受到影响。
解决方案:关注点分离是软件工程中的一个有趣技术。由可预测事件触发的服务逻辑可以被隔离到专门为事件发生时自动调用而设计的独立程序中。这减少了需要在服务中驻留的组成逻辑的数量,并进一步减少了给定组合所需的服务调用次数。
事件驱动代理为多个服务组合形成依赖关系提供了另一层抽象。尽管感知到的组合大小可能减少,但组合本身的实际复杂性并没有减少。组合逻辑只是更加分散,因为它现在还涵盖了自动执行整体任务部分的服务代理。
中间路由模式
动态运行时因素如何影响消息路径?:
| 问题 | 服务组合越大、越复杂,提前预想和设计所有可能的运行时场景就越困难,尤其是在异步和基于消息的通信中。 |
|---|---|
| 解决方案 | 通过使用中间件路由逻辑,可以动态确定消息路径。 |
| 影响 | 动态确定消息路径会增加处理逻辑的层级,相应地可能会增加性能开销。此外,使用多个路由逻辑可能导致服务活动过于复杂。 |
问题:服务组合可以看作是组合参与者之间的一系列点对点数据交换。这些交换共同自动化一个父级业务流程。消息路由逻辑(决定消息如何从一个服务传递到另一个服务的决策逻辑)可以嵌入到组合中每个服务的逻辑中。这允许成功执行预定的消息路径。然而,可能存在未考虑到的因素,这些因素可能导致未预见的系统故障。例如:
-
消息正在传输到的目标服务暂时(甚至永久)不可用
-
嵌入的路由逻辑包含一个通配符条件来处理异常,但结果的消息目的地仍然不正确
-
原计划的消息路径无法执行,导致服务的前一个消费者拒绝消息
或者,可能只是存在动态的功能需求,而服务无法提前设计。
解决方案:通用的多用途路由逻辑可以被抽象化,使其作为架构的独立部分存在,以支持多个服务和服务组合。最常见的是,这通过使用事件驱动的服务代理来实现,这些代理可以透明地拦截消息并动态确定它们的路径。
这种模式通常作为服务代理的专用实现应用。需要执行动态路由的路由中心代理通常由消息中间件提供,是企业服务总线(ESB)产品的基本组件。这些类型的即用型代理可以被配置为执行一系列路由功能。然而,创建自定义路由代理也是可能的,并且并不罕见,尤其是在需要支持具有特殊要求复杂服务组合的环境中。
状态消息模式
如何在保持无状态的同时,为有状态交互做出贡献?
| 问题 | 当服务需要在消息交换与消费者之间在内存中维护状态信息时,它们的可扩展性可能会受损,并且它们可能成为周围基础设施的性能瓶颈。 |
|---|---|
| 解决方案 | 不是在内存中保留状态数据,而是临时将其存储委托给消息。 |
| 影响 | 此模式可能不适用于所有形式的状态数据,并且如果消息丢失,它们携带的任何状态信息也可能丢失。 |
问题:服务有时需要参与跨越多个消息交换的运行时活动。在这些情况下,服务可能需要保留状态信息,直到整体任务完成。这对于充当组合控制器的服务尤其常见。默认情况下,服务通常设计为将此状态数据保留在内存中,以便易于访问,并且基本上在服务实例活跃期间保持活跃。然而,这种设计方法可能导致严重的可扩展性问题,并且进一步违反了服务无状态设计原则。
解决方案:服务不是在内存中维护状态数据,而是将其移动到消息中。在对话交互期间,服务从下一个输入消息中检索最新的状态数据。
应用此模式有两种常见方法,这两种方法都会影响服务消费者与状态数据的关系。消费者在内存中保留最新状态数据的副本,而只有服务从将状态数据委托给消息中受益。这种方法适用于使用 WS-Addressing 实现此模式时,由于端点引用(EPRs)的单向对话性质。
消费者和服务都使用消息来临时卸载状态数据。当消费者和服务都是更大组合中的实际服务时,这种与状态数据的双向交互可能是合适的。此技术可以通过自定义消息头部实现。
当遵循带有自定义头部的双向模型时,由于运行时失败或异常条件而丢失的消息将进一步丢失状态数据,从而将整体任务置于危险之中。同时,考虑放置在消息层上的状态数据的安全影响也很重要。对于处理敏感或私人数据的服务,相应的状态信息应适当加密和/或数字签名,消费者无法访问受保护的状态数据的情况并不少见。
此外,由于此模式要求状态数据存储在每次请求和响应中传递和回传的消息中,因此考虑此信息的大小及其对带宽和运行时延迟的影响很重要。与其他需要新基础设施扩展的模式一样,建立库存范围内的状态消息支持将引入成本和努力,这是由于必要的基础设施升级所导致的。
服务回调模式
服务如何异步与其消费者同步?:
| 问题 | 当服务需要响应消费者请求以发送多个消息,或者服务消息处理需要大量时间时,通常无法进行同步通信。 |
|---|---|
| 解决方案 | 服务可以要求消费者异步与其通信,并提供一个回调地址,服务可以将响应消息发送到该地址。 |
| 影响 | 异步通信可能会引入可靠性问题,并可能需要升级周围的基础设施以完全支持必要的回调关联。 |
问题:当服务逻辑需要用多个消息来响应消费者请求时,标准的请求-响应消息交换是不合适的。同样,当特定的消费者请求需要服务在能够响应之前进行长时间处理时,同步通信是不可能的,这可能会危及服务及其周围架构的可扩展性和可靠性。
解决方案:服务被设计成消费者提供一个回调地址,服务在接收到初始消费者请求消息后,在某个时间点可以通过该地址联系消费者。此外,还要求消费者提供关联细节,以便服务可以在未来的消息中发送一个标识符,从而消费者可以将它们与原始任务关联起来。
服务实例路由
如何在不需要专有处理逻辑的情况下,让消费者联系和交互服务实例?
| 问题 | 当需要反复访问特定的状态化服务实例时,消费者必须依赖于将它们与服务更紧密耦合的自定义逻辑。 |
|---|---|
| 解决方案 | 服务以标准化的格式提供实例标识符及其目标信息,从而保护消费者免于需要使用自定义逻辑。 |
| 影响 | 这种模式可能会引入对重大基础设施升级的需求,并且如果滥用,还可能导致过度状态化的消息活动,从而违反服务无状态原则。 |
问题:存在消费者向服务发送多个消息,并且这些消息需要在同一运行时上下文中处理的情况。这类服务被有意设计成保持状态化,以便它们可以执行对话或以会话为中心的消息交换。然而,服务合同通常不提供一种标准化的方式来表示或定位服务实例。因此,消费者和服务设计者需要求助于将专有实例标识符作为常规消息数据的一部分传递,这导致需要专有实例处理逻辑。
解决方案:底层基础设施扩展以支持处理消息元数据,这使得可以将服务实例标识符放入对服务整体目标的引用中。此引用(也称为端点引用)由消息基础设施管理,以便消费者发出的消息自动路由到由引用表示的目标。因此,实例 ID 的处理不会对消费者到服务的耦合产生负面影响,因为消费者不需要包含专有的服务实例处理逻辑。由于实例 ID 是由基础设施管理的引用的一部分,因此对消费者来说是透明的。这意味着消费者不需要知道他们是否正在向服务或其实例发送消息,因为这是由消息基础设施内部的路由逻辑负责的。
异步队列模式
如何让服务和其消费者适应隔离故障并避免不必要地锁定资源?:
| 问题 | 当服务能力要求消费者同步与之交互时,它可能会抑制性能并损害可靠性。 |
|---|---|
| 解决方案 | 服务可以通过中介缓冲区与其消费者交换消息,允许服务和消费者通过保持时间解耦独立处理消息。 |
| 影响 | 可能不会有成功消息交付的确认,并且原子事务可能不可行。 |
问题:同步通信要求对每个请求立即做出响应,因此强迫每个服务交互进行双向数据交换。当服务需要执行同步通信时,服务和消费者都必须可用并准备好完成数据交换。这可能会在服务无法保证其接收请求消息的可用性或服务消费者无法保证其接收请求响应的可用性时引入可靠性问题。由于其顺序性,同步消息交换还可以进一步增加处理开销,因为服务消费者需要等待收到其原始请求的响应后才能进行其下一项操作。长时间的响应可以通过暂时锁定消费者和服务来引入延迟。
强制同步通信可能导致的另一个问题是,需要大量并发访问的服务可能会过载。因为服务预计会立即处理接收到的请求,所以使用阈值更容易达到,从而使得服务暴露于多消费者延迟或整体故障。
解决方案:引入一个队列作为中介缓冲区,接收请求消息,然后代表服务消费者转发它们。如果目标服务不可用,队列充当临时存储并保留消息。然后它定期尝试重新传输。同样,如果有响应,它可以通过同一个队列发出,当消费者可用时,该队列会将它转发回服务消费者。当服务或消费者处理消息内容时,另一方可以停用自己(或继续其他处理),以最小化内存消耗。|
可靠消息模式
我们如何在不可靠的环境中启用并确保服务可靠地交互?:
| 问题 | 消息需要到达正确的服务,并且在其路径中不应被篡改。也就是说,不可靠的通信协议和服务环境被认为是服务可靠性的主要障碍。 |
|---|---|
| 解决方案 | 必须实施一个中间可靠性机制,以确保消息能够到达正确的服务,并且它们的完整性和保密性得到适当的维护。此外,这个中间件还必须保证消息的投递。 |
| 影响 | 使用可靠性框架会增加处理开销,这可能会影响服务活动性能。它还增加了组合设计复杂性,并且可能不兼容原子服务事务。 |
问题:当服务被设计为通过消息激活和行动时,由于底层消息协议(如 HTTP)的无状态特性,自然会有服务质量下降的趋势。二进制通信协议在发送者和接收者之间的数据传输完成之前保持持久连接。然而,在消息交换中,运行时平台可能无法向发送者提供反馈,告知消息是否成功送达目标服务端点。随着服务和网络链路的增加,服务组合的复杂性相应增加。|
如果正在使用的中间件基础设施无法保证可靠的消息投递,那么风险就会爆发。如何在系统或通信失败的情况下保证消息交换,同时确保消息不会丢失?可靠性代理通过正(ACK)和负(NACK)确认通知进一步管理成功和失败的消息投递的确认。消息可以单独传输和确认,也可以捆绑成消息序列,这些序列以组的形式确认(并且也可能有与序列相关的投递规则)。
当在分布式系统中交换消息时,在通信链路上传输消息或在系统组件中处理消息时可能会发生错误。在这些条件下,应保证没有消息丢失,并且在系统故障后最终可以恢复消息。
解决方案:底层基础设施配备了一个可靠性框架,该框架跟踪和临时持久化消息传输,并向消息发送者发出成功和失败确认,以传达成功和失败的消息传输。在通信伙伴之间进行消息交换是在事务上下文中执行的,保证了 ACID 行为。在云中,有几个消息系统可以作为服务访问,例如 Amazon SQS 或 Windows Azure 存储的队列服务。
如前所述,云集成模式对于基于云的分布式应用程序的开发、部署和交付至关重要。有专门的适配器、连接器、驱动程序和其他插件来简化并简化云集成需求。集成模式对于云范式的成功至关重要。
云设计模式
本节将讨论各种对在云中构建可靠、可扩展和安全的云应用程序非常有用的云应用程序设计模式。读者可以在 Microsoft 网站上找到有关这些模式的更深入和决定性的细节:docs.microsoft.com/en-us/azure/architecture/patterns/。
缓存旁路模式
该模式的核心是从数据存储中按需将数据加载到缓存中。此模式可以提高性能,并有助于保持缓存中保留的数据与数据存储中的数据之间的一致性。应用程序使用缓存来优化对数据存储中保留信息的重复访问。然而,通常不切实际地期望缓存数据始终与数据存储中的数据完全一致。
有许多商业缓存系统提供读取通过和写入通过/写入后操作。在这些系统中,应用程序通过引用缓存来检索数据。如果数据不在缓存中,它将透明地从远程数据存储中检索并添加到缓存中。对缓存中保留的数据的任何修改都将自动写回数据存储。对于不提供此功能的缓存,维护缓存中的数据是使用缓存的应用程序的责任。应用程序可以通过实现缓存旁路策略来模拟读取通过缓存的函数。此策略有效地按需将数据加载到缓存中。
云应用性能经常受到许多人的质疑。因此,涌现出大量性能提升技术和技巧。这种模式就是这样一个突破性的解决方案技术,旨在为应用设计师提供所有正确和相关的信息,以显著提高云性能。
使用场景包括:
-
缓存不提供原生的读透和写透操作
-
资源需求是不可预测的
断路器模式
我们都知道,分布式计算是新代企业的发展方向。在分布式计算环境中,连接到远程服务和资源是一个核心需求。远程连接有故障的倾向。也就是说,应用试图连接到远程服务或数据源,但由于某些暂时性故障(如网络连接缓慢、超时、资源过载、暂时不可用等)而无法访问。这些故障通常在短时间内自行纠正,一个健壮的云应用应准备好通过使用如重试模式所描述的良好策略来克服这些故障。
然而,也可能出现故障由难以预料的事件引起的特殊情况。此外,这些故障可能需要更长的时间才能得到修复。这些故障的严重程度可能从部分连接丢失到服务的完全失败不等。在这些情况下,应用不断重试执行不太可能成功的操作可能毫无意义,相反,应用应迅速接受操作已失败,并相应地处理故障。
断路器模式可以防止应用反复尝试执行可能失败的操作,允许它在等待故障修复或确定故障持续时间较长时继续运行,而不会浪费 CPU 周期。断路器模式还使应用能够检测故障是否已解决。如果问题似乎已经得到解决,应用可以尝试调用操作。
断路器模式与重试模式不同。重试模式允许应用在有成功期望的情况下重试操作,但断路器模式阻止应用执行可能失败的操作。应用可以通过使用断路器通过重试模式调用操作来结合这两种模式。然而,重试逻辑应敏感于断路器返回的任何异常,并在断路器指示故障不是暂时性的情况下放弃重试尝试。
断路器充当可能失败的操作的代理。代理应监控最近发生的失败次数,然后使用这些信息来决定是否允许操作继续进行,或者立即返回异常。
补偿事务模式
我们都知道,任何商业和金融交易都必须严格满足 ACID 属性。随着事务性应用程序在云环境中的部署,这些属性正逐渐得到满足。现在,在大数据时代,分布式计算已成为主流计算模型。NoSQL 数据库如今非常突出和主导,以适应大数据的需求。越来越多的数据源和存储被分割但相互连接,以执行高性能的数据访问、处理和检索。在这种情况下,强事务一致性没有得到保持。相反,应用程序应追求最终一致性。在这些步骤执行过程中,系统的整体状态可能不一致,但一旦操作完成并且所有步骤都已执行,系统应再次变得一致。
在最终一致性模型中,一个重大挑战是如何处理一个无法恢复的失败步骤。在这种情况下,可能需要撤销操作中之前步骤完成的所有工作。然而,数据不能简单地回滚,因为其他并发实例的应用程序可能已经更改了它。即使在数据没有被并发实例更改的情况下,撤销一个步骤可能不仅仅是恢复原始状态的问题。可能需要应用各种特定于业务规则。
补偿机制是事务失败时的典型响应。这种模式主要是撤销一系列步骤所执行的工作,这些步骤共同定义了一个最终一致性操作,如果其中一个或多个步骤失败。补偿事务可能无法简单地用操作开始时系统的状态替换当前状态,因为这种方法可能会覆盖其他并发应用程序实例所做的更改。相反,它必须是一个智能过程,考虑到任何并发实例完成的工作。这个过程通常将是特定于应用程序的,由原始操作执行的工作的性质驱动。
实现需要补偿的最终一致性操作的常见方法是用工作流。随着原始操作的进行,系统记录有关每个步骤以及该步骤执行的工作如何撤销的信息。如果操作在任何一点失败,工作流将回滚到已完成的步骤,并执行每个步骤的反向工作。
竞争消费者模式
随着 Web 规模应用程序的日益流行,可能会有来自世界各地的许多请求。用户和数据负载通常是不可预测的。任务/操作复杂性也是不可预测的。由于负载沉重,云应用程序发现很难在规定的时间内处理每个请求并给出回复。一个选择是添加新的服务器实例。在集群和负载均衡环境中也存在一些实际困难。然而,这些消费者必须协调一致,以确保每个消息只被发送给单个消费者。工作负载也需要在消费者之间进行负载均衡,以防止实例成为瓶颈。
在这里的一个压倒性的解决方案是,在请求应用程序/用户和处理应用程序之间使用消息系统(消息队列或代理)。面向消息的中间件(MOM)是满足大量并发消费者需求的一种方法。这种中间件方法支持异步通信和处理,因此可以快速响应大量请求。
消息队列/代理/总线用于在应用程序和消费者服务实例之间建立通信通道。应用程序将请求以消息的形式发布到队列中,消费者服务实例从队列中接收消息并处理它们。这种方法使得同一池的消费者服务实例可以处理来自应用程序任何实例的消息。以下图示说明了这种架构:

此模式允许多个并发消费者处理同一消息通道接收到的消息。此模式允许系统并发处理多个消息以优化吞吐量,提高可扩展性和可用性,并平衡工作负载。
计算资源整合模式
存在几种架构模式,如 MVC、面向服务的架构(SOA)、事件驱动架构(EDA)、资源导向架构(ROA)、微服务架构(MSA)等,推荐应用分区以获得各种好处。然而,有时将多个任务或操作整合到一个计算单元中会带来许多优势。
一种常见的做法是寻找具有相似的可扩展性、生命周期和处理要求的任务。将这些项目分组在一起可以使它们作为一个单元进行扩展。许多云环境提供的弹性使得可以根据工作负载启动和停止计算单元的额外实例。这种模式可以提高计算资源利用率,并减少在云托管应用程序中执行计算处理相关的成本和管理开销。
命令和查询责任分离(CQRS)模式
在传统的数据库管理系统(DBMS)中,命令(对数据的更新)和查询(对数据的要求)都是针对单个数据仓库中的同一组实体执行的。这些实体可能是 RDBMS 中一个或多个表中的行的一个子集。通常,在这些系统中,所有创建、读取、更新和删除(CRUD)操作都应用于实体的同一表示。当对数据操作应用的业务逻辑有限时,传统的 CRUD 设计效果良好。与 CRUD 方法相关联存在一些严重问题,如下所述:
-
数据的读取和写入表示之间可能存在不匹配,例如,即使它们不是操作的一部分,也必须正确更新额外的列或属性
-
在数据存储中锁定记录时,可能会在协作域(多个操作者在同一组数据上并行操作)中遇到数据竞争,或者在乐观锁定时由于并发更新而引起更新冲突
此模式通过使用单独的接口将读取数据的操作与更新数据的操作分开,从而隔离操作。此模式可以最大化性能、可伸缩性和安全性,通过更高的灵活性支持系统随时间的演变,并防止更新命令在域级别引起合并冲突。
事件溯源模式和 CQRS 模式:基于 CQRS 的系统使用单独的读取和写入数据模型。每个模型都针对相关任务进行定制,并且通常位于物理上分开的存储中。当与事件溯源一起使用时,事件存储是写入模型,这是信息的权威来源。基于 CQRS 的系统中的读取模型提供数据的高度反规范化视图。这些视图针对应用程序的接口和显示要求进行定制,这有助于最大化显示和查询性能。
使用事件流作为写入存储,而不是在某个时间点的实际数据,避免了单个聚合上的更新冲突,并最大化了性能和可伸缩性。这些事件可以用来异步生成用于填充读取存储的数据的物化视图。
事件溯源模式
大多数应用程序都与数据一起工作,最常见的方法是应用程序通过在用户操作数据时更新数据来维护数据的当前状态。例如,在 CRUD 模型中,数据处理过程从存储中读取数据,对其进行一些修改,并使用新值更新数据的当前状态。这种方法的缺点是直接对数据存储执行更新操作可能会降低性能和响应速度。可扩展性方面也可能受到影响。在协作环境中,有众多并发用户,因此数据更新冲突的可能性很高,因为更新操作是在单个数据项上进行的。
事件被持久化在事件存储中,该存储作为数据当前状态的真相来源。事件存储通常发布这些事件,以便消费者可以收到通知并在需要时处理它们。例如,消费者可以启动任务,将事件中的操作应用于其他系统。需要注意的是,生成事件的应用程序代码与订阅事件的系统是解耦的。
解决方案是使用只追加存储来记录描述在域中对数据执行的操作的完整事件序列,而不是仅存储当前状态,以便存储可以用来实例化域对象。这种模式可以通过避免同步数据模型和业务域的要求来简化复杂域中的任务。这种模式提高了性能、可扩展性和响应速度。此外,它为事务数据提供了一致性,并维护了完整的审计跟踪和历史记录,这可能使补偿操作成为可能。
外部配置存储模式
大多数应用程序的运行时环境包括配置信息,这些信息存储在与应用程序一起部署的文件中,位于应用程序文件夹内。在某些情况下,可以编辑这些文件来更改已部署应用程序的行为。然而,在许多情况下,对配置的更改需要重新部署应用程序,从而导致不可接受的停机时间和额外的管理开销。
本地配置文件也限制了配置仅限于单个应用程序,而在某些场景中,跨多个应用程序共享配置设置会很有用。管理多个应用程序运行实例之间的本地配置更改是另一个挑战。解决方案是将配置信息存储在外部存储中。这把配置信息从应用程序部署包移至集中位置。这种模式可以提供更易于管理和控制配置数据的机会,以及跨应用程序和应用程序实例共享配置数据的机会。
联邦身份模式
有许多应用由不同的云服务提供商托管。主要的是电子邮件和社交网络应用。这些应用被来自世界各地的人们订阅和使用。通常,用户需要记住并使用不同的凭证来访问这些以客户为中心的、协作的和云应用中的每一个。管理多个凭证是一项艰巨的任务。解决方案是实现一种可以使用联邦身份这一经过验证的概念的认证机制。这是通过将用户认证方面与应用逻辑代码分离,并将认证需求委托给受信任的第三方身份服务提供商来实现的。受信任的身份提供者可以代表应用服务提供商认证用户。例如,身份服务提供商拥有微软、谷歌、雅虎!或 Facebook 账户。这种身份模式可以简化开发,减少用户管理的需求,并提高应用的用户体验。
守门人模式
云应用需要保护免受恶意用户的侵害。此外,一些云应用由多个云服务提供商提供。因此,用户可以根据自己的条款选择一个服务提供商。云代理是一种新的软件产品,使用户能够缩小合适的云服务提供商。因此,需要一种守门人软件解决方案来作为应用客户端和应用服务之间的经纪人,验证和清理请求,并在它们之间传递请求和数据。这可以提供额外的安全层,并限制系统的攻击面。
此模式最小化了客户端获取敏感信息和服务的风险。此网关解决方案作为一个门面或专门的任务,与客户端交互,然后将请求通过解耦接口传递给处理请求的主机或任务。
应用健康监控模式
云应用应满足通过 SLA 协议正式签订的各种服务和运营期望。因此,拥有一个能够精确和细致监控云应用、数据库系统、中间件解决方案等运行和健康状况的健康监控系统是相关的。因此,健康检查是确保协议质量参数的重要因素。监控并非易事。由于规模巨大,如日益软件定义、联邦化和共享,云环境非常复杂。前进的道路是将健康监控系统实施到位,以便向应用端点发送请求,以捕获正确和相关的数据,以便清晰和自信地采取行动。
领导选举模式
云应用极其复杂且精密。多个云应用实例可以在云环境中运行。同样,应用程序的不同组件也可以在云上运行。任务可能会并行工作,以执行复杂计算的各个部分。
任务实例可能大部分时间都在单独运行,但有时也可能需要协调每个实例的行动,以确保它们不会产生任何冲突,不会对共享资源造成竞争,或者意外干扰其他任务实例正在执行的工作。因此,需要熟练的协调软件;每个动作都必须得到协调。
应该选择一个单独的任务实例作为领导者,并且这个实例应该协调其他从属任务实例的行动。如果所有任务实例都在运行相同的代码,那么一个实例可以充当领导者。然而,领导者的选举必须做得聪明。必须有一个健壮的领导者选择机制。这种选择方法必须能够处理诸如网络中断或进程故障等事件。在许多解决方案中,从属任务实例通过某种心跳方法或轮询来监控领导者。如果指定的领导者意外终止,或者网络故障使领导者对从属任务实例不可用,那么他们必须选举一个新的领导者。
物化视图模式
在存储数据时,开发人员和数据库管理员更关心数据是如何存储的。他们最不关心的是数据如何被读取。选择的数据存储格式通常与数据的格式、管理数据大小和数据完整性的要求以及所使用的存储类型密切相关。例如,当使用 NoSQL 文档存储时,数据通常表示为一系列聚合,每个聚合包含该实体的所有信息。然而,这可能会对查询产生负面影响。当查询只需要从某些实体中获取数据的一个子集时,例如,几个客户的订单摘要而不包括所有订单详情,它必须提取相关实体的所有数据以获取所需详情。
为了支持高效的查询,一个常见的解决方案是在预先生成一个视图,该视图以适合所需结果集的格式实现数据。物化视图模式描述了在源数据不适合查询、生成合适的查询困难或由于数据或数据存储的性质导致查询性能较差的环境中生成预填充的数据视图。
这些仅包含查询所需数据的物化视图,允许应用程序快速获取所需的信息。除了连接表或组合数据实体之外,物化视图还可以包括计算列或数据项的当前值,对数据项进行组合值或执行转换的结果,以及作为查询一部分指定的值。物化视图甚至可以针对单个查询进行优化。这种模式可以帮助支持高效的查询和数据提取,并提高应用程序性能。
管道和过滤器模式
应用程序必须执行其在接收、处理和呈现信息时遇到的各种不同复杂性的任务。传统上,为了完成这项任务,会生成一个单体应用程序。然而,由于各种原因(可修改性、可替换性、可重用性、可替代性、简单性、可访问性、可持续性、可扩展性等),单体架构和方式注定会在某个时候失败。因此,经过验证的“分而治之”技术已经成为软件工程领域的一种首选方法。面向方面编程(AOP)是一种流行的方法。还有其他分解方法。
此外,单体模块执行的一些任务在功能上非常相似,但模块是分别设计的。一些任务可能是计算密集型的,可能从在强大的硬件上运行中受益,而其他任务可能不需要这样昂贵的资源。此外,未来可能需要额外的处理,或者处理执行任务的顺序可能会改变。
考虑到所有这些限制,推荐的方法是将每个任务流所需的处理分解成一组单独的组件(过滤器),并将每个组件(过滤器)分配以执行单个任务。通过标准化每个组件接收和发送的数据格式,这些过滤器可以组合成一个管道。这有助于避免代码重复,并使得在处理需求发生变化时,轻松地移除、替换或集成额外的组件变得容易。这种独特的模式可以通过允许执行处理的任务元素独立部署和扩展,从而显著提高性能、可扩展性和可重用性。
优先队列模式
应用程序可以将特定任务委托给其他服务执行,例如一些后台处理或与第三方或外部应用程序或服务的集成。采用中间件解决方案来执行这些中间任务已经成为一种广泛遵循的活动。消息队列在企业级和云环境中是实现诸如中介、丰富、过滤和导流等任务的突出工具。在这里,请求的顺序并不重要。也就是说,在某些场景下,对特定任务给予一种优先级是必须坚持的。这些请求应该比应用程序先前发送的优先级较低的请求先被处理。
队列通常是一个先进先出(FIFO)结构,消费者通常以它们被发布到队列中的相同顺序接收消息。然而,一些消息队列支持优先级消息。发布消息的应用程序可以分配一个优先级,队列中的消息将自动重新排序,以便具有更高优先级的消息将在具有较低优先级的消息之前被接收。这种模式在为个别客户提供不同服务级别保证的应用程序中非常有用。
基于队列的负载均衡模式
云应用程序有时可能会面临沉重的负载(用户和数据)。应用程序据此被设计和开发,并部署在集群环境中以应对突然或季节性的高峰。当应用程序承受重负载时,应用程序的性能可能会下降。特别是,一些作为应用程序一部分的关键任务可能会受到重压。
可行的做法是对应用程序进行重构,并在任务和服务之间引入一个队列。这里的想法是任务和服务异步运行。任务将包含服务所需数据的消息发布到队列中。队列充当缓冲区,存储消息直到被服务检索。服务从队列中检索消息并处理它们。来自多个任务(这些任务可以以高度可变的速度生成)的请求可以通过同一个消息队列传递到服务。这种模式可以帮助最小化需求高峰对任务和服务可用性和响应性的影响。
重试模式
应用程序分布在多个云中,跨越大陆、国家、县和城市。不仅公共云被用作应用程序部署、交付和管理平台,而且关键任务、高性能和安全的应用程序和数据存储也通过私有云进行部署和交付。一些企业继续使用传统的 IT 环境。应用程序实际上必须连接、访问和使用附近的,以及远程持有的应用程序或数据库,通常作为成功满足任何正在酝酿的业务流程需求的一部分。但是,与附近或异地环境中的其他应用程序连接和协作的应用程序并不那么简单。
在访问其他应用程序的方式中可能会出现短暂的故障。网络连接问题、由于过载导致的请求应用程序的失败、应用程序的暂时不可用等问题,都被视为在任意网络中相互通信的应用程序所面临的挑战。
应用程序应该设计成尝试再次连接并继续完成任务。如果应用程序请求失败,应用程序可以等待并再次尝试。如果需要,这个过程可以在尝试请求之间增加延迟,直到尝试了最大数量的请求。延迟可以按增量或指数方式增加,具体取决于失败类型和在此期间得到纠正的概率。
运行时重新配置模式
传统上,静态配置一直是任何应用程序的方式。如果需要更改配置,那么在合并配置更改后,应用程序必须关闭并重新启动。现在在互联网世界中,停机时间不受欢迎。因此,需要一种可行的技术来实现运行时配置。也就是说,当应用程序仍在运行并交付其服务时,必须引入所需的配置。应用程序必须立即考虑这些更改并采取行动。同样,应用程序必须将其配置更改传达给所有其组件。
这种模式的成功完全取决于应用程序运行时环境中的功能。通常,应用程序代码将对托管基础设施在检测到应用程序配置更改时引发的一个或多个事件做出响应。这通常是由于上传新的配置文件,或者通过管理门户或通过访问 API 对配置进行更改的结果。
处理配置更改事件的源代码可以检查更改并将它们应用到应用程序的组件中。这些组件必须检测并响应更改。组件应使用新值,以便实现预期的应用程序行为。这有助于保持可用性并最小化停机时间。
调度代理监督者模式
企业级应用被安排按顺序或并行执行许多任务。每个任务都由一个可以在 Docker 容器内舒适运行的微服务架构执行。一些任务可能需要连接和协作与远程应用程序服务或第三方服务。如前所述,远程连接面临着许多挑战,因为还有其他组件在贡献远程连接和访问。现在,通过包括控制流和数据流在内的流程流简化了复杂应用。这意味着一个应用必须编排所有步骤/服务以确保其消费者能力。在分布式计算领域,所有服务都必须扮演其独特角色并为应用提供价值。如果有人未能完成交易,则可以利用重试模式。如果这也未能起飞,那么整个操作必须被取消。
解决方案是使用调度代理监督者模式,该模式巧妙地编排所有正确且相关的步骤以完成预期的任务。这种编排软件解决方案以弹性和有奖的方式管理分布式工作环境中所有参与和贡献的步骤。调度器,作为调度代理监督者的主要组件,负责安排构成任务的步骤执行,并编排它们的操作。这些步骤可以组合成一个管道或工作流程。调度器负责确保此工作流程中的步骤按正确顺序执行。服务的自我恢复被称作新一代软件服务的首要属性之一。
分片模式
在大数据世界中,数据存储需要存储大量的数据。由于数据收集、存储、处理和分析的非凡增长,出现了包括存储空间在内的几个操作和管理挑战。此外,交互式查询和数据检索也困难重重。
数据正在变成大数据,这反过来又承诺带来深刻的见解。批处理和实时处理大数据也被企业所要求。新的常态是多结构化数据。因此,大量多结构化数据在结构和操作上对传统的 SQL 数据库管理系统构成了挑战。也就是说,在新世界秩序中,NoSQL 和 NewSQL 数据库非常流行。这一新趋势的主要原因是对分片(将大型数据库明确划分为更小且可管理的数据库)的成熟度和稳定性的更快提升。这些隔离的数据库正在不同的分布式通用服务器机器上运行。分片本质上支持水平可扩展性(向外扩展),而 SQL 数据库支持向上扩展(垂直可扩展性)。NoSQL 数据库还支持运行时模式更改的集成。
这种模式具有以下优点:
-
数据库系统可以通过添加运行在额外存储节点上的更多分片来向外扩展。
-
系统可以使用现成的硬件,而不是为每个存储节点使用专用和昂贵的计算机。
-
通过在分片之间平衡工作负载,您可以减少竞争并提高性能。
-
在云中,数据分片可以物理上靠近将访问数据的用户。
节流模式
云应用程序的负载通常根据活跃用户数量或他们执行的活动类型随时间变化。在办公时间内可能会有更多用户。在节日期间,更多用户会访问电子商务和电子商务应用。也可能会有突然和不可预见的活动高峰。如果系统的处理需求超过了可用资源的容量,它将遭受性能下降,甚至可能失败。如果系统必须满足约定的服务水平,这类故障可能是不被接受的。
有几种策略和解决方案可以应对这一重要挑战。一个可行的解决方案是仅使用到一定限度的资源,然后在达到分配的极限时进行节流。另一种替代自动扩展的策略是允许应用程序仅使用到一定限度的资源,然后在达到这个极限时进行节流。
系统应该监控其资源使用情况,以便在超过阈值时,可以限制一个或多个用户的请求。这将使系统能够继续运行并满足任何现有的服务水平协议(SLAs)。
工作负载分配模式
IT 资源和业务工作负载有时会面临高负载。当用户数量急剧增加时,可能会出现性能下降、可用性降低、可靠性等问题,这些问题可能会阻塞系统。目前有一些有趣的解决方案被推荐用于克服这些问题。水平扩展和利用负载均衡器在 Web、应用和数据库服务器前进行广泛和明智的实施,以满足提供商和用户之间达成的 SLA。需要将工作负载实例分布以应对高用户负载。
云工作负载调度器模式
云工作负载调度器自动化、监控和控制整个云基础设施中的工作负载。这种自动化通常每天从单一控制点管理数十万个工作负载。云调度器也可以是一个自动调度工作负载的编排引擎。调度器必须提供,以及工作负载所需的安全级别。
有新的设计模式用于加速云应用程序设计。虽然云理念发展迅速且越来越受欢迎,但可能会有更多的设计模式。我们将遇到专为云经纪服务和编排能力设计的独特而优雅的模式。将重点关注挖掘更深入和决定性的云活动自动化解决方案和模式。自助服务也是一个被赋予极高重要性的热门词汇,以便云变得对商业友好且具有商业意识。无服务器计算是云领域深入研究和研究的另一个实用且热门的话题。容器化的 Docker 是讨论和讨论的主流话题,不久的将来,我们将听到更多关于容器化云基础设施、平台和应用工作负载的消息。高度有益的设计模式将出现并赋予下一代云应用程序能力。
云可靠性及弹性模式
必须通过技术可靠的解决方案来确保云应用程序的可靠性和可靠性。云基础设施也必须相应地获得能力以确保可靠性。第二个方面是云弹性。随着业务工作负载和 IT 平台越来越多地现代化并迁移到云环境中,对云弹性的需求急剧增加。云专业人员正在努力工作,以增强人们对云范式的信心。对于这些重复需求和常见问题,拥有有能力的模式是解决 QoS 和 QoE 因素的一种可靠方式。本节致力于说明突出的云可靠性和弹性模式。
资源池化模式
为了可扩展性,IT 资源必须按需集中管理,以便在需要时提供额外的资源。当适当的资源被集中时,可以实现自动扩展能力。这里的挑战是手动在共享资源集合中建立和维护所需同步性的水平。共享 IT 资源之间的任何差异或差异都可能导致不一致性,有时甚至导致风险操作。解决方案是获取相同的 IT 资源并将它们集中起来,以便在必要时使用。关键资源包括裸机(BM)服务器、虚拟机(VMs)和容器。此外,细粒度资源包括内存、存储、处理核心、I/O 等等。已经部署了多种监控、测量和管理工具,用于资源分配、复制和利用。
资源预留模式
容量规划是实现高度优化的 IT 基础设施和资源以满足应用各种复杂需求的重要因素。如果没有得到妥善处理,那么可能会遇到资源限制的问题。当更多的云用户尝试访问一个没有能力满足用户处理需求的共享 IT 资源时,这种资源限制的情况就会发生。结果可能是性能下降,甚至可能完全无法满足请求。这取决于 IT 资源如何设计用于共享使用,以及它们可用的容量水平,并发访问可能导致称为资源限制的运行时异常条件。
资源限制是在两个或多个云用户被分配到共享一个没有能力容纳云用户全部处理需求的 IT 资源时发生的情况。结果,一个或多个用户可能会遇到某种性能下降,或者完全被拒绝。
解决方案主要是动态容量规划和建立一个 IT 资源预留系统,以保护云服务消费者。这个预留系统为每个云消费者保证了一定数量的 IT 资源。
虚拟机管理程序集群模式
任何 IT 基础设施和资源在任何时候都可能发生故障。预期 IT 系统会失败是一种良好的做法,以便更好地设计 IT 系统。现在,虚拟机管理程序,也被称为虚拟机监控程序(VMMs),为了模拟底层硬件而提供了一个额外的抽象层。问题是虚拟机管理程序也可能发生故障。当虚拟机管理程序失败时,它们上面的所有虚拟机也必然失败。因此,确保虚拟机管理程序的高可用性变得至关重要。
创建一个高可用性虚拟机管理程序集群,以建立一个跨越物理服务器的虚拟机管理程序组。结果,如果某个物理服务器或虚拟机管理程序变得不可用,托管虚拟服务器可以被移动到另一个物理服务器或虚拟机管理程序。
冗余存储模式
由于增强了灵活性和极端的性价比,云存储最近受到了很多关注。有块存储、对象存储、文件存储等等。存储设备也可能会因各种原因而出现故障和中断,包括网络连接问题、存储控制器故障、通用硬件故障和安全漏洞。当云存储系统受到损害时,结果将是前所未有的。一个辅助云存储设备被纳入一个系统,该系统与其主云存储设备中的数据进行同步。当主设备失败时,存储服务网关会自动将请求重定向到辅助设备,以满足业务连续性(BC)的要求。
此模式基本依赖于资源复制机制,以保持主云存储设备与辅助云存储设备同步。云服务提供商可能会将辅助存储设备放置在地理位置不同的位置,以确保数据备份和灾难恢复。
动态故障检测和恢复模式
云环境以集中和统一的方式包含大量 IT 基础设施,以满足全球消费者多变的 IT 需求。云环境确保了自助服务能力。IT 基础设施的主要部分包括虚拟化、共享和商品化的服务器、存储设备和网络解决方案。故障率相当高,因此主动检测故障正成为成功运行云环境的关键要求。
必须建立一个有弹性的看门狗系统来监控、测量和响应更广泛的预定义故障场景。该系统还能够通知并升级某些它无法自动解决的故障条件。
虚拟服务器的冗余物理连接模式
虚拟服务器通过虚拟交换机上行链路端口连接到外部网络。如果上行链路失败(由于电缆断开、端口故障或任何其他事故和事件),虚拟服务器就会变得孤立,并从外部网络断开连接。建立并置于待机模式的一个或多个冗余上行链路连接。当主上行链路连接不可用或出现故障条件时,冗余上行链路连接可以接管作为活动上行链路连接。
云环境承诺具有一些独特的功能,例如基础设施弹性和应用程序可伸缩性。这些增强了云的可用性。正在尝试技术和模式以确保云的可靠性/可信赖性。此外,云教授们正在给予足够的推动力,以便能够轻松且快速地实现云资产可靠性和弹性的目标。
云安全模式
如广泛接受和阐述的那样,云安全问题是个人、机构和创新者利用云环境的主要障碍,尤其是对于托管和交付他们企业级、业务关键和高性能应用程序和数据库(客户、公司和机密)的公共云。在本节中,我们将讨论一些突出的云安全模式,以便为云安全架构师、顾问和传教士提供所有正确的细节。
密码学密钥管理系统模式
密码学是确保数据安全的独特方法。加密和解密是这个数学理论的两个主要组成部分。密钥被安全生成和存储,并且在使用过程中流畅地用于保护数据,无论是传输中、静止还是被软件应用程序使用。这里的担忧是如何安全地存储生成的密钥。如果密钥丢失,那么加密的数据将无法解密。因此,行业推荐使用密码学密钥管理系统(CKMS),它包括用于保护、管理和分发密码学密钥以及某些特定信息(称为元数据)的政策、程序、组件和设备。CKMS 包括所有可以访问未加密密钥或其元数据的设备或子系统。加密密钥及其密码学保护的元数据可以由计算机处理,并通过通信系统传输,存储在不被视为 CKMS 一部分的媒体中。
虚拟专用网络(VPN)模式
在互联的世界中,互联网是廉价、开放、灵活和公共通信基础设施。虚拟专用网络(VPN)是一个使用公共电信基础设施(如互联网)来为消费者提供对其组织网络的加密连接的网络。VPN 通过安全程序和隧道协议(包括二层隧道协议(L2TP))确保隐私。数据在发送端加密以进行传输,并在接收端解密,如下面的图所示:

图中显示了两个防火墙在两个云之间建立 VPN。它们首先交换彼此的证书,并使用非对称加密来安全地交换密钥材料,以建立有效的对称密钥加密。IPsec 是在公共网络上进行私有通信的开放标准框架。它是一种网络层安全控制,用于创建 VPN。
云认证网关模式
云消费者被迫支持多种身份验证、通信和会话协议,以便访问和使用各种云服务。身份验证服务用于验证云消费者访问云服务。身份验证服务使用云服务提供商为验证云消费者所需的多种协议。
可以在云消费者和云资源之间建立一个身份验证网关服务(AGS),作为反向代理前端。此 AGS 拦截并终止消费者的加密网络连接,并验证云消费者。此外,它还验证自身和消费者到云提供商,然后代理两者之间的所有通信。
在传输中的云数据加密模式
数据安全是云概念持续增长的重要组件。随着数据分析获得广泛的重视,对安全数据捕获、传输、交换、持久化和使用的需求大大增加。数据传输网络、数据管理系统、数据分析平台、数据存储设备、文件系统等,是下一代知识时代的重要成分。加密是保护数据源和服务器之间交换数据的主要机制。
云存储设备屏蔽模式
如前所述,数据安全对于增强云消费者对基于云的企业应用程序和数据库的信心至关重要。授权数据访问是确保最高数据安全的首要任务。存储在共享云环境中的数据可能容易受到许多安全风险、威胁、漏洞和漏洞的影响。LUN 屏蔽机制可以在物理存储阵列中强制执行定义的政策,以防止未经授权的云消费者在共享云环境中访问特定的云存储设备。
静态云存储数据加密模式
存储在云环境中的数据需要防止访问构成云存储设备的物理硬盘。解决方案是利用物理存储阵列支持的任何加密机制,自动加密存储在硬盘上的数据,并解密离开硬盘的数据。
端点威胁检测和响应模式
端点安全是指通过远程设备(如智能手机、平板电脑和笔记本电脑)访问组织网络时的保护。端点威胁检测和响应(ETDR)侧重于端点而不是网络。建议利用集成安全工具来了解边缘设备的安全漏洞,以加强云网络和服务器。
威胁情报处理模式
分析行为日益普遍。IT 环境的操作、行为、安全、日志和性能数据被有意识地收集并接受各种调查。对安全相关数据的深入和决定性分析为安全分析师、架构师和顾问提供了大量有用的信息。提取的见解有助于主动建立适当的网络安全机制,以防范任何类型的网络安全攻击和利用。
可以建立一个威胁情报系统来接收和处理外部情报源,以及从分析内部攻击中获得情报。接收和收集的详细信息可以输入到安全增强系统中,例如安全信息和事件管理系统(SIEMs)、网络取证监控器(NFM)、端点威胁检测和响应系统(ETDRs)、入侵检测和保护系统(IDPSs)等。此外,这些敏感的详细信息可以在云安全运营团队之间共享,以便他们能够考虑并采取最佳行动。
云拒绝服务(DoS)保护模式
云拒绝服务(DoS)攻击是多方面的,阻止了云服务的消费者访问他们的云资源。必须将云 DoS 保护服务纳入安全架构中,以保护云服务提供商免受 DoS 攻击。网络 DoS 保护服务更新域名服务(DNS),将所有云服务提供商的流量路由通过保护服务,该服务过滤攻击流量,并将合法流量仅路由到云服务提供商。或者,当云服务提供商遭受攻击时,可以将其流量路由到 DoS 保护服务,或者创建自己的 DoS 保护服务。考虑到对坚不可摧和无法渗透的云安全解决方案的坚持,安全专家和研究人员正在挖掘新的云安全模式。未来,将出现更多与安全相关的模式。
摘要
模式一直是战略和简化设计以及各种商业和社会系统工程的根本工具。IT 领域也采纳了模式这一经过验证和具有潜力的概念,以便克服 IT 系统和服务的工程固有限制。本章专门编写,用于描述各种云计算专业人士正在挖掘和阐述的各类架构和设计模式。读者可以找到每个模式所需的确切细节。随着云范式的高速发展,有必要详细阐述各种最近提出的云模式及其正确细节。本章对有兴趣了解云相关模式的 IT 人士来说非常有用。
参考文献
云模式注册表:cloudpatterns.org/
微软的云设计模式:docs.microsoft.com/en-us/azure/architecture/patterns/
云计算模式:www.cloudcomputingpatterns.org/
亚马逊网络服务的云设计模式:en.clouddesignpattern.org/index.php/Main_Page
云架构模式:shop.oreilly.com/product/0636920023777.do
第十二章:大数据架构和设计模式
大数据是我们在当今数字世界中使用互联网和其他数字技术时产生的数字痕迹。我们在数字上所做的任何事情都会留下大量数据。有趣的是,我们可以用这些痕迹进行更智能的分析,因此可以做出更明智的决策。例如,当你登录任何网站时,它会显示你之前搜索或浏览过的产品的广告,即使它是在一个完全不同的网站上。所以通过展示你感兴趣的产品,无论具体的产品销售网站是什么,大数据分析以及一种聪明的销售方式意味着最终用户可能会喜欢这个产品,更有可能购买它。
本章旨在向读者介绍更常见的大数据架构模式。概述了大数据的核心部分、其核心原则和特性的一些简要细节,包括分析原则、大数据工作负载模式和最佳决策模式。
请注意,本章仅是对模式的一个简单介绍。读者需要参考其他在线和离线的材料(参考文献部分)。
大数据的四个 V
大数据在各个行业中有许多定义和不同的实现方式。然而,任何大数据定义都有四个共同要素,通常被称为大数据的 V。它们如下:
-
速度:这指的是数据积累的速度
-
体积:这指的是数据的规模或数据存储增长阶段
-
多样性:这指的是数据的多样性,例如结构化、半结构化、非结构化等
-
真实性:这指的是收集到的数据的准确性及其对事实的反映
V 群组的最新成员是价值。这指的是我们将积累的数据转化为有价值事物的能力和需求。这不仅仅是商业价值,还可以是任何对社交、医疗和公共事业具有显著附加价值的事物。
大数据分析和技术概念
让我们从大数据分析的技术先决条件开始,然后我们将涵盖大数据分析的生命周期。这些先决条件包括:
-
灵活的架构,支持各种数据类型和模式
-
优化数据相关性的上游分析使用
-
高级分析和实时可视化以加速行动和了解
-
协作方法以协调利益相关者
数据分析生命周期
大数据分析生命周期为组织与数据获取、处理、分析及再利用相关的数据活动和工作任务提供了一步步的方法论。以下是大数据分析生命周期的各个阶段及其简要概述。
-
数据发现:了解业务领域,将业务问题作为分析挑战来构建,并制定和形成初始假设以开始学习数据。
-
数据准备:使用数据提取、加载和转换(ELT)以及数据提取、转换和加载(ETL)来熟悉数据。
-
模型规划:确定和制定要遵循的技术、工作流程和最佳实践。了解变量之间的关系并选择最合适的方法。
-
模型构建:开发用于测试、训练和生产部署的数据集。评估运行模型所需的工具,并在需要时建议额外的工具、工作流程和执行环境。
-
沟通结果:确定关键发现,量化当前练习的商业价值、成功标准、风险和缓解措施,并向利益相关者展示。
-
实施:交付概念验证、最终报告和技术文档。
大数据分析与数据科学
大数据是收集和管理大量多样化数据的结果;数据挖掘就是搜索数据以寻找未识别的模式。
数据分析
数据分析是关于打破挖掘出的数据并评估那些未识别方法的影响。它甚至可能在一段时间内创建新的模式,并有助于开发工作应用。
数据科学
数据科学是清理、挖掘和分析数据以从中提取有价值见解的过程。通过探索性数据分析与建模的组合来提取数据见解。数据科学是从数据中提炼见解以指导决策的过程。
数据科学创建的模型能够捕捉复杂系统的潜在模式,并帮助这些模型成为工作应用:

上述图表旨在表示数据科学家遵循的数据科学过程。
大数据平台
任何软件或硬件平台都应该支持大量数据集;否则,使用传统的数据库工具很难支持这些大量数据集:

上述图表描绘了一个示例大数据平台,其中包含支持的样本工具、服务器、硬件等。
大数据工程
大数据工程从任何大数据平台的大量不同数据、数据暂存、数据概要和数据处理中获取最大价值。它还代表了将数据从后台系统迁移到前台以帮助数据分析师和数据科学家的最佳方式:

上述图表考虑了大数据工程景观的一个示例生态系统。在大数据景观的每个阶段都可以找到许多工具。以下是一些这些工具的例子:Hadoop、Oozie、Flume、Hive、HBase、Apache Pig、Apache Spark、MapReduce、YARN、Sqoop、ZooKeeper、文本分析等。然而,我们不会在这里讨论所有这些工具,因为这超出了本章的范围。
大数据治理
任何大数据企业都需要通过引入优化和隐私的规则或政策来发展和完善更广泛的 企业信息治理,同时找到货币化(价值)的途径,同时确保合规性和促进谨慎的风险管理:

大数据架构景观和层
您应该能够从大量数据中提取有价值、有意义的信息(洞察),以改善涉及各种挑战的组织决策,例如数据法规、快速决策、与客户的互动、处理遗留系统、不同的数据源等。因此,为了有效地解决所有这些挑战,研究人员提出了一个由不同层级的层组成的统一架构:

上述金字塔描绘了大数据层的重要属性以及每一层解决的问题。正如我们之前提到的,大数据不是解决一组用例的单个技术或框架;它是一套工具、流程、技术和系统基础设施,帮助企业基于大量数据痕迹进行更智能的分析和做出更明智的决策。
统一的大数据架构由多个层级组成。它提供了一种组织不同组件以解决问题的方式,并代表独特的功能:
-
大数据来源:来自多个渠道的数据,例如手持设备、软件应用、传感器、遗留数据库等
-
数据消息和存储:从数据源获取数据,数据合规性和存储格式化
-
数据分析:数据模型管理、分析引擎****和访问数据消息存储
-
数据消耗:仪表板、洞察、报告等

上述图表描绘了大数据景观的不同层级和层。这些层可能被视为我们之前对大数据概念介绍和每一层价值实现的总结。
在我们查看模式之前,让我们总结大数据架构原则如下:
-
解耦的数据总线
-
适合工作的正确工具
-
数据结构、延迟、吞吐量、访问模式
-
Lambda 架构
-
不可变日志、批量/速度/服务层
-
基于云的基础设施
-
低或无管理员系统维护
-
经济高效
大数据架构模式
在本节中,我们将根据以下大数据架构模式,带您了解大数据设计模式,并对大数据架构模式进行简要概述。
MapReduce 模式
MapReduce 是一种软件框架实现,通过在集群基础设施上应用并行和分布式算法来处理和生成大数据集。
MapReduce 的主要方法如下:
-
Map:负责过滤和排序
-
Reduce:负责操作(例如,统计记录数)
Lambda 架构模式
为了应对大数据挑战(在本章前面已描述),需要有一个数据处理架构来处理大量数据,并快速使用批量处理和流处理方法。
Lambda 架构的一些基本特征如下:
-
它依赖于底层数据的只增不减、不可变和原子性原则
-
它在平衡延迟、吞吐量和容错性方面茁壮成长
-
它与大数据和实时分析的增长相关
-
它有助于减轻 MapReduce 的延迟

上一图展示了具有三个主要层(批量处理层、速度或实时处理层和用于响应查询的服务层)的 Lambda 架构。
这里解释了三个主要层:
-
批量层:此层预先计算结果,使用分布式处理系统输出到只读数据存储,并通过替换现有的预先计算视图来更新视图。批量作业中的视图数据精度高(精度高于延迟)。
-
速度/实时层:此层实时处理数据流,视图几乎即时生成,但可能数据精度较低(延迟高于精度)。然而,这些视图可以通过批量方法稍后更新(精度高于延迟)。
-
服务层:此层存储批量层和速度层的输出,以通过预计算视图或处理数据的新视图来响应即席查询。
数据湖架构模式
在成熟的企业中,最常见的业务案例是利用现有的数据基础设施以及大数据实施。数据湖架构模式提供了有效的方法来实现重用大部分数据基础设施,同时获得大数据范式转变的好处。
数据湖具有以下基本特征以应对:
-
管理大量未处理的数据
-
尽可能长时间保留数据
-
管理数据转换的能力
-
支持动态模式
以下图表描述了数据湖模式实现。它将来自不同数据源的原生数据引入数据存储。此外,接收到的数据需要在数据仓库中尽可能长时间保留。只有在确定数据源用于主线分析时,才会进行条件处理:

数据湖提供了一种机制,可以捕获和探索可能有用的数据,而无需承担额外的交易系统存储成本,或任何将数据源带入这些交易系统的条件处理工作。
数据湖实现包括 HDFS、AWS S3、分布式文件系统等。微软、亚马逊、EMC、Teradata 和 Hortonworks 是数据湖实现方面的主要供应商,它们在其产品中提供这些技术,并销售这些技术。数据湖也可以是云基础设施即服务(IaaS)。
大数据设计模式
本节涵盖了各种数据层(如数据源和摄取层、数据存储层和数据访问层)中最突出的大数据设计模式。
数据源和摄取层
企业大数据系统面临着各种数据源,其中包含非相关信息(噪声)以及相关(信号)数据。与信号相比,噪声比率非常高,因此从相关信息中过滤噪声、处理大量数据和数据速度是非常重要的。这是摄取层的责任。摄取层中常见的挑战如下:
-
多数据源加载和优先级排序
-
摄取数据索引和标记
-
数据验证和清洗
-
数据转换和压缩

上述图表描述了摄取层的构建块及其各种组件。我们需要模式来应对数据源到摄取层通信的挑战,该通信负责处理性能、可扩展性和可用性需求。
在本节中,我们将讨论以下摄取和流模式以及它们如何帮助解决摄取层的挑战。我们还将简要提及一些常见的工作负载模式,包括:
-
多源提取器
-
多目的地
-
协议转换器
-
即时(JIT)转换
-
实时流模式
多源提取器
一种从多个数据源高效摄取多种数据类型的方法被称为多源提取器。效率代表了许多因素,如数据速度、数据大小、数据频率,以及在不稳定的网络、混合网络带宽、不同技术和系统上管理各种数据格式:

多源提取器系统确保高可用性和分布。它还确认大量数据被分割到不同节点上的多个批次。单个节点实现对于少量来自少量客户端的数据仍然有帮助,当然,对于批量处理的大量来自多个客户端的数据也是一样。在集群中将数据分割成小批量产生优秀的结果。
数据丰富器有助于进行初始数据聚合和数据清洗。丰富器确保文件传输的可靠性、验证、噪声减少、压缩以及从原生格式到标准格式的转换。收集代理节点代表中间集群系统,有助于最终数据处理和将数据加载到目标系统。
以下是多源提取器的益处:
-
为存储和消耗数据提供合理的速度
-
更好的数据优先级和数据处理
-
推动业务决策的改进
-
与数据生产解耦且独立于数据消费
-
数据语义和变更数据检测
-
可扩展和容错系统
以下是多源提取器的影响:
-
难以实现或不可能实现近乎实时数据处理
-
需要在丰富器和收集代理中维护多个副本,导致数据冗余以及每个节点上的巨大数据量
-
高可用性与高成本管理系统容量增长之间的权衡
-
基础设施和配置复杂性增加,以维护批量处理
多目标模式
在多源中,我们看到了原始数据被摄入到 HDFS,但在大多数常见情况下,企业需要将原始数据摄入到新的 HDFS 系统,同时也需要摄入到他们现有的传统数据存储,例如 Informatica 或其他分析平台。在这种情况下,额外的数据流数量导致了许多挑战,例如存储溢出、数据错误(也称为数据遗憾)、数据传输和处理时间的增加等等。
多目标模式被认为是克服先前提到的所有挑战的更好方法。这种模式与多源非常相似,直到它准备好与多个目标集成(参考以下图表)。路由器发布改进后的数据,然后将其广播到订阅目标(已在路由器上的发布代理中注册)。丰富器可以充当发布者以及订阅者:

在集群环境中部署路由器也推荐用于高流量和大量订阅者。
以下是多目标模式的益处:
-
高度可扩展、灵活、快速、对数据故障有弹性且成本效益高
-
组织可以开始将数据摄入到多个数据存储中,包括其现有的 RDBMS 以及 NoSQL 数据存储
-
允许您使用简单的查询语言,如 Hive 和 Pig,以及传统的分析
-
提供了数据分区的能力,以实现灵活访问和去中心化处理
-
数据节点中实现去中心化计算的可能性
-
由于 HDFS 节点上的复制,没有数据丢失
-
自给自足的数据节点可以无延迟地添加更多节点
以下是多目的地模式的以下影响:
-
需要复杂或额外的基础设施来管理分布式节点
-
需要在安全网络中管理分布式数据以确保数据安全
-
需要实施、治理和严格的实践来管理数据的完整性和一致性
协议转换器
这是一种中介方法,为来自各种系统的传入数据提供抽象。协议转换器模式提供了一种有效的方法,从多个数据源和不同协议中摄取各种非结构化数据。
消息交换器处理来自各种协议和处理器的同步和异步消息,如下所示图所示。它执行各种中介功能,如文件处理、Web 服务消息处理、流处理、序列化等:

在协议转换器模式中,摄取层承担着识别传入事件的各个通道、确定传入数据结构、为多个协议提供中介服务到合适的接收器、提供一种表示传入消息的标准方式、提供管理各种请求类型的处理器以及从传入协议层提供抽象等责任。
实时(JIT)转换模式
JIT 转换模式在需要将原始数据在转换和处理之前预先加载到数据存储中的情况下是最合适的。在这种业务案例中,此模式运行独立的预处理批处理作业,进行清理、验证、关联和转换,然后将转换后的信息存储到相同的数据存储(HDFS/NoSQL)中;也就是说,它可以与原始数据共存:

上述图示展示了包含原始数据存储以及转换数据集的数据存储。请注意,在多数据源模式中缺失的数据增强器在此模式中不存在,并且可以并行运行多个批处理作业以在大数据存储(如 HDFS、Mongo DB 等)中按需转换数据。
实时流模式
大多数现代企业需要对其企业大数据应用进行连续和实时的非结构化数据处理。
实时流实现需要具备以下特性:
-
通过使用大内存来最小化延迟
-
事件处理器是原子性的,并且相互独立,因此易于扩展
-
提供解析实时信息的 API
-
任何节点都可以独立部署的脚本,没有集中式主节点实现
实时流模式建议引入适当数量的事件处理节点来消费来自不同数据源的不同输入数据,并引入监听器来处理事件处理引擎中生成的事件(来自事件处理节点):

事件处理引擎(事件处理器)具有相当大的内存容量,事件处理器由特定事件触发。触发器或警报负责将内存中的大数据分析结果发布到企业业务流程引擎,并反过来被重定向到各种发布渠道(移动、CIO 桌面等)。
大数据工作负载模式
工作负载模式有助于有效地解决与不同领域和业务案例相关的数据工作负载挑战。大数据设计模式体现在解决方案结构中,因此工作负载挑战可以与正确的架构结构相对应,从而服务于工作负载。
以下图表描述了最常见的 workload 模式及其相关的架构结构:

工作负载设计模式有助于简化并将业务用例分解为工作负载。然后,这些工作负载可以系统地映射到大数据解决方案架构的各个构建块。
数据存储层
数据存储层负责获取从各种数据源收集的所有数据,并且它还负责(如果需要)将收集的数据转换为可以分析的形式。以下部分将更详细地讨论数据存储层模式。
ACID 与 BASE 与 CAP
传统的关系型数据库管理系统(RDBMS)遵循原子性、一致性、隔离性、持久性(ACID)来为数据库的任何用户提供可靠性。然而,如果存储强制执行 ACID 规则,则搜索大量大数据并从这些数据量中检索数据将消耗大量时间。因此,大数据遵循基本可用性、软状态、最终一致性(BASE),这是在大数据空间中进行任何搜索的现象。
数据库理论表明,NoSQL 大型数据库可能主要满足两个属性,并在第三个属性上放宽标准,这些属性是一致性、可用性、分区容错性(CAP)。
在 ACID、BASE 和 CAP 范式下,大数据存储设计模式获得了动力和目的。在本节中,我们将详细探讨这些模式。这些模式包括:
-
外观模式
-
NoSQL 模式
-
多语言模式
外观模式
此模式提供了一种使用现有或传统现有数据仓库以及大数据存储(如 Hadoop)的方法。它可以作为企业数据仓库和商业智能工具的外观。
在外观模式中,在转换之前,或甚至在加载到传统现有数据仓库之前,来自不同数据源的数据被聚合到 HDFS:

外观模式允许在以结构化存储的形式摄入 HDFS 后,即使数据以结构化存储在 RDBMS、NoSQL 数据库或内存缓存中,也能进行结构化数据存储。外观模式确保数据大小减少,因为只有必要的数据驻留在结构化存储中,以及从存储中更快地访问。
NoSQL 模式
此模式涉及用 NoSQL 替代传统的 RDBMS,以促进对大数据的快速访问和查询。NoSQL 数据库以列式、非关系式的方式存储数据。由于它对 HDFS 有意识,因此它可以在本地磁盘以及 HDFS 上存储数据。因此,数据可以分布在数据节点上,并且可以非常快速地检索。
让我们简要地看看四种类型的 NoSQL 数据库:
- 列式数据库管理系统:简称为列存储或大数据表存储,它为每个元组拥有大量的列。每个列都有一个列键。列族限定符代表相关的列,以便可以检索列和限定符,因为每个列都有一个列键。这些数据存储适合快速写入。

-
键值对数据库:键值数据库是一种数据存储,当提供一个简单的字符串(键)时,返回任意大小的数据(值)。键绑定到值,直到将其新值分配到或从数据库中。键值数据存储不需要有查询语言。它提供了一种添加和删除键值对的方法。键值存储是一种字典类型的数据存储,其中包含一个单词列表,每个单词代表一个或多个定义。
-
图数据库:这是包含一系列节点和关系的系统的表示,当结合在一起时,创建了一个图。图表示三个数据字段:节点、关系和属性。一些类型的图存储被称为三元存储,因为它们的节点-关系-节点结构。你可能熟悉提供类似或可能特征评估的应用程序,作为搜索的一部分(例如,一个用户购买了此物品也购买了...是图存储实现的良好示例)。

- 文档数据库:我们可以将图数据存储表示为树结构。文档树有一个根元素,有时甚至有多个根元素。注意,在根元素下面有一个分支、子分支和值的序列。每个分支都可以有一个表达式或相对路径来确定从起源节点(根)到任何给定分支、子分支或值的遍历路径。每个分支可能都与该分支相关联一个值。有时树中分支的存在具有特定的意义,有时分支必须具有特定的值才能正确解释。

下表总结了可能需要考虑 NoSQL 模式的某些 NoSQL 用例、提供商、工具和场景。大多数这种模式实现已经是各种供应商实现的一部分,它们作为开箱即用的实现和即插即用,以便任何企业都可以快速利用。
| 要使用的 NoSQL 数据库 | 场景 | 供应商/应用程序/工具 |
|---|---|---|
| 列数据库 | 需要根据给定的字符串获取整个相关列族的应用程序:例如,搜索引擎 | SAP HANA / IBM DB2 BLU / ExtremeDB / EXASOL / IBM Informix / MS SQL Server / MonetDB |
| 关键值对数据库 | 棋盘针应用(参考本节中给出的大数据工作负载模式) | Redis / Oracle NoSQL DB / Linux DBM / Dynamo / Cassandra |
| 图数据库 | 推荐引擎:提供“类似/喜欢”评估的应用程序:例如,购买此物品的用户也购买了 | ArangoDB / Cayley / DataStax / Neo4j / Oracle Spatial and Graph / Apache Orient DB / Teradata Aster |
| 文档数据库 | 评估社交媒体数据或非企业数据流失管理的应用程序 | Couch DB / Apache Elastic Search / Informix / Jackrabbit / Mongo DB / Apache SOLR |
多语言模式
传统(RDBMS)和多种存储类型(文件、CMS 等)与大数据类型(NoSQL/HDFS)共存,以解决商业问题。
大多数现代商业案例都需要传统数据库与大数据技术的共存。同时,他们还需要采用最新的大数据技术。替换整个系统不可行,也不切实际。多语言模式提供了一种有效的方法来组合和使用多种存储机制,例如 Hadoop 和 RDBMS。大数据设备在存储解决方案中共存:

上述图表展示了多语言模式在不同存储类型中存储数据的方式,例如关系型数据库管理系统(RDBMS)、键值存储、NoSQL 数据库、内容管理系统(CMS)等。与将所有信息存储在单一数据源的传统方式不同,多语言模式使得来自多个来源(RDBMS、CMS、Hadoop 等)的所有应用程序的数据都能进入不同的存储机制,如内存、RDBMS、HDFS、CMS 等。
数据访问层
在传统数据库中,数据访问涉及 JDBC 连接和文档的 HTTP 访问。然而,在大数据中,即使有缓存实现,使用传统方法进行数据访问也需要花费太多时间来获取数据,因为数据量非常大。
因此,我们需要一种机制来高效快速地获取数据,同时减少开发周期,降低维护成本等。
数据访问模式主要关注访问两种主要类型的大数据资源:
-
端到端用户驱动 API(通过简单查询访问)
-
开发者 API(通过 API 方法提供访问)
在本节中,我们将讨论以下数据访问模式,这些模式在更广泛的数据访问中实现了高效的数据访问、提高了性能、减少了开发周期和降低了维护成本:
-
连接器模式
-
轻量级无状态模式
-
服务定位器模式
-
近实时模式
-
阶段转换模式

上述图表展示了大数据架构布局,其中大数据访问模式有助于数据访问。我们将在以下章节中详细讨论整个机制。
连接器模式
开发者 API 方法涉及通过 API 快速传输和访问数据服务。它创建了优化后的数据集,以实现高效加载和分析。尽管底层数据存储在 HDFS 或自定义文件系统实现中,一些大数据设备甚至抽象化 NoSQL 数据库中的数据,以便数据访问非常高效和快速。
连接器模式包括提供开发者 API 和类似 SQL 的查询语言来访问数据,从而显著减少开发时间。正如我们在早期图表中看到的,大数据设备自带连接器模式实现。大数据设备本身是一个完整的大数据生态系统,支持虚拟化、冗余、使用协议进行复制(RAID),并且一些设备还托管 NoSQL 数据库。

上述图表显示了 Oracle 大数据设备的示例连接器实现。数据连接器可以连接到 Hadoop 和大数据设备。这是我们之前描述的定制实现的一个例子,旨在通过减少开发时间来促进更快的数据访问。
轻量级无状态模式
此模式涉及通过 Web 服务提供数据访问,因此它独立于平台或语言实现。数据通过 RESTful HTTP 调用获取,这使得该模式在云部署中最为受欢迎。WebHDFS 和 HttpFS 是 HDFS HTTP 访问的轻量级无状态模式实现示例。它使用 HTTP REST 协议。HDFS 系统向分析大数据的消费者公开 REST API(Web 服务)。此模式降低了企业的拥有成本(按使用付费),因为实现可以是集成平台即服务(iPaaS)的一部分:

前面的图示展示了 HDFS 存储的一个示例实现,该实现通过 HTTP 网络界面公开 HTTP 访问。
服务定位器模式
在大数据存储环境中,存在不同类型的数据格式(多语言持久性),如果需要从存储数据的列表中选择并分析特定的存储类型,那么服务定位器模式就派上用场。当存储访问采用 SaaS 模型时,它提供了操作、过滤、选择和关联服务目录中服务的灵活性:

前面的图示展示了服务定位器模式的一个示例实现。来自各种来源的观测数据被聚合并通过服务目录公开,可用于可视化,或者可能用于进一步分析。服务聚合器可以在企业内部或外部聚合服务。不同的可视化工具可以混合匹配这些服务,以在企业数据旁边显示社交媒体,其格式与其他数据源格式不同。
近实时模式
对于任何企业要实现实时数据访问或近实时数据访问,需要解决的关键挑战是:
-
快速数据确定:确保快速确定数据,并在数据变得无意义之前(几秒钟内,而不是几分钟)迅速做出决策。
-
快速分析:能够实时分析数据,发现异常并将它们与业务事件相关联,在数据到达的瞬间提供可视化并生成警报
需要实时数据分析的一些系统示例是:
-
雷达系统
-
客户服务应用程序
-
自动柜员机
-
社交媒体平台
-
入侵检测系统
Storm 和内存中的应用,如 Oracle Coherence、Hazelcast IMDG、SAP HANA、TIBCO、Software AG(Terracotta)、VMware 和 Pivotal GemFire XD 是一些可以实施近实时数据访问模式应用的内存计算供应商/技术平台:

如前图所示,在摄取阶段实现多级缓存,并在多个存储目的地(此处其中一个目的地是缓存)中过滤和排序数据,可以实现近乎实时的访问。缓存可以是 NoSQL 数据库,也可以是前面提到的任何内存实现工具。前图描述了使用 SOLR 作为搜索引擎的典型日志搜索实现。
阶段转换模式
在大数据世界中,大量数据可以进入数据存储。然而,并非所有数据在每个业务案例中都是必需的或具有意义的。阶段转换模式提供了一种减少扫描数据量的机制,并只检索相关数据。
HDFS 在 NoSQL 数据库中包含原始数据和特定业务数据,该数据库可以提供面向应用的结构,并且只以所需格式检索相关数据:

在需要减少数据扫描的情况下,结合阶段转换模式和 NoSQL 模式是推荐的方法。前图描述了一个这样的案例,即推荐引擎,我们需要显著减少扫描的数据量以改善客户体验。
将 HDFS 中的数据虚拟化到 NoSQL 数据库中,并与大数据设备集成,是一种高度推荐的数据快速或加速检索机制。我们已经在前面本节中展示的近实时实现中看到了这一点。
快速数据分析模式
为了更快的数据处理和访问,企业可以在其数据景观中选择以下任何一种工具。每种实现都有其自身的优点和用途;我们建议您详细阅读我们提供的参考资料中的每个实现,并根据您的企业需求选择最佳方案:
-
Apache Hadoop
-
Bash Reduce
-
Disco(诺基亚研究)
-
Apache Spark
-
Graph Lab
-
Apache Storm
-
Google Big Query
数据发现和分析层
大数据中的数据发现和分析不同于从有限集合中分析结构化 RDBMS 数据的传统分析。大数据分析需要更复杂的机制,因为它涉及自然语言处理、非结构化文本、视频和图像、RFID 数据等。本节涉及一些数据发现和分析模式,并提到了支持这些模式的工具。鼓励读者阅读其他参考资料以获得对每个模式更深入的理解:

数据排队模式
在数据分析过程中,系统需要处理峰值情况是一种非常常见的情况。此模式引入了一个工作流程或过程,用于排队额外的数据块,然后将它们路由到可用的节点:

上述图示描述了数据队列和用于额外工作流程和路由到可用节点(多个节点)的处理器的一个示例实现。
使用云 IaaS 是处理动态峰值并实现更好成本节约的最佳选择。根据需要启动额外的虚拟机,峰值时更多,流量慢或平均时更少)。
基于索引的洞察模式
此模式根据与客户互动的用户输入定义索引(键)。迭代地,找到一系列索引是索引洞察模式建议的机制。它将分析机制或模式设置为索引变量,并提供对常见行为(如父母购买玩具,以及一个社区中所有 13 岁以上的儿童)的洞察。此模式有助于找到关键高效的查找,但保持相关列在一起。
机器学习模式
此模式有助于找到来自异构设备(如 RFID 设备、能源计量器、信号设备、与天气相关的设备等)生成数据输入的模式。
理解由自动化系统或无需人工干预的设备生成数据是一项具有挑战性的任务,需要依赖算法和统计方法。幸运的是,有一些出色的算法有助于分析这些数据,以下是一些传统算法:
-
简单贝叶斯分类器算法
-
K 均值聚类算法
-
支持向量机算法
-
Apriori 算法
-
线性回归
-
假设检验
-
聚类
-
方差分析(ANOVA)
-
逻辑回归
-
神经网络/人工神经网络
-
随机森林
-
决策树
-
最近邻
-
主成分分析
-
联合分析
-
集成方法
我们可以根据需要使用这些算法的一个或多个组合。鼓励读者参考其他材料以深入了解每个算法,因为本节的范围不包括它们。
收敛(r)模式
在大多数业务案例中,正如我们之前所看到的,企业需要处理传统(结构化)数据,同时利用大数据以获得企业级洞察。收敛(r)模式提供了一种有效的方法将非结构化数据与结构化数据合并,并获取洞察和做出决策。
在某些业务案例中,企业可能需要了解其产品来自社交媒体的情感(观点和意见)。结合外部数据格式与内部企业数据格式的收敛(r)模式是最佳选择之一。此模式涉及将社交媒体中的观点和意见与内部数据分析相结合,以获得综合数据洞察。
在分析企业数据之前,数据收敛需要发生。因此,我们可以使用外观模式(参考本章的“数据存储层”部分),并且还可以使用机器学习模式来使用来自社交媒体的分组数据(对于影响、收入、品牌形象、流失率等)。
DrivenData、天池、众包分析、InfoChimps、Kaggle 和 TopCoder 等工具提供现成的汇聚器实现,我们可以使用这些工具以及 ETL 工具进行数据转换、清洗和丰富,并通过结合数据获得见解。
数据可视化层
数据可视化的主要责任是通过使用视觉表示,如统计报告、图表等,从大量数据中提供更多见解。洞察力的可视化是利益相关者和赞助者最直观的部分;它是整个大数据范式中最具影响力的部分。
由于可视化最具影响力且考虑到可视化的广泛性,本节旨在仅简要介绍一些常见的可视化模式。然而,我们鼓励读者探索参考部分中提供的独特可视化材料。

上述图表展示了样本大数据场景中的数据可视化模式。可视化模式需要支持高级视图和详细级别的细节作为视觉表示。此外,可视化模式可以与数据访问模式结合使用,以利用数据的快速访问及其展示。
初见模式
如其名所示,这是一种提供主要或简约可视化数据的方法,并且仅在需要时获取详细信息。
此模式涉及仅获取最关键和基本的数据(可能由机器学习模式、排名、分数等决定)作为第一印象,并在需要时获取钻取数据。一个例子是一个搜索应用程序仅显示一页(第一页)的搜索结果,并在用户需要时在后续页面上提供更多数据。
门户模式
在大多数常见情况下,企业已经拥有报告应用程序并打算重用这些应用程序进行大数据可视化,那么此模式涉及通过脚本框架增强网络应用程序(门户)以增强遗留可视化,从而为企业节省新可视化工具的成本。
以下列出了一些可能想要包含并增强企业门户以实现门户模式的脚本框架:
-
D3.js
-
Chart.js
-
HighChart.js
-
ChartList.js
-
Raphael
-
Processing.js
-
Pixi.js
-
Webix
-
AnyChart
-
Flot
-
Pykcharts
-
Cytoscape.js
混合视图模式
混合视图从异构数据存储(如 Hadoop、缓存和 RDBMS)创建聚合的混合视图,从而通过聚合查询结果来减少分析时间。
通过在 HIVE 层存储聚合的混合视图,它有助于提高查询性能,类似于传统的数据仓库。数据仓库的更新作为离线批处理作业进行:
| 支持的一些混合视图工具(供应商) | 一些数据集成混合工具 |
|---|
|
-
IBM Netezza
-
Cassandra
-
Vertica, Cloudera Impala
-
Hortonworks Stinger
|
-
Damia
-
Yahoo Pipes
-
MS Popfly
-
Google Mashup Editor (GME)
-
Exhibit
-
Apatar
-
MashMaker
|
表 12.2:支持的混合视图工具和数据集成工具
你可能需要注意的一些混合视图的缺点包括文本/数据不匹配、对象标识符、模式不匹配、抽象级别不匹配以及较低的数据质量或准确性(由于从独立来源的数据集成)。
压缩模式
压缩是大数据分析中的一种数据减少方法,因为减少的数据大小在计算上更便宜。
压缩模式在需要访问数据而不进行聚合或混合的情况下提供了一个机制。通过拥有标准化的格式(无论数据来源如何都需要转换到标准化格式),压缩模式可以帮助从数据存储中更快地访问数据。拥有格式的优势是确保数据正确性和一致性。
最受欢迎的压缩数据分析平台是 R,也可以使用 ReRams 探索内存压缩。
爆炸模式
这是一个帮助数据分析师查看不同数据集、发现不同数据集之间关系的模式,同时也提供不同的视角。爆炸模式在企业需要各种数据视图且没有相同类型视觉模式限制的情况下是一个有用的模式。
它还允许用户通过点击从一个视图钻取到不同的图表类型或可视化模式。
摘要
尽管数据分析的开发领域并不新鲜,但随着企业、传感器、应用程序等产生的数据量巨大,它比以往任何时候都更加关键。一旦生成数据被存储,它可以提供非凡的洞察力,不仅帮助商业企业,也帮助政府和非政府企业、社会社区、经济等方面。
在当前的技术趋势中,大数据已经涉及到许多演变,从仅仅是 buzzwords 到从机器学习算法中处理数据。随着高速、高容量、高多样性以及数据源和流的真实性(四个 V)的指数级爆炸,大数据已经成为处理企业日益增长需求的架构、工具和技术的必然代表。
在本章中,我们简要介绍了大数据的四个“V”(Volume、Velocity、Variety、Veracity),数据分析技术和概念。我们还讨论了大数据生命周期以及它是如何帮助不同利益相关者实现和实现他们的数据洞察的。一个简短的章节涵盖了大数据景观、数据层以及与大数据相关的多数架构模式,包括数据管道:即数据采集、集成、摄取、快速处理、存储、快速访问和分析阶段的有序组合。
本书最关键的主题是架构模式,本章在其大数据架构和设计模式部分反映了这一点,包括一系列架构模式,如 MapReduce、Lambda 和数据湖。然后我们按层覆盖了最常见的(应用)大数据设计模式:即在各种大数据架构层中的模式,如数据源和摄取层、数据存储层、数据访问层、数据发现和分析层以及数据可视化层。
在一个章节中涵盖大数据架构模式对我们来说是一项非常大的挑战,我们通过提供大数据概念和最常见模式的样本,尽力帮助数据架构师和其他数据技术利益相关者。我们希望这一章能为他们的大数据之旅提供一个良好的开端。正如本章许多地方所提到的,我们强烈建议读者在需要获取独家模式和实现细节时参考引用部分。
参考文献
引用和参考资料:
-
大数据:Nitin Sawant 和 Himanshu Shah 著,《应用架构问答,问题-解决方案方法》(Apress 2013)
-
大数据治理:Sunil Soares 著,《一个新兴的必要性》(MC Press,2012 年 10 月)
其他来源:
-
assured-cloud-computing.illinois.edu/files/2015/02/Cristina_Abad.pdf -
blog.flutura.com//2012/08/11-core-big-data-workload-design.html -
ercoppa.github.io/HadoopInternals/HadoopArchitectureOverview.html -
www.bcs.org/upload/pdf/enterprise-architecture-patterns-201016.pdf -
www.bigdatapatterns.org/design_patterns/automated_dataset_execution -
www.infoworld.com/article/2616959/big-data/7-top-tools-for-taming-big-data.html -
www.pentaho.com/sites/default/files/uploads/resources/forrester_patterns_in_big_data.pdf -
blogs.msmvps.com/abu/2010/10/16/data-architecture-patterns-design-patterns-and-solution-patterns/ -
conferences.oreilly.com/strata/big-data-conference-ca-2015/public/schedule/detail/38774 -
conferences.oreilly.com/strata/strataeu2014/public/schedule/detail/37305 -
hackernoon.com/ingestion-and-processing-of-data-for-big-data-and-iot-solutions-659431e37b52 -
iwringer.wordpress.com/2015/08/03/patterns-for-streaming-realtime-analytics/ -
vision.cloudera.com/the-six-principles-of-modern-data-architecture/ -
www.dezyre.com/article/types-of-analytics-descriptive-predictive-prescriptive-analytics/209



浙公网安备 33010602011771号