Close

如何构建微服务

过渡到微服务架构的最佳实践

Chandler Harris 头像
Sten Pittet

的 Cloud 应用概述


假设您的应用是基于一种代码构建的大型单体式应用。该应用一直运行良好,直到后来出现问题。您希望能改进该应用,提高应用弹性、可扩展性并实现独立部署。为此,您需要在微服务的粒度级别上重新考虑该应用的结构。

随着应用的分散程度和复杂性不断加剧,微服务也越来越受欢迎。微服务的指导原则是:通过将应用的业务组件拆分为可相互独立部署和运行的小型服务来构建应用。服务之间关注点的分离被定义为“服务边界”。

服务边界与业务需求以及组织层次结构边界紧密相关。个别服务可能与独立的团队、预算和路线图相关联。部分示例服务边界可能包括“支付处理”和“用户身份验证”服务。微服务不同于传统的软件开发实践。在传统软件开发实践中,所有组件都捆绑在一起。

本文档将引用一家名为“Pizzup”的虚构披萨初创公司来说明微服务在现代软件企业中的应用。

如何构建微服务


第 1 步:从单体式开始

微服务的第一个最佳实践是:您可能不需要这些服务。如果您的应用没有任何用户,那么在构建 MVP 时,业务需求可能会迅速发生变化。这仅仅是由于软件开发的性质以及在确定系统需要提供的关键业务功能时需要依据的反馈周期。微服务会使开销和管理复杂性呈现指数级增长。因此,对于新项目而言,将所有代码和逻辑保存在一个代码库中的开销要小得多,因为这样可以更轻松地移动应用中不同模块的边界。

例如在 Pizzup,我们将从一个待解决的简单问题开始:我们希望客户能够在线订购披萨。

一位 Pizzup 用户说:作为用户,我可以在线订购披萨!
代码库图标
相关资料

微服务与单体式架构

三环图标
查看解决方案

使用 Compass 来管理组件

当我们开始思考订购披萨的问题时,我们会确定在应用中要实现该需求所需的不同功能。我们需要管理可制作的不同披萨的清单,允许顾客挑选一个或多个披萨,办理支付,安排配送时间等。我们可能会决定让客户创建一个帐户,以便他们在下次使用 Pizzup 时再次下单。在与第一批用户沟通之后,我们可能会意识到,实时跟踪配送和移动支持可让我们占据竞争优势。

该图形显示出最终用户和管理员在使用 Pizzup 应用之间存在的差异。

最初的简单需求很快就变成了一系列新功能。

如果对系统所需的不同服务有了深入了解,微服务就能很好地发挥作用。但是,如果没有明确定义应用的核心需求,微服务则很难发挥作用。在微服务中重新定义服务交互、API 和数据结构的成本相当高,因为这通常需要协调更多的灵活因素。我们的建议是,在您收集到足够的用户反馈且有足够的信心掌握客户的基本需求并为之进行规划之前,请务必让一切都保持简单。

需要注意的是:单体式构建可能会导致代码复杂性立马加剧,难以分解成更小的部分。因此,最好能确定清晰的模块,以便后续可将这些模块从整体中提取出来。您也可以一开始就将逻辑与 Web UI 分离,并确保逻辑通过 HTTP 上的 RESTful API 与您的后端进行交互。这样,当您将 API 资源移动至其他服务时,便可更轻松地过渡到微服务。

第 2 步:以正确的方式组织团队

到目前为止,构建微服务似乎主要是一项技术工作。您需要将代码库拆分为多个服务,实现正确的模式以允许优雅降级,并从网络问题中恢复,处理数据一致性,监控服务负载等。这其中涉及许多需要掌握的新概念。但最重要且不容忽视的一点是,您需要重构团队的组织方式。

康威定律是真实存在的,并且适用于所有类型的团队。如果一个软件团队由一个后端团队、一个前端团队和一个独立工作的运营团队组成,这个软件团队将提供独立的前端和后端单体,而这些单体会被扔给运营团队随后投入生产。此类团队结构并不适合微服务,因为每项服务都应被视为自己的产品,需要独立于其他服务进行交付。

相反,您应该创建规模较小的 DevOps 团队,这些团队具备所有开发和维护的能力以满足他们所负责的服务。以此方式组织您的团队大有益处。首先,开发人员可以更好地理解他们的代码在生产中所产生的影响,这有助于他们开发出更好的版本,并降低客户发现问题的风险。其次,部署成为每个团队的第二天性,因为他们会共同改进代码,并实现部署管道的自动化。

第 3 步:拆分单体式结构,构建微服务架构

确定服务的边界并弄清楚如何重建团队后,您就可以着手拆分单体式架构,以便构建微服务。在此阶段,您需考虑以下要点。

使用 RESTful API 简化服务之间的通信

如果您还没有使用 RESTful API,现在正是大好时机。正如 Martin Fowler 所说,您想拥有“智能端点与管道扁平化”。这意味着服务之间的通信协议应该尽可能简单,仅负责传输数据而不进行转换。这种神奇的事情发生在端点本身 – 由端点来接收请求、处理请求并做出响应。

微服务架构力求使操作尽可能简单,从而避免组件的紧密耦合。在某些情况下,您可能会发现自己正在使用事件驱动的架构,而该架构是基于异步消息的通信。但是,您应该再次研究 RabbitMQ 一类的基本消息队列服务,并避免增加通过网络传输的消息的复杂性。

将数据划分为带边界的上下文或数据域

单体式应用使用单个数据库来存储该应用的所有业务功能。由于单体被分解为微服务,该单一数据库可能不再具有意义。中央数据库可能会成为流量扩展的瓶颈。如果某一特定服务在高负载下访问数据库,则可能会中断其他服务对数据库的访问。此外,如果有多个团队试图同时修改该架构,单个数据库可能会成为这些团队开展协作的瓶颈。这可能需要拆分数据库或添加其他数据存储工具来支持微服务数据需求。

重构单体式数据库架构可能是一项精细操作。明确每个服务需要哪些数据集和所有重叠之处非常重要。这种架构规划可以通过使用带边界的上下文来完成,这是“领域驱动设计”中的一种模式。带边界的上下文定义了一个自包含系统,其中包括可以进入和退出该系统的内容。

在此系统中,当用户访问订单时,您可以在表格中查看客户信息,这些信息还可用于填充开票系统管理的发票。这看似合乎逻辑且简单,但如果采用微服务,这种服务则应该解耦。如此,即使订购系统宕机,也可以访问发票。此外,该系统还允许您独立于其他服务来优化或改进发票表格。每个服务最终都可能拥有自己的数据存储来访问其所需的数据。

这又带来了新的问题,因为某些数据将在不同的数据库中被复制。带边界的上下文可以确定处理共享或重复数据的最佳策略。您可以采用事件驱动架构来协助完成多个服务之间的数据同步。例如,当客户更新其个人信息时,您的开票和配送跟踪服务可能会监听帐户服务发出的事件。收到事件后,这些服务将相应地更新其数据存储。这种由事件驱动的架构能让帐户服务逻辑保持简单,因为它无需知道其他依赖服务。帐户服务只需告诉系统自己做了什么,其他服务便会监听并采取相应的行动。

您还可以选择将所有客户信息保留在帐户服务中,并且只在开票和配送服务中保留外键引用。然后,这些服务与帐户服务进行交互来获取相关的客户数据,而不是复制现有记录。由于这些问题没有通用的解决方案,因此您需要研究每个具体案例以确定最佳方法。

构建微服务架构以应对故障

我们已经了解微服务相对于单体式架构如何为您提供更大优势。微服务体积更小,专业程度高,这使它们更易于理解。微服务处于解耦状态,这意味着您可以重构服务,而不必担心破坏系统的其他组件或妨碍其他团队的开发速度。微服务还为开发人员提供了更大的灵活性,因为他们可以在需要时选择不同的技术,而不会受到其他服务需求的限制。

简而言之,采用微服务架构可以更轻松地开发和维护每项业务功能。但如果从整体查看所有服务并了解它们需要如何交互以完成操作,事情就会变得更加复杂。您的系统现在分布有多个故障点,您需要解决这个问题。您不仅需要考虑服务未响应的情况,还需要考虑处理网络响应缓慢的问题。从故障中恢复有时也很棘手,因为您需要确保重新联机的服务不会被待处理的消息所淹没。

开始从单体式系统中提取功能时,请确保您的设计从一开始就是应对故障而构建的。

重视监控以简化微服务测试

与单体式系统相比,微服务的另一个缺点是测试。作为单个代码库所构建的应用不需要太多就能让一个测试环境启动并运行。大多数情况下,您需要启动后端服务器以及配套数据库以运行测试套件。

在微服务世界中,事情就没那么简单了。在涉及到单元测试时,微服务仍然与单体式非常相似,在此层面您不会有什么额外的烦恼。但是,在集成和系统测试方面,事情将变得更加困难。您也许不得不一次使用多个服务,启动并运行不同的数据存储,并且您的设置可能需要包含单体式不需要的消息队列。在此情况下,运行功能测试会花费更高的成本,而且灵活因素也会增加,这样就很难预测可能发生的不同类型的故障。

监控可以及早发现问题,并让您做出相应的反应。您需要了解不同服务的基准,不仅要在服务停机时做出反应,还要在这些服务出现意外时做出反应。采用微服务架构的一个优势是,您的系统应该能够应对局部故障。因此,即便您开始注意到我们的 Pizzup 应用在配送跟踪服务中出现异常,该应用也不会像单体式系统那样糟糕。我们的应用设计思路是:在恢复实时跟踪的同时,让其他所有服务都能正确响应,并让我们的客户能够订购披萨。

采用持续交付,减少部署摩擦

手动将单体式系统发布到生产环境是一项繁琐且冒险的工作,虽然也可以实现。当然,我们不建议使用这种方法,而是鼓励每个软件团队都采用持续交付来进行所有类型的开发。但在项目开始时,您可能需要通过命令行自行进行首次部署。

如果您需要每天多次部署越来越多的服务,这种方法便失去了可持续性。因此,作为向微服务过渡的一部分,您必须采用持续交付以降低发布失败的风险,并确保您的团队专注于构建和运行应用,而不是困在应用的部署中。采用持续交付还意味着您的服务在投入生产之前便已通过验收测试。当然也会出现缺陷,但随着时间的推移,您会逐渐构建一个强大的测试套件,这将增强团队对发布质量的信心。

运行微服务不是一场冲刺


微服务是一种热门且被广泛采用的行业最佳实践。对于复杂的项目,微服务为构建和部署软件提供了更高的灵活性。微服务还有助于确定和规范系统的业务组件,当您有多个团队在同一应用上工作时,这种功能就会派上用场。但是,管理分布式系统也存在一些明显的缺点,只有在清楚了解服务边界的情况下,才能拆分单体式架构。

构建微服务应被视为一个长期过程,而不是团队的近期目标。从小处着手,了解分布式系统的技术要求、如何优雅降级以及如何扩展单个组件。然后,随着经验和知识的积累,您可以逐步提取更多服务。

迁移到微服务架构不需要一次全部完成。采用迭代策略,将较小的组件次第迁移至微服务是更为安全的一种选择。在已建立的单体式应用中定义最明确的服务边界,然后反复将它们解耦到自己的微服务中。

总之......


简单概括一下,微服务是一种既有利于原始技术代码开发流程又有利于整体业务组织战略的策略。微服务有助于将团队组织成专注于开发和拥有特定业务职能的单元。这种精细化的重点发力改善了整体业务的沟通和效率。微服务的好处需要权衡取舍。在迁移到微服务架构之前,必须明确定义服务边界,这一点很重要。

虽然微服务架构有很多好处,但也会增加复杂性。Atlassian 开发了 Compass,它旨在帮助公司在扩展分布式架构时管理其复杂性。它是一个可扩展的开发人员体验平台,可将有关工程产出及团队协作的分散信息整合到一个集中且可搜索的位置。

Sten Pittet
Sten Pittet

我从事软件行业已有 10 年了,担任过从开发到产品管理的各种职务。过去五年,我在 Atlassian一直从事开发人员工具方面的工作,现在在写关于构建软件的文章。在工作之外,我喜欢与我的孩子一起共度美好时光。


分享这篇文章
下一个主题

推荐阅读

将这些资源加入书签,以了解 DevOps 团队的类型,或获取 Atlassian 关于 DevOps 的持续更新。

Devops 示意图

Compass 社区

克服障碍插图

教程:创建组件

地图插图

免费试用 Compass

注册以获取我们的 DevOps 新闻资讯

Thank you for signing up