微服务

这个新架构术语的定义

“微服务架构”一词在过去几年中兴起,用于描述一种将软件应用程序设计为一组可独立部署的服务的特定方式。虽然没有对这种架构风格的精确定义,但围绕业务能力组织、自动化部署、端点智能和语言和数据的去中心化控制等方面存在某些共同特征。

2014 年 3 月 25 日


Photo of James Lewis

James Lewis 是 Thoughtworks 的首席顾问和技术咨询委员会成员。James 对构建由小型协作服务组成的应用程序的兴趣源于他在大规模集成企业系统方面的背景。他使用微服务构建了许多系统,并且几年来一直是不断发展的社区的积极参与者。

Photo of Martin Fowler

Martin Fowler 是一位作家、演说家,也是软件开发领域的知名人士。长期以来,他一直对如何将软件系统组件化的问题感到困惑,因为他听到的模糊说法比他满意的要多。他希望微服务能够实现其倡导者所发现的早期承诺。


“微服务”——软件架构领域中又一个新术语。虽然我们自然倾向于对这类事物不屑一顾,但这个术语描述了一种我们发现越来越有吸引力的软件系统风格。在过去几年中,我们已经看到许多项目使用这种风格,并且迄今为止的结果都是积极的,以至于对于我们的许多同事来说,这正在成为构建企业应用程序的默认风格。然而,遗憾的是,没有太多信息概述了什么是微服务风格以及如何实现它。

简而言之,微服务架构风格 [1] 是一种将单个应用程序开发为一组小型服务的方法,每个服务都在自己的进程中运行,并通过轻量级机制(通常是 HTTP 资源 API)进行通信。这些服务围绕业务能力构建,并且可以通过全自动部署机制独立部署。对这些服务的集中管理最少,这些服务可以用不同的编程语言编写,并使用不同的数据存储技术。

为了开始解释微服务风格,将其与单体风格进行比较很有用:单体应用程序作为一个单元构建。企业应用程序通常由三个主要部分构建:客户端用户界面(由在用户机器上的浏览器中运行的 HTML 页面和 JavaScript 组成)、数据库(由插入到公共的、通常是关系数据库管理系统中的许多表组成)和服务器端应用程序。服务器端应用程序将处理 HTTP 请求、执行域逻辑、从数据库检索和更新数据,以及选择和填充要发送到浏览器的 HTML 视图。这个服务器端应用程序是一个单体——一个单一的逻辑可执行文件 [2]。对系统的任何更改都涉及构建和部署服务器端应用程序的新版本。

这样的单体服务器是构建此类系统的自然方式。您用于处理请求的所有逻辑都在单个进程中运行,允许您使用语言的基本功能将应用程序划分为类、函数和命名空间。稍加注意,您就可以在开发人员的笔记本电脑上运行和测试应用程序,并使用部署管道来确保更改经过适当测试并部署到生产环境中。您可以通过在负载均衡器后面运行多个实例来水平扩展单体。

单体应用程序可以取得成功,但人们越来越感到沮丧——尤其是随着越来越多的应用程序被部署到云端。更改周期绑定在一起——对应用程序的一小部分进行更改,需要重建和部署整个单体。随着时间的推移,通常很难保持良好的模块化结构,这使得更难以将本应只影响一个模块的更改保留在该模块内。扩展需要扩展整个应用程序,而不是扩展需要更多资源的部分。

图 1:单体和微服务

这些挫败感导致了微服务架构风格:将应用程序构建为一组服务。除了服务可以独立部署和扩展之外,每个服务还提供了一个坚固的模块边界,甚至允许不同的服务用不同的编程语言编写。它们也可以由不同的团队管理。

我们ไม่ได้声称微服务风格是新颖的或创新的,它的根源至少可以追溯到 Unix 的设计原则。但我们确实认为,没有足够多的人考虑微服务架构,如果他们使用它,许多软件开发会更好。

微服务架构的特征

我们不能说微服务架构风格有一个正式的定义,但我们可以尝试描述我们认为符合该标签的架构的共同特征。与任何概述共同特征的定义一样,并非所有微服务架构都具有所有特征,但我们确实期望大多数微服务架构都表现出大多数特征。虽然我们作者一直是这个相当松散的社区的积极成员,但我们的目的是尝试描述我们在自己的工作中以及在我们认识的团队的类似努力中所看到的情况。特别是,我们没有制定任何定义来遵守。

通过服务进行组件化

只要我们参与软件行业,就一直渴望通过将组件插入在一起来构建系统,就像我们在物质世界中看到事物的方式一样。在过去的几十年里,我们已经看到,作为大多数语言平台的一部分,常见的库的大量汇编取得了相当大的进展。

在谈论组件时,我们遇到了什么构成组件的困难定义。我们的定义是,组件是一个可以独立替换和升级的软件单元。

微服务架构将使用库,但它们组件化自身软件的主要方式是分解成服务。我们将定义为链接到程序中并使用内存函数调用调用的组件,而服务是进程外组件,它们使用 Web 服务请求或远程过程调用等机制进行通信。(这与许多面向对象程序中的服务对象的概念不同 [3]。)

使用服务作为组件(而不是库)的一个主要原因是服务是可独立部署的。如果您有一个应用程序 [4],它由单个进程中的多个库组成,那么对任何单个组件的更改都会导致必须重新部署整个应用程序。但是,如果将该应用程序分解为多个服务,则您可以预期许多单一服务更改只需要重新部署该服务。这不是绝对的,有些更改会更改服务接口,从而导致一些协调,但良好的微服务架构的目标是通过内聚的服务边界和服务契约中的演进机制来最大程度地减少这些更改。

使用服务作为组件的另一个结果是更明确的组件接口。大多数语言都没有很好的机制来定义显式的 发布接口。通常,只有文档和纪律才能防止客户端破坏组件的封装,从而导致组件之间过度紧密的耦合。服务通过使用显式的远程调用机制,可以更容易地避免这种情况。

像这样使用服务确实有缺点。远程调用比进程内调用更昂贵,因此远程 API 需要更粗粒度,这通常更难使用。如果您需要更改组件之间的职责分配,那么在跨越进程边界时,这种行为的移动更难做到。

初步看来,我们可以观察到服务映射到运行时进程,但这只是一个初步的近似值。服务可能由多个进程组成,这些进程将始终一起开发和部署,例如应用程序进程和仅由该服务使用的数据库。

围绕业务能力组织

在寻求将大型应用程序拆分成多个部分时,管理层通常会关注技术层,从而导致 UI 团队、服务器端逻辑团队和数据库团队。当团队按照这些路线分开时,即使是简单的更改也可能导致跨团队项目需要时间和预算批准。一个聪明的团队会围绕这一点进行优化,并选择两害相权取其轻——只需将逻辑强制到他们可以访问的任何应用程序中。换句话说,逻辑无处不在。这是 康威定律 的一个例子。

任何设计系统(广义定义)的组织,其产生的设计结构都是该组织通信结构的副本。

——梅尔文·康威,1968 年

图 2:康威定律在行动

微服务方法的划分是不同的,它被划分为围绕业务能力组织的服务。此类服务采用该业务领域的软件的广泛堆栈实现,包括用户界面、持久存储和任何外部协作。因此,团队是跨职能的,包括开发所需的所有技能:用户体验、数据库和项目管理。

图 3:由团队边界强化的服务边界

一家以这种方式组织的公司是 www.comparethemarket.com。跨职能团队负责构建和运营每个产品,每个产品都被拆分为许多通过消息总线进行通信的独立服务。

大型单体应用程序也可以围绕业务能力进行模块化,尽管这并不常见。当然,我们建议构建单体应用程序的大型团队按照业务线进行划分。我们在这里看到的主要问题是,它们往往围绕着*太多*的上下文进行组织。如果单体跨越了许多这样的模块边界,团队中的个别成员可能难以将它们放入短期记忆中。此外,我们看到模块化线需要大量的纪律来执行。服务组件所需的更明确的分离使得团队边界更容易保持清晰。

产品而非项目

我们看到的大多数应用程序开发工作都使用项目模型:目标是交付一些软件,然后将其视为已完成。完成后,软件被移交给维护组织,构建它的项目团队被解散。

微服务支持者倾向于避免这种模式,而是更倾向于团队应该在其整个生命周期内拥有产品的理念。这种理念的一个常见灵感来自亚马逊的“你构建,你运行”的理念,即开发团队对生产环境中的软件负全部责任。这使得开发人员能够每天接触到他们的软件在生产环境中的行为,并增加与用户的联系,因为他们必须承担至少一部分的支持负担。

产品思维与业务能力的联系紧密相连。与其将软件视为一组要完成的功能,不如将其视为一种持续的关系,其中的问题是如何让软件帮助其用户增强业务能力。

单体应用程序没有理由不能采用同样的方法,但是服务的粒度越小,就越容易在服务开发人员和他们的用户之间建立个人关系。

智能端点和哑管道

在构建不同流程之间的通信结构时,我们已经看到许多产品和方法都强调在通信机制本身中加入重要的智能。企业服务总线(ESB)就是一个很好的例子,ESB产品通常包括用于消息路由、编排、转换和应用业务规则的复杂设施。

微服务社区倾向于另一种方法:*智能端点和哑管道*。由微服务构建的应用程序的目标是尽可能地解耦和内聚——它们拥有自己的域逻辑,并且更像是经典Unix意义上的过滤器——接收请求,根据需要应用逻辑并生成响应。这些是使用简单的RESTish协议而不是像WS-Choreography或BPEL这样的复杂协议或由中央工具进行编排的。

最常用的两种协议是带有资源API的HTTP请求-响应和轻量级消息传递[7]。第一个的最佳表达是

成为Web的一部分,而不是Web的背后

-- Ian Robinson

微服务团队使用构建万维网(以及在很大程度上,Unix)的原则和协议。经常使用的资源可以被缓存,而开发人员或运营人员几乎不需要付出任何努力。

第二种常用的方法是通过轻量级消息总线进行消息传递。所选择的基础设施通常是哑的(哑的意思是只充当消息路由器)——像RabbitMQ或ZeroMQ这样的简单实现除了提供可靠的异步结构之外,没有做太多其他的事情——智能仍然存在于生产和消费消息的端点中;在服务中。

在单体中,组件在进程内执行,它们之间的通信是通过方法调用或函数调用进行的。将单体更改为微服务的最大问题在于更改通信模式。将内存中的方法调用简单地转换为RPC会导致性能不佳的频繁通信。相反,您需要用粗粒度的方法来代替细粒度的通信。

去中心化治理

集中治理的后果之一是倾向于在单一技术平台上进行标准化。经验表明,这种方法是有限制的——并非所有问题都是钉子,并非所有解决方案都是锤子。我们更喜欢使用合适的工具来完成工作,虽然单体应用程序可以在一定程度上利用不同的语言,但这并不常见。

将单体的组件拆分为服务,我们在构建每个组件时都有选择。你想使用Node.js来建立一个简单的报表页面吗?放手去做吧。为一个特别棘手的近实时组件使用C++?没问题。你想换一种更适合一个组件的读取行为的数据库吗?我们有技术来重建它。

当然,仅仅因为你*可以*做某事,并不意味着你*应该*做——但是以这种方式对你的系统进行分区意味着你有选择。

构建微服务的团队也更喜欢不同的标准方法。他们不喜欢使用写在纸上的既定标准,而是更喜欢生成有用工具的想法,其他开发人员可以使用这些工具来解决他们面临的类似问题。这些工具通常是从实现中收集的,并与更广泛的群体共享,有时(但不限于)使用内部开源模型。现在,git和github已经成为事实上的首选版本控制系统,开源实践在企业内部正变得越来越普遍。

Netflix是一个遵循这种理念的组织的很好的例子。将有用且经过实战检验的代码作为库共享,鼓励其他开发人员以类似的方式解决类似的问题,但在需要时也为选择不同的方法敞开了大门。共享库往往侧重于数据存储、进程间通信以及我们在下面进一步讨论的基础设施自动化的常见问题。

对于微服务社区来说,开销特别不具吸引力。这并不是说社区不重视服务契约。恰恰相反,因为它们的数量往往要多得多。只是他们正在寻找不同的方式来管理这些契约。像*容错读取器*和*消费者驱动的契约*这样的模式通常应用于微服务。这些有助于服务契约独立发展。将执行消费者驱动的契约作为构建的一部分,可以增加信心,并提供关于服务是否正常运行的快速反馈。事实上,我们知道澳大利亚的一个团队使用消费者驱动的契约来驱动新服务的构建。他们使用简单的工具来定义服务的契约。这在编写新服务的代码之前就成为了自动化构建的一部分。然后,服务只构建到满足契约的程度——这是一种避免在构建新软件时出现“YAGNI”[8]困境的优雅方法。这些技术以及围绕它们不断发展的工具,通过减少服务之间的时间耦合,限制了对中央契约管理的需求。

也许,去中心化治理的顶峰是由亚马逊推广的“构建它/运行它”的精神。团队负责他们构建的软件的各个方面,包括全天候运营软件。这种责任下放绝对不是常态,但我们确实看到越来越多的公司将责任推向开发团队。Netflix是另一个采用这种理念的组织[10]。每天晚上都被你的寻呼机吵醒,这无疑是一个强大的动力,让你在编写代码时专注于质量。这些想法与传统的集中治理模式相去甚远。

去中心化数据管理

数据管理的去中心化以多种不同的方式呈现。在最抽象的层面上,这意味着世界观的概念模型在不同的系统之间会有所不同。这是在大型企业中进行集成时的一个常见问题,销售人员对客户的看法与支持人员的看法不同。在销售视图中被称为客户的某些东西可能根本不会出现在支持视图中。那些出现的客户可能具有不同的属性,并且(更糟糕的是)具有微妙不同的语义的通用属性。

这个问题在应用程序之间很常见,但也可能发生在应用程序*内部*,特别是当应用程序被划分为不同的组件时。考虑这个问题的一个有用方法是领域驱动设计中的*限界上下文*概念。DDD将一个复杂的领域划分为多个限界上下文,并绘制出它们之间的关系。这个过程对于单体和微服务架构都很有用,但是在服务和上下文边界之间存在自然的关联,这有助于澄清,并且正如我们在关于业务能力的部分中所描述的那样,加强了分离。

除了对概念模型的决策进行去中心化之外,微服务还对数据存储决策进行了去中心化。虽然单片应用程序更倾向于为持久数据使用单一逻辑数据库,但企业通常更倾向于在各种应用程序中使用单一数据库 - 其中许多决策是根据供应商围绕许可的商业模式做出的。微服务更倾向于让每个服务管理自己的数据库,无论是相同数据库技术的不同实例,还是完全不同的数据库系统 - 这种方法称为多语言持久化。您可以在单片架构中使用多语言持久化,但它在微服务中更为常见。

将跨微服务的数据责任分散会对更新管理产生影响。处理更新的常用方法是使用事务来保证更新多个资源时的一致性。这种方法经常在单片架构中使用。

像这样使用事务有助于保持一致性,但会造成显著的时间耦合,这在多个服务中是一个问题。众所周知,分布式事务难以实现,因此微服务架构强调服务之间无事务协调,并明确认识到一致性可能只是最终一致性,并且问题是通过补偿操作来解决的。

选择以这种方式管理不一致性对许多开发团队来说是一个新的挑战,但这通常与业务实践相一致。企业通常会处理一定程度的不一致性,以便快速响应需求,同时拥有一些逆向流程来处理错误。只要修复错误的成本低于在更高一致性下损失业务的成本,那么这种权衡就是值得的。

基础设施自动化

在过去几年中,基础设施自动化技术得到了极大的发展 - 云计算,特别是 AWS 的发展,降低了构建、部署和运营微服务的运营复杂性。

许多使用微服务构建的产品或系统是由具有丰富持续交付及其前身持续集成经验的团队构建的。以这种方式构建软件的团队广泛使用基础设施自动化技术。下图所示的构建管道说明了这一点。

图 5:基本构建管道

由于这不是一篇关于持续交付的文章,因此我们将在这里只关注几个关键特性。我们希望尽可能确信我们的软件能够正常工作,因此我们运行了大量的自动化测试。将工作软件“向上”提升到管道意味着我们将自动化部署到每个新环境。

一个单片应用程序将通过这些环境顺利地构建、测试和推送。事实证明,一旦您投资于自动化单片架构的生产路径,那么部署更多应用程序就不再那么可怕了。请记住,持续交付的目标之一是使部署变得枯燥乏味,所以无论是部署一个还是三个应用程序,只要它仍然枯燥乏味,那就无所谓了[11]

我们看到团队在生产环境中管理微服务时广泛使用基础设施自动化的另一个领域是。与我们上面断言的只要部署枯燥乏味,单片架构和微服务之间就没有太大区别相反,每种架构的运营环境可能截然不同。

图 6:模块部署通常不同

为故障而设计

使用服务作为组件的结果是,需要对应用程序进行设计,使其能够容忍服务的故障。任何服务调用都可能由于供应商不可用而失败,客户端必须尽可能优雅地对此做出响应。与单片设计相比,这是一个缺点,因为它引入了额外的复杂性来处理它。因此,微服务团队不断反思服务故障如何影响用户体验。Netflix 的Simian Army会在工作日内引发服务甚至数据中心的故障,以测试应用程序的弹性和监控能力。

这种在生产环境中进行的自动化测试足以让大多数运营团队不寒而栗,通常是在休假一周之前。这并不是说单片架构风格不能进行复杂的监控设置 - 只是根据我们的经验,这种情况不太常见。

由于服务随时可能发生故障,因此能够快速检测故障并尽可能自动恢复服务非常重要。微服务应用程序非常重视应用程序的实时监控,检查架构元素(数据库每秒接收多少请求)和业务相关指标(例如每分钟收到多少订单)。语义监控可以提供早期预警系统,提醒开发团队进行跟进和调查。

这对微服务架构尤为重要,因为微服务倾向于编排和事件协作会导致紧急行为。虽然许多专家都称赞意外出现的价值,但事实是,紧急行为有时可能是一件坏事。监控对于快速发现不良紧急行为以便及时修复至关重要。

可以将单片架构构建为与微服务一样透明 - 事实上,它们应该如此。区别在于,您绝对需要知道在不同进程中运行的服务何时断开连接。对于同一进程中的库,这种透明性不太可能有用。

微服务团队希望看到每个服务的复杂监控和日志记录设置,例如显示正常运行时间/停机时间的仪表板,以及各种运营和业务相关指标。有关断路器状态、当前吞吐量和延迟的详细信息是我们经常遇到的其他示例。

演进式设计

微服务实践者通常来自演进式设计背景,并将服务分解视为一种额外的工具,使应用程序开发人员能够控制应用程序中的更改,而不会减缓更改速度。变更控制并不一定意味着减少变更 - 只要态度和工具正确,您就可以对软件进行频繁、快速且良好控制的变更。

每当您尝试将软件系统分解为组件时,您都面临着如何划分各个部分的决定 - 我们根据哪些原则来决定如何切分我们的应用程序?组件的关键属性是独立替换和可升级性的概念[12] - 这意味着我们要寻找可以想象在不影响其协作者的情况下重写组件的点。事实上,许多微服务团队更进一步,明确期望许多服务会被废弃,而不是在长期内进行演进。

《卫报》网站是一个很好的例子,它最初被设计和构建为一个单片应用程序,但一直在向微服务方向发展。单片架构仍然是网站的核心,但他们更喜欢通过构建使用单片架构 API 的微服务来添加新功能。这种方法对于本质上是临时的功能特别方便,例如处理体育赛事的专门页面。网站的这一部分可以使用快速开发语言快速拼凑起来,并在赛事结束后删除。我们已经在一家金融机构看到了类似的方法,其中会针对市场机会添加新服务,并在几个月甚至几周后弃用。

这种对可替换性的强调是更通用的模块化设计原则的一个特例,即通过变更模式来驱动模块化[13]。您希望将同时发生变化的内容保存在同一个模块中。很少发生变化的系统部分应该与当前正在经历大量变更的系统部分使用不同的服务。如果您发现自己反复地同时更改两个服务,那么这就是一个信号,表明它们应该合并。

将组件放入服务中为更精细的发布计划提供了机会。对于单片架构,任何更改都需要对整个应用程序进行完整的构建和部署。但是,对于微服务,您只需要重新部署您修改过的服务即可。这可以简化和加快发布过程。缺点是您必须担心对一个服务的更改会破坏其使用者。传统的集成方法是尝试使用版本控制来解决这个问题,但在微服务领域,人们更倾向于仅将版本控制作为最后的手段。我们可以通过设计服务以尽可能容忍其供应商的变化来避免大量的版本控制。

微服务是未来吗?

我们撰写本文的主要目的是解释微服务的主要思想和原则。通过花时间来做这件事,我们清楚地认为微服务架构风格是一个重要的理念 - 值得企业应用程序认真考虑。我们最近使用这种风格构建了几个系统,并且知道其他人也使用并喜欢这种方法。

据我们所知,在某种程度上开创这种架构风格的公司包括亚马逊、Netflix、《卫报》、英国政府数字服务realestate.com.au、Forward 和comparethemarket.com。2013 年的会议电路充满了正在转向我们所说的微服务的公司的例子 - 包括 Travis CI。此外,还有很多组织长期以来一直在做我们所说的微服务,但从未使用过这个名称。(通常这被称为 SOA - 尽管,正如我们所说,SOA 有许多相互矛盾的形式。[14]

然而,尽管有这些积极的经验,但我们并不认为我们确信微服务是软件架构的未来方向。虽然与单片应用程序相比,我们迄今为止的经验是积极的,但我们意识到,我们还没有足够的时间来做出全面的判断。

通常情况下,您架构决策的真正后果只有在您做出决策几年后才会显现出来。我们见过一些项目,其中一个优秀的团队,强烈希望实现模块化,却构建了一个多年来一直在衰败的单片架构。许多人认为,这种衰败在微服务中不太可能发生,因为服务边界是明确的,并且难以修补。然而,在我们看到足够多的系统具有足够的年龄之前,我们无法真正评估微服务架构是如何成熟的。

当然,我们有理由认为微服务架构在发展成熟的过程中会变得糟糕。任何组件化工作,其成功都取决于软件与组件的契合程度。很难确切地找出组件边界应该在哪里。演进式设计认识到正确划分边界很困难,因此,易于重构边界至关重要。但是,当您的组件是通过远程通信的服务时,重构就比使用进程内库要难得多。跨服务边界移动代码很困难,任何接口更改都需要在参与者之间进行协调,需要添加向后兼容层,并且测试也变得更加复杂。

我们的同事 Sam Newman 在 2014 年的大部分时间里都在写一本书,记录了我们构建微服务的经验。如果您想深入了解这个主题,这应该是您的下一步。

另一个问题是,如果组件不能整齐地组合,那么您所做的只是将复杂性从组件内部转移到组件之间的连接。这不仅会将复杂性转移到其他地方,还会将其转移到一个不那么明确且更难控制的地方。当您查看一个小型、简单的组件内部时,很容易认为事情变得更好了,而忽略了服务之间混乱的连接。

最后,还有团队技能的因素。新技术往往会被技能更高的团队采用。但是,对技能更高的团队更有效的技术不一定对技能较低的团队有效。我们已经看到很多技能较低的团队构建混乱的单体架构的案例,但要想知道当这种混乱发生在微服务中时会发生什么,还需要时间。糟糕的团队总是会创建糟糕的系统——很难说在这种情况下,微服务是减少了混乱还是使情况变得更糟。

我们听到的一个合理的论点是,您不应该从微服务架构开始。而是从单体架构开始,保持其模块化,并在单体架构成为问题时将其拆分为微服务。(尽管这个建议并不理想,因为良好的进程内接口通常不是良好的服务接口。)

因此,我们在撰写本文时持谨慎乐观的态度。到目前为止,我们已经对微服务风格有了足够的了解,认为它可以成为一条值得走的道路。我们不能确定最终会走向何方,但软件开发的挑战之一是,您只能根据当前掌握的不完整信息做出决策。


脚注

1: “微服务”一词是在 2011 年 5 月威尼斯附近的一次软件架构师研讨会上讨论的,用于描述参与者认为许多人最近一直在探索的一种通用架构风格。2012 年 5 月,同一组人决定将“微服务”作为最合适的名称。James 在 2012 年 3 月克拉科夫举行的第 33 届大会上以案例研究的形式介绍了其中的一些想法,微服务 - Java,Unix 之道,Fred George 也大约在同一时间介绍了这些想法。Netflix 的 Adrian Cockcroft 将这种方法描述为“细粒度 SOA”,他与本文中提到的许多其他人一样,都在网络规模上开创了这种风格——Joe Walnes、Daniel Terhorst-North、Evan Botcher 和 Graham Tackley。

2: “单体架构”一词在 Unix 社区中已经使用了一段时间。它出现在《Unix 编程艺术》中,用于描述变得过大的系统。

3: 许多面向对象的设计人员(包括我们自己)在领域驱动设计中使用“服务对象”一词来表示执行与实体无关的重要流程的对象。这与我们在本文中使用“服务”的方式是不同的概念。遗憾的是,“服务”一词具有这两种含义,我们必须接受这种多义性。

4: 我们认为应用程序是一种社会结构,它将代码库、功能组和资金主体绑定在一起。

5: 我们不得不提到 Jim Webber 的说法,ESB 代表“错误的意大利面条盒”

6: Netflix 明确了这种联系——直到最近,他们还将自己的架构风格称为细粒度 SOA。

7: 在极端规模下,组织通常会转向二进制协议——例如protobufs。使用这些协议的系统仍然表现出智能端点、哑管道——并以牺牲_透明度_来换取规模。大多数 Web 属性,当然也包括绝大多数企业,都不需要做出这种权衡——透明度可以带来巨大的胜利。

8: “YAGNI”或“您不会需要它”是XP 原则,它告诫人们在知道自己需要某个功能之前不要添加它。

9: 我们声称单体架构是单一语言,这有点不诚实——为了在当今的网络上构建系统,您可能需要了解 JavaScript、XHTML、CSS、您选择的服务端语言、SQL 和 ORM 方言。几乎不是单一语言,但您知道我们的意思。

10: Adrian Cockcroft 在 2013 年 11 月 Flowcon 大会上发表的这篇精彩演讲中特别提到了“开发者自助服务”和“开发者运行他们编写的内容”。

11: 我们在这里有点不诚实。显然,在更复杂的拓扑中部署更多服务比部署单个单体架构更困难。幸运的是,模式减少了这种复杂性——但仍然必须在工具方面进行投资。

12: 事实上,Daniel Terhorst-North 将这种风格称为_可替换组件架构_,而不是微服务。由于这似乎是指我们更喜欢的后者的一个子集。

13: Kent Beck 在《实现模式》中强调这是他的设计原则之一。

14: SOA 并不是这段历史的根源。我记得在本世纪初 SOA 一词出现时,人们说“我们已经这样做很多年了”。一种说法是,这种风格的根源可以追溯到企业计算的早期,当时 COBOL 程序通过数据文件进行通信。从另一个角度来看,可以说微服务与 Erlang 编程模型是一回事,只是应用于企业应用程序环境。

参考文献

虽然这不是一个详尽的列表,但有一些资料来源是实践者从中汲取灵感的,或者与本文中描述的理念相似。

博客和在线文章

书籍

演示文稿

论文

  • L. Lamport,“可靠分布式多进程系统的实现”,1978 年 http:// research.microsoft.com/en-us/um/people/lamport/pubs/implementation.pdf
  • L. Lamport、R. Shostak、M. Pease,“拜占庭将军问题”,1982 年(可在以下网址获取)http:// www.cs.cornell.edu/courses/cs614/2004sp/papers/lsp82.pdf
  • R.T. Fielding,“架构风格和基于网络的软件架构设计”,2000 年 http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
  • E. A. Brewer,“迈向健壮的分布式系统”,2000 年 http://www.cs.berkeley.edu/ ~brewer/cs262b-2004/PODC-keynote.pdf
  • E. Brewer,“CAP 十二年后:‘规则’如何改变”,2012 年,http:// www.infoq.com/articles/cap-twelve-years-later-how-the-rules-have-changed

扩展阅读

以上列表是我们最初在 2014 年初撰写本文时使用的参考资料。有关更多信息的最新资料来源列表,请查看微服务资源指南

重大修订

2014 年 3 月 25 日:关于微服务是否是未来的最后一部分?

2014 年 3 月 24 日:添加了关于演进式设计的章节

2014 年 3 月 19 日:添加了关于基础设施自动化和故障设计的章节

2014 年 3 月 18 日:添加了关于去中心化数据的章节

2014 年 3 月 17 日:添加了关于去中心化治理的章节

2014 年 3 月 14 日:添加了关于智能端点和哑管道的章节

2014 年 3 月 13 日:添加了关于产品而非项目的章节

2014 年 3 月 12 日:添加了关于围绕业务能力进行组织的章节

2014 年 3 月 10 日:发布第一部分