JAVA微服务的使用场景


在纸面上,微服务听起来很棒。它们是模块化的、可扩展的和容错的。很多公司都使用这种模型取得了巨大的成功,因此微服务可能自然会成为卓越的架构和启动新应用程序的最佳方式。

然而,大多数在微服务方面取得成功的公司并不是从它们开始的。考虑一下 Airbnb 和 Twitter 的例子,它们在超越了单体应用之后走上了微服务路线,现在正在与它的复杂性作斗争。即使是使用微服务的成功公司似乎仍在寻找使它们发挥作用的最佳方法。很明显,微服务需要权衡取舍。

从单体架构迁移到微服务也不是一项简单的任务。创建未经测试的产品作为新的微服务更加复杂。只有在评估了替代路径之后,才应该认真考虑微服务。

微服务只适用于成熟产品

关于从微服务设计开始的话题,Martin Fowler 观察到

  1. 几乎所有成功的微服务故事都是从一个太大而被分解的单体应用开始的。

  2. 几乎所有从头开始构建为微服务系统的系统都以严重的麻烦告终。

这种模式导致许多人争辩说,即使您确定您的应用程序将足够大以使其值得,也不应该使用微服务开始一个新项目。

第一个设计很少完全优化。任何新产品的前几次迭代都用于寻找用户真正需要的东西。因此,成功取决于保持敏捷并能够快速改进、重新设计和重构。在这方面,微服务显然不如单体应用。如果您没有确定最初的设计,那么您将处于一个艰难的开始,因为重构微服务比重构单体应用要困难得多。

您是初创公司还是正在从事绿地项目?

作为一家初创公司(在这个经济体中不太可能),你已经在争分夺秒,在下一个坏事发生之前寻找突破口。此时您不需要可扩展性(可能几年内也不需要),那么为什么要使用复杂的架构模型来忽略您的客户呢?

在从事新建项目时可以提出类似的论点,这些项目不受早期工作的限制,因此没有任何决策依据。《构建微服务:设计细粒度系统》一书的作者 Sam Newman表示,使用微服务构建新项目非常困难:

我仍然坚信,对现有的“棕地”系统进行分区要比预先使用新的绿地系统进行分区要容易得多。你有更多的工作要做。您有可以检查的代码,可以与使用和维护系统的人交谈。你也知道“好”是什么样子——你有一个可以改变的工作系统,让你更容易知道你什么时候做错了,或者在你的决策过程中过于激进。

微服务不是本地部署的最佳选择

由于所有移动部件,微服务部署需要强大的自动化。在正常情况下,我们可以依靠持续部署管道来完成工作——开发人员部署微服务,客户只需在线使用应用程序。

这不适用于本地应用程序,开发人员在其中发布一个包,并由客户自行在其私有系统上手动部署和配置所有内容。微服务使所有这些任务变得特别具有挑战性,因此这是一个与微服务架构不太匹配的发布模型。

需要明确的是,开发本地微服务应用程序是完全可行的。Semaphore 正是通过 Semaphore On-Premise 实现的。然而,正如我们一路上意识到的那样,有几个挑战需要克服。在决定采用本地微服务之前,请考虑以下事项:

  • 本地微服务的版本控制规则更加严格。您必须跟踪参与发布的每个单独的微服务。
  • 您必须进行彻底的集成和端到端测试,因为您无法在生产环境中进行测试。
  • 如果不直接访问生产环境,对微服务应用程序进行故障排除要困难得多。

你的巨石可能还有生命

每个软件都有一个生命周期。你可能会想废弃一个单体,因为它很旧并且有它的复杂性。但是折腾一个工作产品是浪费的。稍加努力,您就可以从您当前的系统中挤出更多的好年头。

有两个时候,微服务似乎是唯一的前进方向:

  • 纠结的代码库:很难在不破坏其他功能的情况下进行更改和添加功能。
  • 性能:你在扩展单体应用时遇到了麻烦。

模块化单体

开发人员想要避免单体应用的一个常见原因是他们倾向于恶化成一堆乱七八糟的代码。当我们到达这一点时,添加新功能是一项挑战,因为一切都是相互关联的。

但是单体不一定是一团糟。以 Shopify 为例:他们的代码行数超过 300 万行,是世界上最大的 Rails 单体应用之一。在某一时刻,系统变得如此之大,以至于给开发人员带来了极大的悲痛

该应用程序非常脆弱,新代码会产生意想不到的影响。进行看似无害的更改可能会引发一连串无关的测试失败。例如,如果计算运费的代码被调用到计算税率的代码中,那么更改我们计算税率的方式可能会影响运费计算的结果,但原因可能并不明显。这是高耦合和缺乏边界的结果,这也导致测试难以编写,并且在 CI 上运行非常缓慢。

Shopify 没有将整个单体架构重写为微服务,而是选择了模块化作为解决方案。

显示两个轴的图表。 纵轴表示模块化程度。 水平轴读取可部署单元的数量。 显示了四个象限。 在两个轴上的零附近有一个分层的整体。 在垂直轴上,有一个模块化的整体。 最右边和最上面是微服务。 在右下角,有一个分布式单体。

模块化有助于设计更好的单体和微服务。如果没有仔细定义模块,我们要么陷入传统的分层单体(大泥球),或者更糟糕的是,成为分布式单体,它结合了单体和微服务的最差特性。

模块化是很多工作,这是真的。但它也增加了很多价值,因为它使开发更加直接。新开发人员在开始进行更改之前不必了解整个应用程序。他们一次只需要熟悉一个模块。模块化使大型整体感觉很小。

模块化是过渡到微服务之前的必要步骤,它可能是比微服务更好的解决方案。与微服务一样,模块化单体架构通过将代码拆分为独立的模块来解决纠结的代码库问题。与通过网络进行通信的微服务不同,单体应用程序中的模块通过内部 API 调用进行通信。

分层与模块化单体。 左图显示了一个经典的 MVC 分层单体。 在右侧,它已被模块化。 我们没有层,而是有代表帐户、订单和产品模块的垂直块。

分层与模块化单体。模块化单体具有微服务架构的许多特征,没有最困难的挑战

巨石可以扩展

关于单体的另一个误解是它们无法扩展。如果您遇到性能问题并认为微服务是唯一的出路,请三思。Shopify 向我们展示了声音工程可以以令人难以置信的规模使工作成为一个整体:

推特

架构和技术栈将决定如何优化单体;一个几乎总是从模块化开始并可以利用云技术进行扩展的过程:

  • 部署单体应用的多个实例并使用负载平衡来分配流量。
  • 使用 CDN 分发静态资产和前端代码。
  • 使用缓存来减少数据库的负载。
  • 使用边缘计算或无服务器功能实现高需求功能。

如果它有效,请不要修复它

如果我们将生产力衡量为随着时间的推移实现的增值功能的数量,那么当生产力很强时,切换架构几乎没有意义。

显示两条线的双轴图,一条用于单体应用程序,另一条用于微服务。 X轴是时间,Y轴是生产力。 最初,单体应用比微服务更具生产力。 随着时间的推移,整体生产力的下降速度比整体生产力更快,从而使线在某个中间点交叉。 在右侧,微服务的生产力更高。

由于维护开销,微服务最初是生产力较低的架构。随着单体的增长,它变得更加复杂,并且更难添加新功能。微服务只有在线路交叉后才能得到回报。

诚然,有些事情最终必须改变。但这可能是几年后的事,到那时,需求可能已经发生了变化——谁知道同时会出现哪些新的架构模型呢?

布鲁克定律和开发人员生产力

The Mythical Man Month (1975) 中,Fred Brook Jr 表示“为后期的软件项目增加人力会使它变得更晚”。发生这种情况是因为必须先对新开发人员进行指导,然后才能处理复杂的代码库。此外,随着团队的壮大,沟通开销也会增加。组织起来和做出决定变得更加困难。

布鲁克定律。 显示了一个两轴图。 纵轴是时间,横轴是开发者数量。 曲线按时开始,随着开发人员数量的增加,曲线下降,使项目完成所需的时间更少。 在某个时刻,趋势发生变化,曲线呈指数增长。 添加的人越多,项目所需的时间就越长。 拐点是最佳团队规模。

适用于复杂软件开发的布鲁克定律指出,在后期的软件项目中增加更多的开发人员只会使其花费更长的时间。微服务是减少布鲁克定律影响的一种方法。然而,这种效果只在复杂而庞大的代码库中才能看到,因为在这种情况下,我们无法将开发划分为离散的任务。

在使用微服务之前,您必须确定布鲁克定律是否正在影响您的单体应用。过早切换到微服务不会增加太多价值。

你准备好过渡了吗?

在开始使用微服务之前,必须满足一些条件。除了准备巨石之外,您还需要:

改变组织的文化可能需要数年时间。学习所有知识需要几个月的时间。如果没有准备,过渡到微服务是不可能成功的。

结论

我们可以用一句话总结关于过渡到微服务的整个讨论:除非你有充分的理由,否则不要这样做。那些毫无准备且没有可靠设计就踏上微服务之旅的公司将度过一段非常艰难的时期。在微服务被视为一种选择之前,您需要达到一定数量的工程文化和扩展专有技术。

同时,如果您的系统运行良好并且您仍在以不错的速度开发功能,为什么要进行更改?

1 条评论

当前评论已经关闭


登录用户头像