当您公司的整体Web应用变得太大而脆弱时,部署变得缓慢而令人恐惧。因此,作为一家软件公司,您已决定遵循许多其他公司所采用的方法——将这个整体/单体架构拆分为微服务架构。

这个迁移旅程可能漫长而艰难,潜伏着许多错误的踩坑,以及您想要避免的路径。我自己经历过,也许我的经验可以提供帮助。

1. 你不知道你为什么采用微服务

对于所有涉及的工作,微服务提供了许多好处。毕竟,这就是贵公司采用它们的原因。

所以告诉我...什么是那些好处?为什么贵公司要转向微服务?

如果你不知道它们是什么,你就不会看到它们的好处!

尽管您可以通过微服务获得所有收益,但您将面临增加的成本、复杂性和痛苦。不幸的是,当您开始部署微服务时,收益不会神奇地实现。取而代之的是,您需要将注意力集中在您试图解决的挑战上,并确保您不断朝着解决这些挑战的方向前进。这不仅意味着提前规划,还意味着在此过程中进行路线修正。

此外,这意味着做出一些根本性的改变——技术和组织方面的改变。微服务的许多最大好处不在于微服务本身,而在于它们释放的非技术优势。

换句话说,如果您一开始不知道为什么要构建微服务,那么您将遭受所有的痛苦而一无所获。

它实际上可能不值得!

在决定采用微服务之前,您需要检查权衡。看看您现在作为一个组织所处的位置。盘点您当前面临的挑战,并具体确定您期望微服务如何提供帮助。一旦您清楚地了解您希望获得的好处,您就可以权衡它们与构建和维护微服务的缺点。只有这样,你才能认为这是值得的。

(banq注:这种观点可能隐含大量调查思考和预设,其实只有进入迁移过程这个上下文,你才可能在实施过程中敏捷调整你的预设目标,否则在实施之外观看预设都是看上去很美的花朵,过度设计,过度评估,不敏捷)

2. 你只有一堆微服务,其他什么也没有

在开始使用微服务之前,您已经进行了一些搜索研究:您已经确定微服务是“小型、松散耦合、自包含的软件单元,它们通过 ReST 或其他协议相互通信。“ 或类似的东西。

这就是您所构建的。一堆“小”服务,它们都通过 ReST 相互通信。如果服务需要持久化数据,则它连接到数据库。如果该数据需要在您的移动应用程序中呈现,则 ReST 端点会暴露给外部世界。如果另一个服务需要访问该数据,则会添加另一个 ReST 端点。或者它可以使用移动应用程序使用的相同端点?或者它应该直接与数据库对话?

换句话说,你有一个糟糕的设计,无法维护的混乱。每个微服务都有多种用途。依赖关系向各个方向发展(并且在某个地方有一个循环依赖等待你在生产中大吃一惊)。并且没有办法为不同团队将拥有的不同服务划清界限。

3.您无法对微服务分类

微服务并非都是平等的……或者至少,它们不应该是平等的。存在不同类型的微服务(通常称为微服务构造型)以服务于不同的目的。这些类型的示例包括:

  • 数据服务,仅负责与单个聚合相关联的数据的存储和检索。
  • 与多个数据服务进行通信的编排服务,以存储与多个聚合相关联的数据,或者读回该数据并将其组合为更大的数据结构。
  • Backends-for-frontends (BFFs),向特定客户端发送数据和从特定客户端接收数据。
  • 消息总线使用者,使用和处理来自诸如Kafka之类的消息总线的消息。

并非所有组织都会使用所有类型(例如,GraphQL 减少了对前端专用后端的需求。)但是,在构建第一个微服务之前,组织应该创建将使用的类型目录。

此外,该目录应概述不同构造型之间的依赖关系。最好的方法是为您的架构定义分层层。任何给定的类型都属于单个层。并且层之间的依赖关系仅在一个方向上流动。

这种方法的好处包括:

  • 组织中的每个人都说同一种语言。
  • 它使工程师不必在每次构建新功能时“重新发明轮子”,或者只是猜测他们需要构建哪些服务。
  • 推断任何给定微服务可能具有的依赖关系变得更容易。
  • 它忽略了诸如“我的微服务应该多小?
  • ”之类的问题。
  • 以及“我应该创建多少个微服务?

4. 你正在更换整体中的一部分

好的,你已经确定了你的微服务印象:底层数据服务,中间编排服务,顶层BFF。你的微服务架构有一个深思熟虑的结构。

现在是时候开始分解单体应用并用微服务替换它们了。因此,不幸的是,您选择了一种在团队第一次尝试拆分整体时很常见的方法:您决定拆除单体应用的一个水平层(例如数据访问层),并用微服务取而代之。

这是沮丧和混乱的来源。

虽然看起来好像您正朝着正确的方向前进,但实际上您倒退了一大步。在每一次交互中,你仍然还保留有你的整体/单体架构,而且您必须将这个单体应用连接到您的新微服务,您需要处理新的网络问题。你在单体应用中认为理所当然的事情(比如粗粒度的数据库事务)需要仔细区分。测试将变得更加困难。部署将变得更加危险。

也许最糟糕的是,组织中的人们会开始怀疑这种微服务是否是个好主意。领导会看到所有这些时间和精力花费,但看不到任何好处。作为工程团队,您当然会捍卫自己的努力。你会说,它在未来会得到回报。但暗地里,你们中的许多人也会怀疑这是否是正确的决定。

所以恭喜:您刚刚增加了应用程序的复杂性,并降低了其性能和可预测性。您增加了额外的故障点,并增加了系统的可观察性要求。你已经完成了大量的一次性工作。你对整个努力的信心下降了。

  • 团队所有权自治

上述直接替换数据层方法违背了团队所有权自治,掉数据层的方法会鼓励您的工程组织简单地制作整体数据持久层的小副本。当团队构建其余的服务和流程时,这些服务几乎无法使用。

借助微服务,各个团队应该设计和构建他们需要的服务。他们可以查看他们的问题空间,并设计最能完成工作的应用程序、服务和流程。这些服务和应用程序——连同它们的底层数据库模式——最终可能会与它们的单体应用程序大不相同。

(banq注:也就是说,使用数据层的服务层才更应该被切割成微服务,这种切割是根据康威定理的团队结构决定技术架构的理论,只有首先切割团队,才能实现微服务,最后切割数据层)

 例如:您的公司应该有一个团队负责在线注册。这个团队应该是跨职能的,包括建立新流程所需的任何人员:产品经理,设计师,移动工程师,前端和后端工程师,数据和安全工程师等。该团队现在不仅拥有构建流程的自由在新堆栈中,还要重新发明流程中需要重新创建的任何部分。

5. 你有一个维护一堆“核心服务”的团队

微服务的一大好处是各个团队拥有自己的东西。他们构建、部署、监控服务,并在出现问题时修复它们。团队知道他们拥有的服务的来龙去脉,并以弹性的方式构建它们(毕竟,当服务失败时,团队就会陷入困境!)

因此,本着这种精神,您组建了一个强大的“核心服务”团队。该团队拥有管理“共享”数据的微服务。可能被多个产品团队使用的任何数据(用户、产品等)都由一项核心服务管理。这些产品团队只需进行同步调用即可获取他们需要的任何“核心数据”。

让我们退后一步问:为什么团队要构建和维护自己的服务?一个主要原因是领域专业知识。团队——尤其是跨职能团队——通常拥有设计、构建和管理与其特定领域相关的服务和应用程序的综合知识。这就是为什么团队(或应该)围绕他们提供的垂直功能组建:产品搜索;购物车结账;帐单;等等。

相比之下,“核心服务”团队不提供特定的领域知识。当然,他们知道如何构建微服务。

  • 让团队管理他们使用的数据

每个垂直团队都应该拥有自己使用的数据副本,而不是依赖“核心”服务领域。这个想法可能会导致一些读者轻微的心脏病发作;毕竟,如何维护任何数据的单一真实来源呢?在大多数情况下,可以以最终一致的方式同步整个组织的数据。它的工作原理是这样的:

  • 某人在某个时候成为您的用户之一;
  • 例如,通过在线注册流程(您可能还记得,由注册团队负责)。
  • 在这里,关于用户的基本信息被收集并存储在注册有界上下文中。
  • 用户还被分配了一个全球唯一的 ID。
  • 这个新用户的数据,连同他们新生成的 ID,然后被发布到一个消息总线,比如 Kafka。
  • 属于其他感兴趣的团队(例如直接营销和客户支持团队)的服务使用来自消息总线的数据。
  • 然后,他们可以自由存储自己对新用户的表示。
  • 此外,这些团队可以自由地使用任何其他信息来扩充他们的用户数据。
  • 例如,客户支持团队可能会收集和存储用户白天和晚上的电话号码。

因此,不同的团队对贵公司的“核心数据”保持自己的看法。当然,一些数据将驻留在多个视图中。例如,不同的团队可能会存储用户的名字和姓氏。如果该数据稍后在其中一个流中发生更改,会发生什么情况?简单的。这些更改将发布到消息总线,与新用户数据的发布方式相同。感兴趣的团队只需使用和处理这些更改事件,即可使他们的数据视图保持最新。

这是否意味着您永远不应该拥有任何“核心服务”?不必要。有一些有效的用例,通常在安全领域(例如令牌验证、授权等)。但是,如果您发现您的组织拥有多个此类服务——尤其是核心团队不具备特殊领域知识的服务——您可能想要改变方向。

相关技术教程:最全面微服务教程:SpringBoot + DDD + Apache Kafka实现最终一致性

6. 多个团队“拥有”一个微服务

不久前,您的团队开发了一个非常受欢迎的微服务。这个微服务有一些独特的功能——假设它是一个复杂的作业调度程序——最初是为了解决特定的计费用例而编写的。

当然,事实证明,其他团队对复杂的作业调度程序也有自己 的需求。因此很自然地,他们没有开发自己的作业调度程序微服务,而是将自己的东西塞进了您的服务中。

这个曾经由单个团队编写、拥有、修改、维护和部署的服务现在正在被修改、维护和部署。

您的团队不再可以随时更新和部署服务:突然之间,您必须在多个团队之间进行协调以确保可以发布服务(实际上,您考虑将每周发布安排在周二早上。)您仍然是代码所有者,因此您需要进行审核你一无所知的拉取请求。

换句话说,这个作业调度服务已经成为一个迷你单体。正是您首先试图避免使用整个微服务的东西。

  • 打破迷你单体

 相反,每个团队都应该构建和维护自己的作业调度程序。这样,他们就可以在自己的时间表上部署更改。他们可以正确地审查自己的拉取请求。当他们的一项工作出现问题时,他们会确切地知道如何解决它。

现在,其他团队想要利用您复杂的作业调度工作是可以理解的。您如何回答他们对重复您的团队已经投入的工作的担忧?

  • 一方面,这是微服务概念的核心。
  • 由于团队拥有自己的微服务,并且这些微服务应该彼此解耦,因此肯定会有一些重复的功能。
  • 另一方面,如果您团队的作业调度器中确实有一些独特的、有价值的代码,那么您可以考虑将公共代码提取出来以供重用。
  • 这可以以框架或库的形式完成(尽管大量使用内部框架/库应该谨慎)。
  • 另一种选择是将作业调度程序作为基本Docker镜像分发,允许团队将自己的配置分层。

将开源技术应用于公司内部代码库的做法,已经变得流行起来。许多公司已经成功地使用了它。因此,您可能会问,这是否与这里给出的建议相矛盾?我们不能采用不同团队在同一个微服务上工作的内部sourcing模型吗?

事实上,内部sourcing可以工作……当它应用于真正共享的资源,如库和模块时。但是请注意,库和模块存在的根本原因是要共享的;它们真正归多个工程团队所有。这与微服务形成鲜明对比,微服务是(或应该是)各个团队只拥有自己的权限。

7. 一个团队构建微服务并将其交给其他团队维护(研发与现场维护分离)

您的团队需要构建一个新的微服务。事实证明,平台团队有一些备用周期。由于您的团队正忙于完成其他一些工作,因此他们已被指派构建新的微服务。完成后,他们会将其交给您的团队。

现在,您应该感觉到这不是一种理想的方法。当然,一个团队将创建服务,一个团队将维护它。但这些团队应该是一体的。如果您的团队将拥有该服务,那么首先应该创建该服务。

  • 您的团队拥有领域专业知识。
  • 是否有其他团队足够了解您的业务以正确构建您的服务?
  • 平台团队知道一旦服务在生产中运行时,他们就没有麻烦了。
  • 即使以最大善意猜测:
  • 他们真的会尽一切努力确保服务具有弹性吗?
  • 并保证在生产中很容易调试吗?
  • 如果需要,他们是否会推迟截止日期以便这样做?
  • 即使在最好的情况下,也会有一个低效的“交接”期,在此期间,您的团队需要与平台团队坐在一起,以演练服务并了解它。

当然,这一切都是经验法则。规则是用来打破的。有时您会真正希望在自己的有界上下文中实现异步通信,而有时则需要跨绑定上下文进行同步通信。

9. 只有当您的客户告诉您时,你才发现您的服务调用失败了

你的公司已经定义了它的微服务教条印象:您的团队已经弄清楚它需要构建哪些微服务并设计了它们的交互。您已经构建了服务,测试了它们,并将它们部署到了生产环境中。

那么……他们在生产中的表现如何?

事情会不时发生故障,尤其是在分布式环境中。这不是if 的问题,而是when 的问题。当他们失败时,你最好是第一个知道这件事的人。

这意味着不仅仅是用日志消息散布您的代码。在将单个服务部署到生产环境之前,您应该确保拥有仪表板,可以近乎实时地洞察服务的重要指标,例如:

  • 错误率和成功率
  • 收到的费率或请求,或消耗的消息(取决于服务的目的)
  • 性能指标,例如延迟等

这些仪表板对于保持对生产中服务行为的认识至关重要。当然,您不会经常盯着这些仪表板;它们通常在部署等高风险时期很有用,或者在您对持续问题进行故障排除时。因此,设置警报以在出现问题时立即通知团队成员更为重要。

监控和警报本身就是一个主题。但在使用微服务之前了解这一点很重要。

10. 你期待完成

这是一段漫长的旅程,充满挫折和成功。但是,您为那个幸运的日子存下了一箱香槟:您的组织完成向微服务迁移的那一天。

你不太可能真正到达那一天。通往微服务的旅程永远不会真正结束。

首先,它在现实世界中很少真正发生。在所有迁移微服务的公司中,很少有人用微服务替换所有遗留系统。随着越来越多的应用程序转向微服务,就会出现收益递减点。构建新服务和淘汰遗留应用程序的努力不再值得。微服务的要点是解耦团队并为他们提供自治权。一旦贵组织的大多数团队拥有这种自主权,替换遗留代码的价值和愿望就会减弱。

其次,微服务带来了敏捷性和变化能力。随着您进一步前进,您将从过去的错误中学习。你会发现新的模式。更新的技术将会出现。

因此,如果您一直等到工作完成的那一天才打开香槟,那么您很可能永远不会打开它。此外,如果您将转向微服务视为一项重大(我敢说,整体)努力,假设有一天您会“完成”,那么您将冒着让自己陷入困境的真正风险永远更糟的状态。

相反,要认识到微服务代表着一个持续的旅程,它应该由一系列的小胜利组成。在每一步之后,您都应该处于比开始时更好的位置。这样,您将始终朝着正确的方向前进。

总结迁移基本原则:

  • 微服务是关于团队自治的

那里的许多文献都会吹捧微服务的技术优势。但实际上,微服务的最大好处在于它们如何使团队能够灵活、自主地运作。

所以在每一步,问问自己:你的团队是否变得更加自主?他们是否对自己的命运有更多的控制权?或者他们和你开始之前一样耦合和相互依存?

  • 垂直思考,而不是水平思考

我们中的许多熟悉单体应用和微服务新手的人倾向于在水平层中考虑我们的技术和我们的组织。我们将单体应用分为表示层、服务层和持久层。同样,我们将我们的工程组织划分为设计师、前端工程师、后端工程、平台等。

然而,为了获得微服务的好处,我们想要垂直思考。我们应该围绕功能(例如,注册或购物车/结帐)组建我们的团队,而不是围绕特定技术架构(例如后端工程)组建团队。借助微服务,这些跨职能团队可以构建满足其需求的应用程序和服务。

  • 微服务是一个持续的旅程

重要的是要了解,从单体应用迁移到微服务需要花费大量时间和精力。您的组织需要保持士气高涨和决心稳定。您不能投资于“暂时”使事情变得更加困难并使您陷入比以前更糟糕的境地的举动。取而代之的是,您的微服务之路需要取得小胜利,以提醒每个人他们正在朝着什么方向努力。