如何决定你真的需要微服务吗? (步骤)

227 阅读10分钟

你真的需要微服务吗?- 如何决定?

微服务是开发人员在互联网上搜索最多的话题之一。不幸的是,大多数可用的内容都倾向于在一种语言/框架中实现微服务。这个话题主要是从单个开发者或单个产品(或可能是两个)的经验角度来阐述的。

这种方法的问题是,你只能听到故事的一面。你得到一个单一的利弊清单,试图过度简化一个相对复杂的决定。其结果是,人们往往对在系统架构中实际使用微服务感到困惑。我遇到的大多数软件架构师要么还在摸索甜蜜点(实用主义的心理模型),要么遵循一些旧的书籍或文章(他们坚信是正确的)。但在大多数情况下,人们忘记了他们需要问自己的第一个问题**--我们到底是否需要一个基于微服务的架构?**

这篇博文将分享我在面对同样问题时的心理模式(决策方法)。我为生产写代码已经超过十年了。我做过许多自由咨询项目,设计过为数百万用户服务的系统(峰值并发量超过每秒1000万次的操作)。请把这篇博文看作是我在这个领域的经验学习的总结。这篇文章背后的想法并不是要规定或推崇 "正确的方法"!而是要给你一个起点。但要给你一个思考过程的起点。决策永远是高度主观的和有背景的,你将永远需要你的心理模型。

需要牢记的关键事项

在进入选择单体和微服务的决策方法之前,我想强调一些人们经常忘记的重要事实。每当我不得不做出上述决定时,都会涉及到三个支柱。这三个支柱是--

  1. 产品
  2. 人员
  3. 技术

我意识到,以上几点让我听起来更像一个产品经理,而不是一个开发人员。但是,当你是一个工程领导时,你应该平衡产品思维和工程思维,因为你的决定可能会产生长期的影响,可以使整个组织成功或失败。让我解释一下这些支柱是什么,以及它们所起的作用。

第一支柱--产品

  • 好好定义产品--定义你要建立的东西,对于在微服务和单体之间做出选择至关重要。作为一个开发者/软件架构师,请理解你正在试图解决一个没有完全定义的问题。我见过许多初创公司在产品范围不明确的情况下就开始写代码。千万不要这样做。编写代码是很昂贵的!
  • 写软件是为了解决一个问题。它本身不应该成为一个问题--这在大多数情况下是由于工程团队中参与决策过程的人而发生的。他们对某种语言/技术/架构模式的偏见往往会悄悄进入,并把本来可以设计得很完美的系统弄得一团糟。使用这个X数据库,而不是Y。使用这个A框架,而不是B,等等。试图因为你的偏见而对自己进行不必要的约束,往往会在你的应用程序需要扩展时造成混乱。所以,试着超越它,做决定时只考虑一件事--为给定的问题提供最优化的解决方案。

第二根支柱--人

  • 工程团队- 在构建任何成功的软件时,人是最大的资产。在决策过程中始终包括每个开发人员/SRE。如果你正在接听与项目中使用的技术有关的具体电话,请与你的团队讨论,并试图得出一个共同的结论,使每个人都站在同一起跑线上。
  • 终端用户- 编写软件应用程序是为了解决终端用户的问题。所以,用户行为应该是你决策的核心。根据你的产品的用户旅程来预测用户行为将使你充分了解你的系统的访问模式,并帮助你很好地设计系统。我们将在这篇文章的后面详细讨论这个问题。

第三根支柱--技术

  • 充分理解技术--我见过用PHP和Ruby编写的服务比用Go或Rust编写的服务性能好得多。原因不是Ruby/PHP或类似语言比Go或Rust好。原因是编写这些程序的人非常了解他们的技术(编译器如何工作,内存使用,限制等),他们知道如何从这些程序中获得最大的输出。而写相应的Go和Rust程序的人并不完全了解语言特性(特别是运行时和并发部分)。同样的逻辑也适用于框架/数据库/队列/文件存储等。技术不是魔术。使用一种新技术不会自动解决你写得不好的逻辑或你糟糕的系统设计的问题。所以,一定要尽可能地了解你所使用的技术。
  • 基准测试、监控和优化--80%的应用程序代码编写后从未被监控或优化。如果功能正常,那么人们就认为它是好的。那么你解决的那几百个竞争性编程问题的意义何在,时间和空间的复杂性就是一切?这就是你将获得的 "经验式学习 "的方式。通过测量和优化,尽可能获得最优化的性能,并节省大量的资金。

我希望有更多的产品、技术和行政职位的人更好地理解上述支柱。

无耻的插件

大家好。在介绍解决方案之前,我决定做一个无耻的插件。如果你是一个想学习如何创造一流技术产品的人,我专门为你创建了一个名为cloudeasy.club的学习社区。通过加入这个俱乐部,你可以学习系统设计、软件架构和分布式系统。你可以在DiscordWhatsapp群中找到我们。此外,如果你有任何问题,请随时在LinkedInTwitter上与我联系。

高层决策流程--用于决定你应该选择微服务还是单体系统

在我进入这个决策流程的细节之前,请理解这是一个非常大胆的尝试,以简化复杂的东西。同样,我们的想法是给你一个思考过程的起点。我是通过犯错,通过破坏东西,艰难地学会了下面提到的流程。所以,你的背景可能不同,但如果你应用下面给出的基本模式,你就可以在做这个决定时预先避免许多错误。这是一种结构化的方式,使用产品思维和信封式计算来做出正确的决定。

第一步 - 收集需求

把你要建立的所有产品功能列出来。在一个板子上把它们可视化。我使用Miro板来做同样的事情(https://miro.com/)。你可以使用任何视觉板工具。只写下要点和高层次的要求(不要写错综复杂的要求)。

第二步--对所有要解决的工程问题做一个高层次的要点清单

  • 将所有的功能分解成工程问题的清单。
  • 然后根据一个简单的规则将问题分解成子问题--关注点的分离。
  • 估计每个子问题的复杂性,以了解两件事--所需的编程努力和所需的资源(CPU/内存/文件系统,等等)。如果你是一个开发人员,这应该是很容易估计的。
  • 每个子问题的解决方案要么是你产品中的功能,要么是一些支持其他功能的幕后系统。

第三步--建立用户角色,并以可衡量的标准写下他们对各个功能的预期行为。

  • 让我给你一个简单的例子--95%的用户在滚动Instagram feed的时候不会滚动过30个帖子。或者90%的用户在滚动浏览Instagram的卷轴时,不会滚动超过50个卷轴。(我不知道真实的数字。 这只是一个假设的例子)。现在你知道了两个用户角色的预期行为,你可以得出一个可衡量的指标,比如--每秒HTTP请求,每秒消耗的媒体,等等。这将给你一个粗略的估计,即这些功能中的每一个可以期待多少流量(或负载)。在大多数情况下,你可以为你的所有子问题(或功能)做这个。
  • 在这一步中,也要把这些功能分为两部分--最不常用的功能和最常用的功能。
  • 使用上面第1点描述的方式,估计这些服务中每一个服务的负载。
  • 请注意,我在这里使用的是 "负载 "一词。原因是,这个负载可能根据你所写的应用程序的性质而变化。例如--如果你正在编写一个REST API(或REST后端),负载将是 "每秒的请求数"。如果它是一个基于事件的(pub-sub类型)系统,它将是每秒的事件(或消息)数量 如果它是一个数据处理系统,每秒的数据传输(以GB、TB等)。

第四步--根据预期的平台流量进一步估算

我们在第三步估计了每个用户角色(或用户旅程)的负载。在这一步,我们将该负载与主要指标相乘(每日活跃用户,在任何特定时间的并发用户数量等)。 例如 - 在上一步,我们采取了一个例子的角色,90%的用户来到Instagram的饲料不会滚动超过50卷。现在让我们假设Instagram对每个卷轴进行四次API调用,并且在任何特定时间,10000个并发用户正在滚动浏览卷轴。有了这些假设,你可以乘以估计你的服务的平均负载。如果你愿意,你可以把它深入到你每秒钟必须进行的数据库调用(或IO操作等)的数量水平。这就是你如何到达真理的时刻。看完所有的数据后,问自己两个问题--

  • 如果我把所有这些功能归入一个单一的单体,它是否能够承受这种负载而不影响特定的功能(或整体用户体验)?
  • 简单的横向扩展是否有助于处理未来可能出现的任何未经计算(超过估计)的额外负载?

如果这两个问题的答案都是 "是",请继续使用单片机服务。另外,请记住,如果你对你的估计没有信心,你总是可以写一个概念验证代码(或应用程序),做一个简单的基准测试,或使用负载测试工具模拟负载,以提高估计的准确性。

第五步 - 将项目预算纳入考虑范围

如果你正在与一个预算受限的组织合作,你必须在做最后决定时考虑到这一点。向适当的利益相关者解释两种方法的优点和缺点,让他们权衡一下。根据我的经验,如果你正确地选择你的工具(语言、数据库、部署架构等),一个精心设计的系统总是具有成本效益的。

这就是了。到第五步,你最好对是否应该为你的下一个项目选择微服务架构有了答案。