Libx

【译】micor services

字数统计: 11,253阅读时长: 39 min
2020/03/05 Share

MicorServices

原文:MicorServices by Martin FLower 原文
翻译: libx

微服务

有关这个新的技术架构术语的定义:
“微服务架构”这个术语最近几年横空出世,来描述一种特定的软件设计方法:以若干组可以独立部署的服务进行软件应用系统的设计。虽然这种架构风格还没有较为准确的定义,但其在下述方面还是存在一定的共性:即围绕业务功能的组织、自动化部署、端点智能、和在编程语言和数据方面进行去中心化的控制。

目录

  • 微服务体系结构的特征
    • 通过服务(Services)的组件化(Componentization)
    • 围绕业务功能来组织团队
    • ‘做产品’而非’做项目’
    • 智能终端和傻瓜管道
    • 去中心化治理技术
    • 数据去中心化
    • 基础设施自动化
    • 容错设计
    • 演进式设计
  • 微服务是未来的趋势吗?

“微服务”– 这是在软件架构这条拥挤的大街上出现的又一个新词。虽然我们自然会倾向用轻蔑的眼光忽略这些东西,但是他所描述的软件系统风格,越来越吸引我们的注意。在过去几年中,我们可以看到许多项目开始使用这种风格,以至于我们身边的同事在构建企业级的应用时,会把它认为是一种理所应当的默认开发形式。但很不幸的是:微服务风格到底是什么,应该怎么开发,详细的理论描述却并不多。

简而言之:微服务架构风格【1】,就像是把一个单独的应用程序开发为一组小的服务来开发的方法。每个小服务都在自己的进程中运行,并且使用轻量级机制(通常是http的api)来进行通信。这些服务是围绕着业务功能构建的,可以通过完全自动化的部署机制进行独立的部署。这些服务的集中管理很少,可能使用不同的编程语言,使用不同的数据存储技术。

我的微服务资源指南提供了关于微服务的最佳文章、书籍、视频、和博客的链接。

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

这样的单块服务是构建这样一个系统的很自然的方式。处理请求的所有逻辑都在单个进程中运行,可以使用语言层面的基本特性来把程序划分类、函数、和命名空间。你可以小心的在开发人员身边运行和测试应用程序,并且通过部署管道来确定能够正确的测试更改并且将其部署到生产环境。通过在LB后面运行多个实例,可以水平的扩展整体。

单片应用程序可以获得成功,但是人们越来越对它们感到失望——尤其是越来越多的应用程序被部署到云上。更改周期被捆绑在一起——对应用程序的一小部分进行更改,需要重新构建和部署整个整体。随着时间的推移,通常很难保持一个良好的模块结构,这使得某个更改的影响范围越来越大,很难控制在某个模块内。当对系统进行扩展时,不得不扩展整个应用系统,而不能仅扩展该系统中需要更多资源的那些部分。
sketch.png

单块应用和微服务

这些问题导致了微服务架构风格的诞生:将应用程序构建为服务套件(一组服务)。除了服务是可以独立部署和可扩展之外。每个服务还提供了一个可靠的模块边界。甚至能够允许使用不同的编程语言来编写不同的服务,这些服务也能够被不同的团队来管理。

我们并不认为微服务风格是创新的。他的根源至少可以追述到Unix的设计原则。但是我们认为确实没有足够多的人在考虑使用微服务架构,如果加以使用,很多软件在开发起来会好很多。

微服务体系结构的特性

虽然我们还不能说微服务体系结构风格有一个正式的定义,但是我们可以尝试去描述我们所看到的符合这个标签的体系结构的共同特征。与任何概述公共特征的定义一样,并非所有微服务体系结构都具有所有特征,但我们确实希望大多数微服务体系结构都具有大多数特征。虽然我们作者一直是这个相当松散的社区的活跃成员,但我们的意图是尝试描述我们在自己的工作和我们所知道的团队的类似工作中看到的内容。特别需要指出的是,我们并不会制定一些大家都需要遵循的微服务的定义。

通过服务(Services)的组件化(Componentization)

自从我们开始涉足软件行业以来,大家都有一种把组件连接在一起来构建系统的愿望,就像我们为您在现实世界看到的东西一样。在过去的几十年里,我们可以看到相当大的进步,一些公共软件库是大多数编程语言平台的组成部分。

在讨论组件时,我们会遇到关于组件定义的难题。我们的定义是:组件是一个可以独立更换和升级的软件单元。

微服务架构也会使用软件库,但组件化软件的主要方式是把它拆分成服务。我们把库(libraries)定义为组件,这些组件被链接到程序,并通过内存中函数调用(in-memory function calls)来调用,而服务(services )是进程外组件(out-of-process components),他们利用某个机制通信,比如 WebService 请求,或远程过程调用(remote procedure call)。组件和服务在很多面向对象编程中是不同的概念。

以使用服务而不是组件库来实现组件化的主要原因是:服务可以独立部署。如果应用程序【4】是由一个在单个进程中的多个软件库组成,那么对其任何一个组件进行修改,都需要重新部署整个应用系统。但是如果把应用程序分解为多个服务,那就可以预期到单个服务的更改,并且只需要重新部署该服务。这并不是绝对的,一些更改可能也会更改接口,需要多个服务进行协调。但是良好的微服务体系结构的目标是通过内聚服务边界和演化机制来最小化这些接口。

使用服务作为组件的另一个结果是更显式的组件接口。大多数语言都没有定义显示发布接口的良好机制。通常,通常情况下,这样的接口仅仅是文档声明和团队纪律,来避免客户端破坏组件的封装,从而导致组件间出现过度紧密的耦合。通过使用显式的远程调用机制,服务能更容易地避免这种情况发生。

使用这样的服务也确实有不足之处。比起进程内的调用,远程调用的成本更加昂贵,因此远程调用API必须是粗粒度的,而使用粗粒度的API通常会更困难。如果你需要更改组件之间的职责分配,则此类行为的改动会更加难以实现。

近似情况下,我们可以观察到服务映射到运行时流程,但这只是第一个近似情况。一个服务可能包含多个总是一起开发和部署的进程,例如一个应用程序流程和一个只由该服务使用的数据库。

围绕“业务功能”组织团队

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

任何设计(广义上的)系统的组织,都会产生这样一个设计,即该设计的结构与该组织的沟通结构相一致。
——梅尔文•康威(Melvyn Conway), 1967年

conways-law.png

图二:Conway’s Law在起作用

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

PreferFunctionalStaffOrganization.png
图3:由团队边界加强的服务边界

以上述方式来组织团队的公司是www.comparethemarket.com。跨职能团队负责构建和运维每个产品,而每个产品被拆分为多个独立的服务,彼此通过一个消息总线来通信。

一个微服务应该有多大?
虽然“微服务”已经成为这种体系结构风格的一个流行名称,但它的名称确实导致了对服务大小的关注,以及关于什么构成“微”的争论。在与微服务从业人员的对话中,我们看到了各种规模的服务。据报道,最大尺寸的披萨符合亚马逊的概念,即两个披萨团队(即整个团队可以吃两个披萨):不超过12人。在规模较小的情况下,我们已经看到了一个6人的团队将支持6个服务。
这就引出了一个问题:在这个规模范围内是否存在足够大的差异,以至于不应该将每12人服务和每人服务的规模集中在一个微服务标签下。目前我们认为最好将它们组合在一起,但随着我们进一步探索这种风格,我们当然有可能改变主意。

有一个这样组织的一个公司是www.comparethemarket.com。跨功能团队负责构建和操作每个产品,每个产品被分解为许多通过消息总线进行通信的单个服务。

大型单片应用程序也可以围绕业务功能进行模块化,尽管这并常见。当然,我们会敦促大型团队构建一个独立的应用程序,并将其按照业务线进行划分。这里的主要问题是,它们往往是围绕着太多的上下文来组织的。如果一个整体跨越了许多这样的模块边界,那么团队中的个别成员就很难将它们放入他们的短期记忆中。此外,我们看到,模块化的路线需要大量的纪律执行。服务组件必需的更显式的分离使得保持团队边界清晰更容易。

“做产品”而非”做项目”

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

微服务的支持者倾向于避免这种模式,他们更倾向于认为一个团队应该在其整个生命周期内拥有一个产品。这一点来自Amazon的“谁构建,谁运行”的概念,在这个概念中,开发团队对生产中的软件承担全部责任。这将使开发人员与他们的软件在生产中的行为进行日常联系,并增加与用户的联系,因为他们必须承担一部分支持工作。

这样的’产品’心态,是与业务能力联系在一起的。他不是将软件视为一组要完成的功能,而是将其视为一种持续的关系:软件如何帮助其用户持续增强业务能力。

同样的方法也可以用于单片应用程序,但是较小粒度的服务可以更容易地在服务开发人员和他们的用户之间创建个人关系。

“智能端点”与“傻瓜管道”

当在不同的进程之间构建通信结构时,已经有了许多产品和方法,来强调将大量的智能特性纳入通信机制本身。一个典型例子就是“企业服务总线”(Enterprise Service Bus, ESB)。ESB产品经常包括高度智能的工具,来进行消息的路由、编制(choreography)、转换,并应用业务规则。

微服务社区主张采用另一种做法:智能端点(smart endpoints)和傻瓜管道(dumb pipes)。采用单独的业务逻辑,表现的更像经典Unix意义上的过滤器一样,接受请求、处理业务逻辑、返回响应。它们更喜欢简单的REST风格,而不是复杂的协议,如WS或者BPEL或者集中式框架。

Microservices和SOA

当我们谈到微服务时,一个常见的问题是:这是否是我们十年前看到的面向服务的体系结构(SOA)。这一点是有讨论价值的,因为微服务风格与一些SOA倡导者所支持的非常相似。然而,问题在于SOA有着太多不同的东西,而且大多数时候我们遇到的所谓的“SOA”与我们在这里描述的风格有很大的不同,这通常是由于对用于集成单一应用程序的esb的关注。

特别是我们已经看到这么多糟糕的实现面向服务——从倾向于隐藏复杂性在ESB的[6],多年的计划失败,数以百万计的成本和交付没有价值,集中治理模式,积极抑制变化,有时很难看到过去的这些问题。

当然,微服务社区中使用的许多技术都来自于在大型组织中集成服务的开发人员的经验。容忍阅读器模式就是一个例子。使用web的努力是有贡献的,使用简单的协议是从这些经验中得到的另一种方法——一种远离中心标准的反应,坦率地说,已经达到了令人惊叹的复杂性。(任何时候你需要一个本体论来管理你的本体论,你知道你有大麻烦了。)>
SOA的这种常见表现已经导致一些微服务倡导者完全拒绝了SOA的标签,尽管其他人认为微服务是SOA[7]的一种形式,可能是正确的面向服务。不管怎样,SOA意味着如此不同的东西,这一事实意味着有一个更明确定义这种体系结构风格的术语是有价值的。

微服务最常用的两种协议是:带有资源API的HTTP“请求-响应”协议,和轻量级的消息发送协议[6]。对于前一种协议的最佳表述是:

善于利用网络,而不是限制(Be of the web, not behind the web)。
——Ian Robinson

微服务团队使用的是构建万维网时所使用的原则和协议(并且在很大程度上,这些原则和协议也是在构建Unix系统时所使用的)。那些被使用过的HTTP资源,通常能被开发或运维人员轻易地缓存起来。

第二种常用的方法是通过轻量级消息总线进行消息传递。基础设施的选择通常是傻瓜型的(仅仅像是充当消息路由器)——简单的实现如RabbitMQ或ZeroMQ,除了提供一个可靠的异步机制以外不需要做其他的事情——主要的功能只存在于生产和消费的端点中,也即在各个服务中。

在一个单块系统中,组件是在一个进程中执行的,它们之间的通信是通过方法调用或函数调用进行的。把一个庞然大物变成微服务的最大问题在于改变通信模式。从内存中方法调用到RPC的简单转换会导致通信混乱,性能不佳。相反,您需要将细粒度的通信替换为粗粒度的方法

去中心化治理技术

集中化治理的后果之一酒是在单一技术平台上标准化的趋势。经验表明,这种方法是有局限性的——不是所有的问题都是钉子,也不是所有的解决方案都是锤子。我们更喜欢使用正确的工具来完成工作,虽然单块程序可以在一定程度上利用不同的语言,但这并不常见。

如果能将单块应用的的组件拆分成多个服务,那么在构建每个组件时都有选择不同技术栈的机会。您想使用Node.js来建立一个简单的报告页面吗?就去做吧。一个近实时组件的c++ ?很好。您想要交换一个不同风格的数据库,以更好地适应一个组件的读取行为吗?可以重建。

当然,可以做并不意味着应该这样,但是以微服务来拆分系统意味着您有这个选项。

相比使用业界常见的技术,构建微服务的团队更喜欢采用不同的方法。与其使用一组写在纸上的定义标准,他们更喜欢开发一些有用的工具,并且让其他开发者能够使用。这些工具通常源自于微服务实施过程中,并与更广泛的组共享,但不完全使用内部开源模型。现在git和github已经成为事实上的版本控制系统的选择,开源实践在企业内部也变得越来越普遍。

Netflix就是遵循这一理念的一个很好的例子。共享有用的、最重要的、经过实战测试的代码,能鼓励其他开发人员以类似的方式解决类似的问题,如果需要,也可以选择不同的方法。共享库往往集中在数据存储、进程间通信以及基础设施自动化等常见问题上。

微服务社区中,成本问题特别引人注意。这并不是说,社区不认为服务交互的价值。相反,正是因为发现到它的价值。这使得他们在寻找各种方法来解决它们。如Tolearant ReaderConsumer-Driven Contracts这样的设计模式就经常被微服务使用。模式通常应用于微服务。这些援助服务合同是独立发展的。作为构建的一部分执行消费者驱动的契约可以增强开发团队的信心,并提供关于所依赖的服务是否正常运行的快速反馈。 实际上,我们了解到澳大利亚有一个团队利用Consumer-Driven Contracts模式来推动新服务的构建。他们使用简单的工具来定义服务的契约。在编写新服务的代码之前,这就成为自动构建的一部分。然后,服务只构建到满足契约的那一点上——这是在构建新软件时避免“YAGNI”[9]困境的一种优雅方法。这些技术和围绕它们发展起来的工具通过减少服务之间的时间耦合来限制对中央契约管理的需求。

或许,亚马逊(Amazon)普及的“构建it /运行it”(build it / run it)精神,才是去中心化治理的顶点。团队对他们构建的软件的所有方面负责,包括24/7的软件操作。这种级别的责任下放绝对不是常态,但我们确实看到越来越多的公司将责任推给开发团队。Netflix是另一家采纳了这种精神的公司【11】。在编写代码时,每天凌晨3点被寻呼机叫醒无疑是关注代码质量的强大动力。这些想法与传统的集中式治理模型相去甚远。

数据管理去中心化

去中心化地管理数据,其表现形式多种多样。在最抽象的层次上来看,这意味着各个系统对客观世界所构建的概念模型,将各不相同。这是大型企业进行系统集成时的常见问题,客户的销售视角和将与支持者的视角不同。有些在sales视图中称为customers的东西可能根本不会出现在support视图中。这样做可能会有不同的属性和具有微妙不同语义的公共属性。

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

“实战检验”的标准与“强制执行”的标准

微服务团队倾向于避开由企业架构组制定的严格执行的标准,而乐于使用甚至宣传使用开放标准,如HTTP、ATOM和其他微格式,这有点矛盾。
关键的区别在于标准是如何制定和如何执行的。像IETF这样的组织管理的标准只有在更广泛的世界中有几个实时实现的情况下才会成为标准,而且这些标准通常来自成功的开源项目。
这些标准与企业世界中的许多标准截然不同,企业世界中的许多标准通常是由最近几乎没有编程经验或过度受供应商影响的团队开发的。

如同在概念模型上进行去中心化的决策一样,微服务也在数据存储上进行去中心化的决策。尽管各个单块应用更愿意在逻辑上各自使用一个单独的数据库来持久化数据,但企业通常更喜欢跨一系列应用程序使用单个数据库——其中许多决策是由供应商围绕许可的商业模型驱动的。微服务更喜欢让每个服务管理自己的数据库,要么是相同数据库技术的不同实例,要么是完全不同的数据库系统——这种方法称为多语言持久性。您可以在一个整体中使用polyglot持久性,但是它在微服务中出现得更频繁。
PreferFunctionalStaffOrganization.png
将数据的责任分散到各个微服务上对管理更新有一定的影响。处理更新的常用方法是在更新多个资源时使用事务来保证一致性。这种方法通常用于单块系统。

使用这样的事务有助于保持一致性,但会带来重大的时间耦合,这在多个服务之间是有问题的。众所周知,分布式事务是非常难以实现的,因此微服务体系结构强调服务之间的无事务协调,明确地认识到一致性可能只是要求数据最终的一致性,并且一致性问题是通过补偿操作来处理的。

对于许多开发团队来说,选择以这种方式管理数据的不一致性是一个新的挑战,但它通常与业务实践相匹配。通常,企业处理一定程度的不一致性是为了快速响应需求,同时使用某种反转过程来处理错误。只要修复错误的成本小于在更大的一致性下丢失业务的成本,这种权衡就是值得的。

“基础设施”自动化

基础设施自动化技术在过去几年里有了巨大的发展——特别是云计算和AWS的发展降低了构建、部署和运行微服务的操作复杂性。

许多使用微服务构建的产品或系统都是由具有丰富的持续交付和持续集成经验的团队构建的。以这种方式构建软件的团队广泛使用了基础设施自动化技术。basic-pipeline.png

图5: basic build pipeline

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

让做正确的事情变得容易

作为持续交付和部署的结果,我们发现自动化程度提高的一个副作用是创建了有用的工具来帮助开发人员和操作人员。用于创建人工制品、管理代码库、支持简单服务或添加标准监视和日志记录的工具现在非常常见。网络上最好的例子可能是Netflix的一套开源工具,但也有其他的,包括我们广泛使用的Dropwizard。

一个单块应用程序将会在这些环境中非常随意地构建、测试和发布。事实证明,一旦你打算为一个整体实现生产路径的自动化,那么部署更多的应用程序就不再那么可怕了。请记住,CD的目标之一是让部署变得乏味,因此无论它是一个还是三个应用程序,只要它仍然是乏味的,[12]都没有关系。

我们看到一些团队使用广泛的基础设施自动化的另一个领域是在生产中管理微服务。与我们上面的断言不同,只要部署是乏味的,那么单体和微服务之间就没有那么大的差别,每种服务的操作环境都可能是截然不同的。

micro-deployment.png
图6:模块部署通常是不同的

容错设计

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

由于服务可能在任何时候出现故障,因此能够快速检测故障并在可能的情况下自动恢复服务非常重要。微服务应用程序非常强调应用程序的实时监控,检查体系结构元素(数据库每秒获得多少请求)和业务相关指标(例如每分钟接收多少订单)。语义监视可以提供出错的早期预警系统,从而触发开发团队进行跟踪和调查。

这对于微服务体系结构尤其重要,因为微服务对编排和事件协作的偏好会导致紧急行为。虽然许多权威人士对偶发事件的价值持积极态度,但事实是,突发性为有时可能是一件坏事。对于快速发现不良的紧急行为是至关重要的,这样才能对其进行修复。

被认为有害的同步调用
任何时候,只要服务之间有大量的同步调用,就会遇到停机的乘法效应。简单地说,这就是系统的停机时间变成各个组件停机时间的产物的时候。您面临一个选择,是异步调用还是管理停机时间。在www.guardian.co.uk,他们在新平台上实现了一个简单的规则——每个用户请求一个同步调用;而在Netflix,他们重新设计的平台API已经在API结构中构建了异步性。

单块系统可以被建造得像微服务一样透明——事实上,它们应该是透明的。不同之处在于,您绝对需要知道在不同进程中运行的服务何时断开连接。如果库在相同的过程中,这种透明性就不太可能有用。

微服务团队希望看到每个单独服务的复杂监视和日志设置,比如显示显示/关闭状态的仪表板以及各种操作和业务相关的度量。关于断路器状态、电流吞吐量和延迟的详细信息都是我们经常遇到的例子。

演进式设计

微服务的实践者,通常来自于演进式设计的背景,并将服务分解看作是使应用程序开发人员能够控制其应用程序中的更改而不减慢更改的进一步工具。控制变更并不一定意味着减少变更——通过正确的态度和工具,可以对软件进行频繁、快速和控制良好的变更。

当试图将一个软件系统分解成多个组件时,就会面临着如何分割这些组件的决定——决定分割应用程序时所依据的原则是什么?组件的关键属性是独立替换和可升级性[13]的概念——这意味着我们要寻找这些点,集想象着在不影响其协作者的情况下重写组件。实际上,许多微服务团队会更进一步,他们会明确给出许多服务会被废弃的预期,而不是守着这些服务做长期的演进。

卫报网站是一个很好的例子,它被设计和构建为一个单块系统,但一直在朝着微服务的方向发展。单体仍然是网站的核心,但他们更喜欢通过使用单体的API构建微服务来增加新功能。这种方法对于本质上是临时的特性(比如处理体育赛事的专门页面)特别方便。使用快速开发语言可以快速地将网站的这一部分整合在一起,并在活动结束后将其删除。我们在一家金融机构看到过类似的做法,为了抓住市场机会而增加新服务,但几个月甚至几周后就放弃了。

这种强调可替换性的特点,是模块化设计普遍原则的一个特例,即通过”变化模式”[14]来驱动模块化。您希望将同时更改的内容保存在同一个模块中。一个系统中很少变化的部分应该放在在不同的服务中,以区别那些正经历着大量变化的服务。如果您发现自己反复地同时更改两个服务,那么就说明应该合并它们。

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

微服务是未来的趋势吗?

Microservice权衡
许多开发团队发现微服务体系结构风格是一种优于单一体系结构的方法。但是其他的团队发现他们是一个生产力消耗的负担。与任何建筑风格一样,微服务也带来了成本和收益。为了做出明智的选择,你必须理解这些并将它们应用到你的特定环境中。
由马丁 2015年7月1日

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

据我们所知,在某种程度上引领这种建筑风格的公司包括亚马逊(Amazon)、Netflix、《卫报》(the Guardian)、英国政府数字服务公司realestate.com.au、Forward和comparethemarket.com。2013年的会议上到处都是公司转向微服务的例子,包括Travis CI。此外,有许多组织长期以来一直在做我们称之为微服务的事情,但从未使用过这个名称。(这通常被称为SOA——尽管正如我们所说,SOA有许多相互矛盾的形式。[15])

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

通常,您的架构决策的真正后果只在您做出它们的几年后才显现出来。我们曾经看到过这样的项目:一个优秀的团队,带着对模块化的强烈渴望,构建了一个经过多年衰落的整体架构。许多人认为,微服务不太可能出现这种衰退,因为服务边界是明确的,而且很难修补。然而,直到我们看到足够多的系统和足够长的时间,我们才能真正评估微服务体系结构的成熟程度。

当然,我们有理由认为微服务的成熟程度会很低。在任何组件化的努力中,成功取决于软件在多大程度上适合于组件。很难确定组件边界的确切位置。进化式设计认识到获得正确边界的困难,从而认识到重构它们的重要性。但是,如果您的组件是带有远程通信的服务,那么重构要比使用进程内库困难得多。跨服务边界移动代码是困难的,任何接口更改都需要在参与者之间进行协调,需要添加向后兼容层,测试也变得更加复杂。

我们的同事山姆·纽曼(Sam Newman) 2014年的大部分时间都在写一本书,这本书捕捉了我们构建微服务的经验。如果你想更深入地研究这个话题,这应该是你的下一步。

另一个问题是,如果组件不能干净地组合,那么您所做的就是将复杂性从组件内部转移到组件之间的连接上。这不仅仅是将复杂性转移,它还将复杂性转移到一个不那么明确和难以控制的地方。当您查看一个小的、简单的组件的内部,而忽略了服务之间混乱的连接时,很容易认为情况会更好。

最后,还有团队技能的因素。新技术往往被更熟练的团队采用。但是,对于技术更熟练的团队来说更有效的技术不一定适用于技术较差的团队。我们已经看到了很多不太熟练的团队构建混乱的单体架构的例子,但是我们需要时间来了解当这种混乱发生在微服务上时会发生什么。一个糟糕的团队总是会创造出一个糟糕的系统——很难判断微服务在这种情况下是减少了混乱还是使它变得更糟。

我们听到的一个合理的观点是,不应该从微服务体系结构开始。相反,从一个整体开始,保持它的模块化,一旦这个整体成为一个问题,就把它分割成微服务。(尽管这个建议并不理想,因为良好的进程内接口通常不是良好的服务接口。)

因此,我们怀着谨慎的乐观态度来写这篇文章。到目前为止,我们已经对微服务风格有了足够的了解,我们觉得这是一条值得走的路。我们不能确定我们将在哪里结束,但是软件开发的挑战之一是,您只能根据当前必须提供的不完善的信息做出决策。

脚注

1: 2011年5月,威尼斯附近的一个软件架构师研讨会上讨论了“微服务”这个术语,以描述参与者所看到的一种共同的架构风格,他们中的许多人最近都在探索这种风格。2012年5月,该组织决定将“微服务”作为最合适的名称。2012年3月,James在Krakow的第33届微服务课程(Java, Unix方式)上提出了一些想法,并将其作为一个案例进行了研究,当时Fred George也是这样做的。Netflix的Adrian Cockcroft将这种方法描述为“细粒度的SOA”,正如本文中提到的其他许多人—Joe Walnes、Daniel Terhorst-North、Evan Botcher和Graham Tackley—一样,在web范围内开创了这种风格。

2: Unix社区使用monolith这个术语已经有一段时间了。它出现在Unix编程艺术中,用来描述变得太大的系统。

3:许多面向对象的设计人员,包括我们自己在内,在领域驱动设计的意义上使用术语服务对象来表示一个对象,该对象执行一个不与实体绑定的重要过程。这与我们在本文中使用“服务”是一个不同的概念。遗憾的是,“服务”这个词有两个含义,我们不得不忍受一词多义的情况。

4:我们认为应用程序是一个社会结构,它将代码库、功能组和资金体绑定在一起。原文可以在梅尔文·康威的网站上找到。他说:我们不得不提到Jim Webber说的ESB代表“令人震惊的意大利面盒子”。

7: Netflix明确了这个链接——直到最近才把他们的架构风格称为细粒度的SOA。

8:在极端情况下,组织经常转向二进制协议——例如protobufs。使用这些技术的系统仍然表现出智能端点、哑管道的特点,并且以透明度换取规模。大多数的网站和绝大多数的企业都不需要做这样的权衡——透明度可以是一个巨大的胜利。

9:“YAGNI”或“您不需要它”是XP的原则,并告诫您在知道需要它们之前不要添加特性。

10:我们有点不相信所谓的单一语言——为了在今天的web上构建系统,您可能需要了解JavaScript和XHTML、CSS、您选择的服务器端语言、SQL和ORM方言。不是单一的语言,但你知道我们的意思。

11:在2013年11月的Flowcon大会上,Adrian Cockcroft特别提到了“开发者自助服务”和“开发者运行他们写的东西”(原文如此)。

12:我们在这里有点不礼貌。显然,在更复杂的拓扑中部署更多的服务要比部署单一的实体更困难。幸运的是,模式降低了这种复杂性——但是在工具上的投资仍然是必须的。

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

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

15: SOA并不是这段历史的根源。我记得当SOA这个术语在本世纪初出现时,人们说“我们已经做了很多年了”。有一种观点认为,这种风格的根源在于COBOL程序在早期企业计算中通过数据文件进行通信的方式。从另一个角度来看,可以认为微服务与Erlang编程模型是一回事,但应用于企业应用程序上下文。

引用

Books

Presentations

Papers

  • L. Lamport, “The Implementation of Reliable Distributed Multiprocess Systems”, 1978 http:// research.microsoft.com/en-us/um/people/lamport/pubs/implementation.pdf
  • L. Lamport, R. Shostak, M. Pease, “The Byzantine Generals Problem”, 1982 (available at) http:// www.cs.cornell.edu/courses/cs614/2004sp/papers/lsp82.pdf
  • R.T. Fielding, “Architectural Styles and the Design of Network-based Software Architectures”, 2000 http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
  • E. A. Brewer, “Towards Robust Distributed Systems”, 2000 http://www.cs.berkeley.edu/ ~brewer/cs262b-2004/PODC-keynote.pdf
  • E. Brewer, “CAP Twelve Years Later: How the ‘Rules’ Have Changed”, 2012, http:// www.infoq.com/articles/cap-twelve-years-later-how-the-rules-have-changed
CATALOG
  1. 1. MicorServices
    1. 1.0.1. 微服务
    2. 1.0.2. 目录
  2. 1.1. 微服务体系结构的特性
    1. 1.1.1. 通过服务(Services)的组件化(Componentization)
    2. 1.1.2. 围绕“业务功能”组织团队
    3. 1.1.3. “做产品”而非”做项目”
    4. 1.1.4. “智能端点”与“傻瓜管道”
    5. 1.1.5. 去中心化治理技术
    6. 1.1.6. 数据管理去中心化
    7. 1.1.7. “基础设施”自动化
    8. 1.1.8. 容错设计
    9. 1.1.9. 演进式设计
  3. 1.2. 微服务是未来的趋势吗?
  4. 1.3. 脚注
  5. 1.4. 引用