英语原文共 27 页,剩余内容已隐藏,支付完成后下载完整资料
第五章
服务设计
正如第3章所讨论的,当我们谈论微服务体系结构时,大多数人都会想到的一个关键因素是实际微服务组件本身的设计。正是这些自主服务构成了我们微服务系统的结构,并完成了实现您的解决方案策略的实际工作。实现包含大量小型服务组件的系统是一项挑战,因此我们将用一整章的篇幅介绍一组工具和流程,这些工具和流程可以帮助您和您的团队完成任务。
根据我们与各种组织合作和采访其他人的经验,采用微服务体系结构的团队面临的一些更具挑战性的问题是如何适当地调整微服务的大小(“微服务为什么被叫做微服务?”)以及如何正确处理数据持久性以避免跨服务共享数据。这两个问题实际上密切相关。优化规模方面的错误通常会引发无关的数据共享问题,但后者在操作上尤其有问题,因为它会造成紧密的跨服务耦合,并阻碍独立的可部署性,这是体系结构风格的核心价值。当我们与正在设计和实现微服务的人交谈时,经常提到的其他话题包括支持异步消息传递、事务建模以及处理微服务环境中的依赖关系。掌握这些元素将有助于您控制蔓延到整个系统中的额外(非必要)复杂性。这样做可以帮助您不断努力平衡任何IT系统中的两个关键因素:速度和安全。
在本章中,我们将讨论微服务的边界,看看一个服务应该有多“微”以及为什么。我们将探讨微服务接口(API),讨论面向消息的可演化API对微服务的重要性,以及它们如何减少组件间的耦合。我们将研究微服务的有效数据存储方法,探索从以数据为中心和状态捕获模型向能力驱动和面向事件源的模型转变的能力。我们还将展示命令查询责任分离(CQRS)模式如何提高数据服务的粒度,同时保持足够的速度和安全性。
本章还将涵盖一些关键主题,如支持跨微服务边界的事务、异步消息传递,以及着眼于独立可部署性来处理依赖关系。
当我们读完这些材料时,您应该已经很好地了解了在设计和构建微服务组件时所面临的挑战以及可用的模式和实践。
让我们从一个大问题开始:“微服务的最佳大小是多少?”
1.微服务边界
那么微服务到底应该有多微型呢?
实际上,这个问题没有简单的答案。首先想到的事情,例如微服务中的代码行或团队的规模都是令人信服的,因为它们提供了关注可量化价值的机会(例如,“答案是42!”). 然而,这些措施的问题在于,它们忽略了我们正在实现的业务上下文。它们不涉及谁在实现服务的组织上下文,更重要的是,不涉及如何在系统中使用服务。
我们发现大多数公司并没有试图找到一些数量来衡量,而是关注每个微服务的质量——组件将在其中使用的用例或上下文。许多微服务采用者已经转向Eric Evans的“域驱动设计”(domain-driven design,DDD)方法,以获得一套完善的流程和实践,从而促进大型复杂系统的有效、业务上下文友好的模块化。
2.微服务边界与领域驱动设计
从本质上说,当人们将微服务引入公司时,我们看到的是,他们开始将现有组件分解为更小的部分,以便在不牺牲可靠性的情况下提高服务质量的能力。
有很多方法可以将一个大系统分解成更小的子系统。在一种情况下,我们可能会试图基于实现技术来分解系统。
例如,我们可以说,所有计算量大的服务都需要用C或Rust或Go(选择您自己的毒药)编写,因此它们是一个独立的子系统,而I/O量大的特性肯定可以从诸如节点.js因此它们是自己的子系统。或者,我们可以根据团队地理划分一个大型系统:一个子系统可能在美国编写,而其他子系统可能由非洲、亚洲、澳大利亚、欧洲或南美的软件团队开发和维护。直观地说,给位于一个地方的团队提供一个独立的开发子系统是非常优化的。您决定根据地理位置划分系统的另一个原因是,本地团队可能会更好地理解在特定市场运营的特定法律、商业和文化要求。一个来自纽约的软件开发团队能否准确地捕捉到将在开罗使用的会计软件的所有必要细节?
在他的开创性著作领域驱动设计,埃里克埃文斯概述了一个新的方法来确定边界的子系统在一个更大的系统。在这个过程中,他提供了一个以模型为中心的软件系统设计视图。正如我们在这本书中指出的,模型是查看系统的一种很好的方式。它们提供了一种抽象的方式来看待事物,一种突出我们感兴趣的事物的方式。模型是一种观点。
只是个模型
要理解DDD方法,重要的是要记住,任何软件系统都是现实的模型,而不是现实本身。例如,当我们登录到网上银行并查看我们的支票账户时,我们并没有查看实际的支票账户。我们只是在看一个表示——一个模型,它给我们关于支票账户的信息,比如余额和过去的交易。银行出纳员在查看我们的账户时看到的屏幕可能有不同的信息,因为这是我们账户的另一种模式。
埃文斯在书中指出,大多数大型系统实际上没有一个单一的模型。一个大系统的整体模型实际上是由许多相互混合的小模型组成的。这些较小的模型是相关业务上下文的有机表示,它们在上下文中是有意义的,当在上下文中使用时,对于上下文的主题专家来说,它们是直观的。
3.有界上下文
在DDD中,Evans指出团队在组合上下文模型以形成更大的软件系统时需要非常小心。他这样说:
任何大型项目都有多种模式。然而,当基于不同模型的代码组合在一起时,软件就会变得有缺陷、不可靠和难以理解。团队成员之间的沟通变得混乱。 在什么情况下不应该应用模型,这一点通常是不清楚的。
-Eric Evans,《领域驱动设计:解决软件核心的复杂性》一书的作者
值得注意的是,Evans的DDD是在“微服务”一词流行的十多年前推出的。然而,前面的引语是关于建模本质的一个重要观察,如果你试图依赖一个单一的模型(例如,规范模型),事情就会变得难以理解。microservices方法试图将大型组件(模型)分解成更小的组件,以减少混乱,并使系统的每个元素更加清晰。因此,微服务体系结构是一种与DDD建模方式高度兼容的体系结构样式。为了帮助创建更小、更连贯的组件,Evans引入了有界上下文的概念。系统中的每个组件都存在于其自身的有界上下文中,这意味着每个组件的模型和这些上下文模型仅在其有界范围内使用,而不在有界上下文中共享。
通常认为,正确地识别系统中的有界上下文,使用DDD技术,并沿着这些有界上下文的接缝分解一个大系统,是设计微服务边界的有效方法。Sam Newman在其著作《构建微服务》中指出:
如果我们的服务边界与域中的有界上下文对齐,并且我们的微服务表示这些有界上下文,那么我们就可以在确保我们的微服务是松散耦合和强内聚的方面有一个很好的开端。
Newman在这里提出了一个重要的观点:有界上下文表示自治的业务域(即不同的业务能力),因此是确定微服务分界线的适当起点。如果我们使用DDD和有界上下文方法,那么两个微服务需要共享一个模型和相应的数据空间,或者最终具有紧密耦合的可能性要低得多。避免数据共享提高了我们将每个微服务视为独立可部署单元的能力。而独立部署能力是我们如何在保持整个系统安全的同时提高速度的。
使用DDD和有界上下文是设计组件的一个很好的过程。然而,还有更多的故事。实际上,我们可以使用DDD,但最终仍然可以创建相当大的组件。但在微服务体系结构中,大型并不是我们要追求的目标。相反,我们的目标是小微,甚至。这就引出了设计微服务组件的一个重要方面:越小越好。
在现代软件开发的许多环境中,工作单元粒度的概念是一个至关重要的概念。无论是显式定义还是隐式定义,我们都可以清楚地看到在敏捷开发、精益启动和持续交付等基础方法中出现的趋势。这些方法分别为项目管理、产品开发和DevOps带来了革命性的变化。值得注意的是,它们中的每一个都有其核心的缩减原则:缩减问题的规模或范围,减少完成任务所需的时间,减少获得反馈所需的时间,以及缩减部署的规模维修单位。所有这些都属于我们称之为“批量大小缩减”的概念。例如,以下是敏捷宣言的摘录:
频繁地交付工作软件,从几周到几个月不等,优先考虑较短的时间范围。
-敏捷宣言,Kent Beck et al。
基本上,从瀑布式开发转向敏捷可以看作是开发周期“批量大小”的减少如果周期在瀑布式开发中花费了很多月,那么现在我们努力在更短的周期内完成类似的一批任务:定义、构建、设计、开发和部署(几周而不是几个月)。诚然,敏捷宣言也列出了其他重要的原则,但它们只是加强和补充了“缩短周期”(即减少批量大小)的核心原则。
在精益启动的案例中,Eric Ries直接指出了小批量的关键重要性,就在方法的定义中:
精益初创公司的名字来源于精益制造革命,大野泰一和Shigeo Shingo被认为是丰田公司开发的。精益思想正在从根本上改变供应链和生产系统的运行方式。它的宗旨之一是利用工人个人的知识和创造力,缩小批量,准时生产和库存控制,加快周期。它教会了全世界创造价值的活动和浪费之间的区别,并展示了如何从内到外为产品创造质量。
-埃里克·里斯,《精益创业》一书的作者
同样,在讨论连续交付的主要好处时,Martin Fowler对小批量的作用毫不含糊,称其为该方法的核心好处的先决条件。
一旦你采纳了敏捷、精益和连续生产的有限批量的概念在代码、项目和部署级别交付时,考虑在架构级别也应用它。我们采访的很多公司都这样做过。毕竟,建筑学是其他三门学科的直接对应物。所以,用最简单的话来说,这个“有限的批量大小”就是微服务中的“微”。
就像在敏捷中一样,没有简单的、通用的度量方法来确定一个微服务应该“有多小”(例如,数量)。人们告诉我们的是,他们用“小”这个词作为一种质量,比如“可靠”和“连贯”等。
4.通用语言
只要简单地说一个“越小越好”的偏好,如果有界上下文是我们调整微服务大小的唯一工具,我们就会立即遇到一个问题,因为有界上下文实际上不能任意地小。以下是DDD领域的著名权威之一沃恩·弗农(Vaughn Vernon)对有界上下文的最佳大小的看法:
有界语境应该尽可能大,以充分表达其完整的无处不在的语言。
-Vaughn Vernon,《实现领域驱动设计》一书的作者
在DDD中,我们需要一个共享的理解和表达领域细节的方式。这种共同的理解应该为业务和技术团队提供一种共同的语言,他们可以使用这种语言在模型的定义和实现上进行协作。正如DDD告诉我们在一个组件(有界上下文)中使用一个模型一样,在有界上下文中使用的语言应该是一致的和普遍的,我们在DDD中称之为泛在语言。
从纯技术角度来看,微服务越小,开发越容易(敏捷),迭代越快(精益),部署越频繁(连续交付)。但是在建模方面,重要的是要避免创建“太小”的服务。Vernon认为,我们不能任意减小有界上下文的大小,因为它的最佳大小是由业务上下文(model)决定的。我们对服务规模的技术需求有时可能与DDD建模所能促进的不同(更小)。这可能就是为什么samnewman非常谨慎地称有界上下文分析为“极好的开始”,但不是确定微服务大小的唯一方法。我们完全同意。有界上下文是一个很好的开始,但是如果我们要有效地调整微服务的大小,我们需要更多的工具。我们将在本章后面讨论其中的一些工具,特别是当我们研究微服务的数据存储时。
5.微服务的API设计
在考虑微服务组件边界时,源代码本身只是我们关注的一部分。只有当微服务组件能够与系统中的其他组件通信时,它们才会变得有价值。它们都有一个接口或API。正如我们需要实现代码的高度分离、独立性和模块化一样,我们需要确保我们的api(组件接口)也是松散耦合的。否则,我们将无法独立部署两个微服务,这是我们的主要目标之一,以平衡速度和安全性。我们在这里看到了为微服务构建API的两种做法:
bull;面向信息
bull;超媒体驱动
6.信息导向
正如我们致力于编写可以随时间安全重构的组件代码一样,我们需要对组件之间的共享接口应用相同的工作。最有效的方法是采用面向消息的microserviceapi实现。消息传递作为在组件之间共享信息的一种方式的概念可以追溯到关于面向对象编程如何工作的最初想法。艾伦·凯在1998年提醒大家电子邮件列表上的信息的力量:
很抱歉,我很久以前就为这个主题创造了“对象”这个词,因为它让很多人把注意力集中在次要的想法上。最重要的是“信息传递”
-艾伦·凯
我们讨论过的所有关于微服务组件设计的公司都提到消息传递的概念是一个关键的设计实践。例如,Netflix依靠Avro、Protobuf和Thrift-over-TCP/IP等消息格式进行内部通信,而JSON-over-HTTP则用于与外部消费者(如手机、浏览器等)通信。通过采用面向消息的方法,开发人员可以将通用入口点公开到组件中(例如,IP地址和端口号),同时接收特定于任务的消息。这允许在消息内容中进行更改,作为一种随时间安全重构组件的方法。这里学到的关键经验是,开发人员将api和web服务视为通过网络传输序列化“对象”的工具已经太久了。然而,一种更有效的方法是将一个复杂的系统看作是一个服务的集合,这些服务在一条线上交换消息。
7.超媒体驱动
我们采访过的一些公司正在将面向消息的概念提升到一个新的层次。它们依赖于超媒体驱动的实现。在这些情况下,组件之间传递的消息不仅仅包含数据。消息还包含可能操作的描述(例如链接和表单)。现在,不仅数据是松散耦合的,动作也是松散耦合的。例如,Amazon的API网关和AppStream API都支持超文本应用程序语言(HAL)格式的响应。
超媒体风格的api将可进化性和松耦合作为设计风格的核心价值。您还可以将这种样式称为API,并将超媒体作为应用程序状态的引擎(HATEOAS API)。不管使用什么名称,如果我们要在微服务体系结构中设计合适的api,熟悉超媒体风格是很有帮助的。
超媒体风格本质上是HTML在浏览器中的工作方式。HTTP
剩余内容已隐藏,支付完成后下载完整资料
资料编号:[405558],资料为PDF文档或Word文档,PDF文档可免费转换为Word
以上是毕业论文外文翻译,课题毕业论文、任务书、文献综述、开题报告、程序设计、图纸设计等资料可联系客服协助查找。