17611538698
webmaster@21cto.com

微服务与单体架构之完全比较

架构 0 200 2024-08-27 07:45:55

图片

21CTO导读:单体架构有它的优势,微服务有新的优点,各有所长,我们来看它们在技术和参数上的比较。相信对你有所帮助。

微服务架构是为了"对抗"一些所谓的单体架构而提出的,它将业务流程拆分为多个独立的服务。

例如在机票预订的场景下,单一方法涉及构建具有“预订机票”流程的单一软件。

“预订机票”涉及多个单独的流程。可能要向航空公司预订机票、向客户信用卡收费,并在机票预订成功后向客户发送确认信息。

在微服务架构中,各个流程被分解为独立的服务。在上面的业务例子中,服务可以是机票预订、信用卡支付和确认。现在,独立的服务通过定义的接口相互通信。

如果说微服务架构已成为主流,这还只是轻描淡写。在我们的文章列表中,我几乎再也看不到单体架构了——只有在关于从微服务回归单片架构的文章中才会看到。在本文中,我们将对这两者进行对比。

  1. 两种软件架构风格进入竞争,其中一种将会胜出


第一轮:延迟


谈到微服务时,有一条基本物理定律在起作用每当一个微服务通过网络调用另一个服务时,字节就会通过网络发送。这涉及将字节转换为电信号或光脉冲,然后将这些信号转换回字节。根据链接,微服务调用的延迟至少为 24 毫秒。如果我们假设实际处理大约需要 100 毫秒,那么总处理时间将如下所示:

图片

网络延迟——微服务与整体式架构

理想情况下,所有调用执行可以同时发生,并且不相互依赖。下面的图表显示了随着越来越多的调用同时执行时,总时间如何减少。

图片

同时执行更多调用意味着总执行时间减少

并行执行所有调用,意味着服务将在最长的调用完成后返回给消费者。整体式架构没有网络延迟,因为所有调用都是本地的。即使在完全可并行的世界中,整体式架构仍然会更快。解决这个问题的方法是减少调用链长度,使用扇出并尽可能保持数据本地化。此外,使用扇出模式可以显著提高性能,如上所示。但最终,微服务在延迟方面无法超越物理层。

这对于单体式架构来说是一个显式的胜利。

第二轮:复杂性


考虑复杂性时,有许多因素在起作用:开发的复杂性和运行软件的复杂性。


对于开发的复杂性,在构建基于微服务的软件时,代码库的大小会快速增长。涉及多个源代码,使用不同的框架甚至不同的语言。


由于微服务需要彼此独立,因此经常会出现代码重复。此外,由于发布计划不同步,不同的服务可能使用不同版本的库。对于运行和监控方面,受影响的服务数量非常重要。单体式架构只会与自己对话。这意味着它在处理流程中有一个潜在的合作伙伴。微服务架构中的单个调用可以访问多个服务。这些服务可以位于不同的服务器上,甚至可以位于不同的地理位置。


在单体应用中,日志记录就像查看单个日志文件一样简单。但是,对于微服务,跟踪问题可能涉及检查多个日志文件。不仅需要找到所有相关的日志输出,还需要按正确的顺序将它们放在一起。微服务对每个调用使用唯一的 ID 或跨度。这允许 Elasticsearch 等工具查找跨服务的所有相关日志输出。Jaeger 等工具可以跟踪和分析跨多个微服务的调用。


在Kubernetes 集群中运行微服务时,复杂性进一步增加。虽然 Kubernetes 支持自动扩展等功能,但它并不是一个易于管理的系统。


要部署一个单体式架构,一个简单的复制操作就足够了。如果要启动或停止单体式架构,通常一个简单的命令就足够了。另一方面,Kubernetes 并不适合胆小的人。与单体式架构相比,事务也增加了运行微服务架构的复杂性。跨越服务边界,很难保证数据同步。例如,实施不当的调用重试可能会导致支付两次。微服务架构可以使用中央协调器等技术来管理这个问题。在单体式架构中,事务很容易处理,甚至对开发人员是透明的。

就复杂性而言,单体式架构又获得了胜利。

第三轮:可靠性


由于单体中的所有调用都是本地的,因此不存在网络故障的可能性。与微服务相比,假设一个微服务通过网络调用另一个服务,可靠性为 99.9%。这意味着每 1000 次调用中,一次会因为网络问题而失败。现在,如果该服务调用另一个服务,我们的可靠性为 99.8%。对于深度为 10 次调用的调用链,可靠性降至 99% — 这意味着每 100 次调用中就有 1 次会失败。

图片

随着呼叫链变长,可靠性会下降

在设计微服务架构时,重要的是要假设网络会在某个时候中断。微服务提供了一些解决方案来解决这个问题。

开源的Spring Cloud为 Java 提供了透明的负载平衡和故障处理。Istio 等服务网格可以为多种语言实现这一点。网络问题在微服务架构中更常见,但由于这是预料之中的,因此它们被设计为处理这些问题。最重要的是,由于网络故障经常发生,微服务已经证明了它们有能力处理这些问题。这确保了这些问题没有隐藏的错误。

当微服务集群中的服务发生故障时,集群管理器将直接启动替代服务。这使得微服务架构具有高度的弹性。Netflix 创建了一个名为Chaos Monkey的工具,可以随机终止虚拟机和容器。这样他们就可以确保系统能够处理生产环境中的中断。单体当然也可以在大规模集群中运行。但由于其规模,问题对它们的打击更大。很难想象随机重启单体以确保它们能够生存下来。另一方面,最可靠的软件是单体,例如工业控制器和飞机飞行控制系统。构建高度可靠的单体绝对是可能的,但在规模和云端时会变得困难。

在此项,微服务获得了胜利。

第四轮:资源使用情况


如果微服务调用使用相同的算法执行相同的工作,它将始终比单体式调用使用更多的资源。Docker 和虚拟机会增加开销。另一项基准测试发现,在 Docker 容器中运行时,连接数下降了约 8%。图像编排也会消耗资源,日志聚合和监控也是如此。


但是,微服务会让我们能够更智能地使用资源。由于集群管理器可以根据需要分配资源,因此实际资源使用量可以低得多。看看一个在 20% 的代码中完成 80% 工作的单体应用,我们可以展示如果可以独立扩展代码的“热门”部分会发生什么。


例如,如果单体应用的一个实例使用 8GB,两个实例使用 16GB,依此类推。让我们假设 20% 可以并行执行以完成繁重的工作。我们有一个 8GB 的实例,然后微服务使用 20% 的内存,即 1.6GB。这意味着对于两个实例,我们的内存使用量为 9.6GB。


下图显示了资源使用情况的差异。

图片

单体式架构比微服务需要更多资源,因为运行实例更多

在极端情况下,单体式架构的表现要优于微服务。例如,如果一个调用传输了大量数据情况下。

但在大多数场景下,资源使用率较低,这对微服务来说是个胜利。

第五轮:可扩展性


有多种方法可以扩展单体式架构。


可以运行多个实例并相应地做路由请求。或者可以运行多个线程或使用非阻塞 IO。对于微服务架构,这三种方法也都适用。正如在资源使用情况中所述,它们可以用更少的资源完成。这意味着每个资源可以处理更多的连接。对于花在资源上的钱,微服务提供了更高的吞吐量。此外,可以进行更精确的扩展。如果整体式架构正在使用所有资源,处理更多连接的方法是启动第二个实例。


如果单个微服务使用了所有资源,则只有此服务需要更多实例。由于微服务的资源密集程度较低,因此可以节省资源。由于扩展简单且精确,这意味着只使用必要量的资源。管理员可以根据需要将 AWS 或其他云提供商联机或脱机。


例如,假设一个单体应用正在目前最大的 Amazon Web Services 实例上运行。m5.24xlarge实例提供高达 96 个 CPU 和 384 GB RAM。目前,该实例的成本也高达每月 2,119.19 美元,并且全天候运行。同样的价格可以购买 12 个c5.2xlarge实例,每个实例具有 8 个虚拟 CPU 和 16GB RAM,全天候运行。但大多数工作负载不需要全天候使用全部资源。相反,资源使用率在某些时段达到峰值,其余时间较低。下面的图表显示了如果这 12 个较小的实例只运行一段时间而不是全天候运行,它们的成本是多少。


由于专用资源比按小时收费的资源便宜,因此单个实例的价格会有所下降。本例中的交叉点是 520 小时,或者大致相当于实例运行时间占 70%。

图片

比较 12 个按需微服务容器与专用大规模单一容器的价格

由于微服务架构更加细粒度,因此单个服务的扩展也更加细粒度。

对于精确的扩展和更好的资源利用来说,这对微服务来说是一个显式的胜利。

第六轮:吞吐量


让我们再看一个性能指标:绝对吞吐量。


我们已经探讨了网络延迟和并行化之间的关系。吞吐量也存在同样的关系。在无法跨网络并发运行的工作负载中,单体式架构可能提供更好的性能。数据需要在服务之间发送,而且所有基础设施都会产生一定的开销。如果工作负载无法扩展到多个实例,单体式架构可以提供更高的吞吐量。


由于工作负载高度本地化,且没有容器、容器编排或服务网格带来的开销,这是单体架构的优势之所在。


第七轮:上线时间


人们选择微服务架构的原因之一是上线时间——这是从对某个功能做出业务决策到该功能公开可用的时间。由于其规模和依赖性,单体式架构通常更难部署。


另一方面,经常或持续部署微服务则更容易一些。原因之一是更改的影响是高度本地化的。微服务应该只公开其接口而不是其实现。这意味着开发人员可以在不修改依赖服务的情况下更改实现。由于接口也很清晰并且可以进行版本控制,因此对它的任何更改都应该具有明确定义的影响。


而对于单体式架构,面向对象编程允许分离接口和实现。但它需要一支高度自律的团队,以免成为依赖实现的诱惑的牺牲品。


此外,微服务更易于测试。由于微服务仅涵盖有限的功能集,因此依赖项的数量也较少。依赖项越少,测试编写和运行的速度就越快。


第三,微服务的资源密集程度越低,并且可扩展。这使得微服务可以无缝推出。微服务可以在部分集群节点上启动。然后,用户可以依次迁移到新版本。其他迁移策略包括同时运行新旧版本。如果出现问题,这可以快速回滚到旧版本。微服务的细粒度架构允许更快、更强大的推出。这缩短了从构思到生产部署的时间。


此轮,微服务又赢得了胜利。


第八轮:沟通与成本


微服务通常以开发团队的规模来定义。


例如,亚马逊有一个“两个披萨规则”,即一个开发团队可以在创建一个微服务所需的时间内“吃两个披萨”,而这个微服务相当于大约 4-8 人的团队规模。其背后的想法是,沟通仅限于团队内部。团队只需通过服务接口进行沟通。


早在微服务理念诞生之前,Fred Brooks 撰写了一本影响深远的著作《人月神话》。这本书的要点之一是,沟通渠道的数量会随着团队成员数量的增加而增加。如果团队只有两个人,则只有一个沟通渠道。如果团队有四个人,则最多有六个渠道。第一个人与第二个人、第三个人和第四个人交谈。第二个人与第三个人和第四个人交谈,第三个人与第四个人交谈。沟通渠道数量的公式为 n(n − 1) / 2。


那么,一个拥有 20 名开发人员的团队有 190 个可能的沟通渠道。


将这些开发人员分成两个披萨团队,将会大大减少沟通渠道的数量。如果我们以 20 名开发人员为例,将其分成四个微服务团队,每个团队有 5 人,那么每个团队就有 10 个沟通渠道。而四个团队之间的沟通渠道只有六个。沟通渠道总数为 46 个,大约是 20 人团队的四分之一。


下图显示了一个大团队与单个微服务团队的沟通渠道数量。

图片

随着团队规模的增长,单体式架构与微服务架构的沟通渠道

当团队规模达到 10 名开发人员时,微服务模型就比传统模型具有明显优势。

当团队规模达到 50 名开发人员时,沟通渠道的数量几乎是传统模型的 10 倍。在这种规模的团队中工作过的每个人都可以证明,沟通需要花费大量时间。单单是 50 名开发人员参加的一次站立会议就显得效率低下。任何超过 10 名开发人员的开发项目,最好将其拆分成更小的团队。微服务非常适合这种模式,因为它们在服务边界上具有定义明确的接口。

微服务的又一次的明显胜利。

谁将是赢家?


图片

结果已经出来了:单体式架构获胜两次,而微服务架构获胜三次。

但是,在我们查看上面的图表时,请记住它是相对的。

例如,微服务仅在团队规模超过 10 名开发人员时才能赢得团队沟通。拥有 5 名开发人员的小型创业团队更适合使用单体架构。

单体架构更易于管理,移动组件更少。而专注的小型团队也可以使用单体架构运行每日发布计划。扩展仅在一定用户或使用量下才有意义。

如果产品每秒获得几次点击,单体架构可能完全足够。此外如果调用通过网络移动大量数据,性能损失可能很大,并超过其他优势。

微服务并不是解决所有开发问题的万能药。以下是一些我们总结的迹象,它们表明微服务架构可能是一个不错的选择:

  • 需要 24/7 全天候可靠性

  • 扩展到超过几个请求

  • 峰值和正常负载明显不同

  • 超过 10 名开发人员

  • 业务领域可以切分为更小的领域

  • 较短的操作

  • 操作可以表达为 REST 调用或队列事件。

  • 没有严格的跨服务交易要求


如果符合以上的标准,微服务将是企业软件或项目的强大选项。

作者:场长

评论