微服务更难维护吗? - Reddit


微服务架构更难维护、更难部署、更难监控、更难调试,也更难测试?

1、当您没有团队结构来支持它时,当您缺少管理它的关键系统时,微服务比单体服务带来更多的复杂性。

  • 你是否能够为快速构建测试和发布CI-CD而自动对它们进行单独测试?
  • 你今天是否有指标表明,也许有一天可以横向扩展某些组件的潜在性能优势?(你将在k8s、云、其他服务的专业知识维护中支付这些费用)
  • 你能保证它的安全吗?API网关?mTLS?
  • 你需要分布式跟踪来了解你的交易在哪里被处理,否则你的运营部门会花很多时间来弄清楚什么时候走过了哪里。

2、这个话题让我想起了我曾经设计和开发的一个应用。它是用Java EE开发的,是一个部署在WebLogic上的单体。我们使用蚂蚁脚本进行自动部署,管理应用、发现错误、部署更新等都相当简单,因为我们定义了一个应用架构,在代码中很容易浏览到包、库等。实体到DTO的逻辑是集中的,对大多数开发人员来说很容易解决故障,而且我们有调试日志,所以你在排除故障时不会被蒙在鼓里。该应用在微服务架构中迁移的好处是零,因为它是一个简单的前端、一个后端和一个Oracle数据库,而且团队没有维护单独开发的组件的专业知识。那是在SPA热潮之前的几年,所以前端和后端都是用JSF紧密耦合的(我一点都不怀念那个时候!)。

现在,据我所知,今天,那个应用程序仍然是作为一个单体存在的。不过主要的缺点是它的技术栈没有吸引力。那些做Java的人几乎不关心EE,甚至不关心JSF,所以如果不重新评估路线图的话,这个应用很可能会成为一个技术债务。如果我今天要写这个应用,可能会用VueJS的前端和Quarkus的后端作为概念验证来评估...... 尽管单体在某些情况下 "有效",但前端和后端耦合的代码在调试时是个麻烦,尤其是JSF的生命周期在某些调试过程中让我很紧张,我不得不把那张图打印在我的桌子上以记住事件的顺序。

3、不同意:

  • 更难维护?因为所有的东西都是由一个小的代码库组成的,可以很容易地在正确的地方进行修改/修复而不影响其他的应用程序。
  • 更难部署?我不知道这怎么会是一个问题?如果你使用CI/CD进行部署,我们会进行热部署,所以我们对大系统的任何部分都不会有停机时间。
  • 更难监控? 你可以在你的系统中跟踪一个不愉快的流程,并立即看到在哪个应用程序中一切都变了。
  • 更难测试? -我们先开发规范。这意味着我们总是知道输入,总是知道输出。你只需使用单元来验证微服务的功能。

虽然我并不是说所有的东西都应该是微服务,因为这完全取决于需求、团队的经验和已有的架构。

4、我从来没有见过一个微服务堆栈可以像你暗示的那样对服务之间的互动如此天真。
微服务通常不会真正帮助应用程序变得更加解耦,它只是将耦合转移到网络上,而网络的可靠性比单线程代码的执行要差。你不能只改变一个服务的API,而认为对其他服务没有下游的影响。

更多的CICD代码更难部署,即使平均部署没有更多的手工步骤,而且运行速度更快。另外,如果你对两个服务做了改变,以至于两个服务都必须更新才能使改变生效,你就必须担心操作顺序的破坏,而这种情况在单片机项目中基本上是不会发生的。

所以,现在你需要一个相关的ID系统,而你以前不需要,还需要一个第三方的监控工具来使用它。你需要两个新的昂贵的工具来解决一个你选择的问题。


5、关于 "更难维护":这不是类似于使用独立的包或模块吗?是的,你需要重新编译,但模块化的关注点分离仍然存在,而且你可以为每个模块维护独立的git仓库。你觉得完全隔离的 "微型项目 "会更好吗?对我来说,这方面的一大好处是,你可以让每个微服务在任何最适合的堆栈上开发,由一个团队负责,并通过IPC的外部API进行集成,而不是单进程的共享内存通信;但你也会面临线程同步的问题,在某种程度上类似于微服务协调。

关于 "更难部署":当你部署一个单体时,它是一个单点故障,当部署一个网状结构时,它是一个潜在故障的网状结构,而且你还需要控制图中的边缘。

关于 "更难监控":是的,有很多方法可以反省你的网状结构,但在Spring Boot应用中,你可以使用传统的Actuator端点,并将其与普通仪器工具连接起来。复杂性可以更容易控制。不管怎么说,Quarkus和MicroProfile工具的仪器化和可观察性工具是非常棒的。你可以在Consul+Nomad或istio上运行网格,也可以享受很多的集成。

关于”难以测试“,嗯,这取决于。我认为在你的IDE中的单个项目与测试套件,CI/CD管道与适当的测试环境之间是有区别的,当你测试一个网格时,你也需要正确的集成 - 在我看来这比测试一个单体更难。你可以模拟IPC APIs,但你不会真正测试你的整个网格,只是测试单个节点,所以你确实需要在上面做一层复杂的集成测试,这取决于你的图是如何链接的。

6、关键因素是您的微服务必须是可独立部署的。我们有几个独立的微服务。这些都很棒。如果您添加一个只与另一个微服务交互的微服务,那么复杂性就会飙升。您需要考虑的因素还有很多。

  • 微服务之间的通信:对于单体应用,您不必担心另一个微服务超时。我们有一系列的边缘案例来覆盖微服务之间的通信,比如超时、重试、500 错误。
  • 缓慢的反馈:在单体应用中,你的 IDE 会给你即时反馈,比如传递错误的类型。不是微服务。您需要一套全新的工具,例如 e2e 测试。
  • 日志:我们必须使用 DataDog 才能跟踪服务之间发生的事情。如果没有某种集中式日志服务,就无法保持清醒。
  • DRY:为了保持微服务可独立部署,您将放弃服务之间的 DRY。我们在多个微服务中实现了相同的代码。没有不引入耦合的简单方法。

我并不是说每个人都说单体更好,因为它们有自己的问题。只是说你应该准备好处理一系列新的问题。
我想我会重点关注两件事:
  1. 保持微服务可独立部署。
  2. 实施持续部署,您可以在其中一天部署多次。

7、我为英国的一家大型零售商工作。我们的后端大部分都是Spring boot,使用K8s和微服务,用Kafka进行消息传递。我们没有做任何内存占用最小化的工作。我想公司只是支付了费用,而我没有从我们的PAAS团队那里听到任何关于最小化内存使用的消息。我们在我们的团队中使用Webflux,因为我们主要是调用其他API,有很多延迟。这可能在一定程度上有助于减少线程的内存使用。

就开发经验而言,它是非常好的。因为我们使用spring boot,所以很容易从一个微服务跳到另一个,因为它们的结构基本上都是一样的。我知道该期待什么。出于同样的原因,跳到不同的团队也很容易。

其实我对Go很感兴趣,因为它被设计成一种更有生产力的语言。然而,我注意到,由于没有一个流行的框架,而大多数Go程序员不喜欢使用框架,这将导致一系列较小的设计决定。基本上,通过使用Spring,我得到了跨代码库的统一性,这有助于我提高工作效率。在Go中,似乎要花更多的精力才能获得这种效果。我没有专业地使用Go,只是一些想法。

8、我在 "微服务 "方面的经验很少是真正的 "微",而只是倾向于 "正确的大小",也就是说,从一开始就不是这些小盒子,而是把单体分解成有明确理由的小部件。

这其中很多都是围绕着数据进行的。例如,会有一个 "前端 "数据库,一个事件处理管道(有各种缓存),然后是搜索/存档数据库。但分割数据的决定是通过增长而被迫做出的,而不是一个独立的概念。所以,重要的是,我们正处于一个团队可以独立改善COGS的阶段。

我现在也和一个巨大的单体一起工作,但是我们将和其他的数据系统进行整合,主要是由企业收购的,因为,需求正在把我们带到那里。这是一个非常漫长而缓慢的过程,我们说的是几年。

我的感觉是,"数据优先 "是确定架构的正确方法。Java作为一种实现语言的影响在很大程度上是不相关的,尽管我们倾向于坚持使用Java,因为它仍然只是完成了工作。我还没有把lambda用于任何不纯粹是瞬时的东西,主要是因为它仍然很昂贵。

(值得注意的是......这种数据导向就是为什么loom对我来说反而是个大问题。我很少与CPU敏感的应用服务器合作......几乎所有的都是IO敏感的)

9、微服务是一个部署/操作问题、滚动更新、可扩展性等。
这种架构风格在某些领域提供了灵活性。然而,作为每一个工程决策,它都有成本和缺点。内存消耗、复杂度等
你需要微服务吗?如果您不需要它提供的灵活性选项,则不必使用它们。如果你需要它们,你也需要了解它们的缺点。
此外,对于大多数 Java 应用程序,初始内存需求可以大大减少。这些微服务自动配置框架中的大多数使开发变得简单而神奇,并带有让开发人员高兴的默认设置:很多东西都是自动配置的,使用了很多依赖项。这也意味着很多不必要的事情。大多数时候你不需要它们。如果您使用上面提到的自动配置框架,正确调整您的应用程序需要时间。
总而言之,一切都是有代价的。部署灵活性有成本,易于开发也有成本。这取决于您想要或可以投资多少来降低这些成本。这就是为什么我们是工程师。

10、微服务是一种组织模式,而不是一种软件架构。当你超越了(例如)由4个开发人员组成的2个团队在同一个系统上工作时,它们就会 "发光"。你消除了一种形式的复杂性(在一个系统上与一个大团队合作),换取了另一种形式的技术复杂性。
这种权衡是否有意义,与内存或计算成本完全无关。是的,微服务的CPU和内存成本更高。不,在它们实际相关的情况下,你不可能通过使用单体来节省成本。如果因为有50个开发人员在一个代码库上工作而导致开发停滞,并且每个人都互相妨碍,那么每月节省1千美元的计算费用就毫无意义。
你可以在谷歌或AWS上运行大量的微服务,而只需花费一个高级开发人员的费用。

11、倾向于将微服务与工作流引擎结合使用,因为从长远来看,微服务往往会成为“单体巨石”或超级智能服务。
我现在更倾向于保持服务小而笨,让工作流引擎跟踪状态并进行编排。
我还使用过某种事件驱动的架构,试图实现相同的(=更小和更笨的服务),但我不喜欢它,因为它使系统变得更加复杂。逻辑分布在很多地方,很难看到全局。

12、我已经开始使用微服务架构的几个应用程序,并迁移了几个单体。诚然,并不是所有的东西都适合这种架构,但它仍然是流行的,而且在可预见的未来,这种推动力似乎会持续下去。

然而,引人注目的是每个微服务所带来的开销,尤其是在Spring上构建的时候。它的构建速度很快,但鉴于其相对较高的内存占用率,维护成本很高。据说内存很便宜,但在一定程度上,而且只与计算有关。但是,扩展每个微服务所带来的开销,以及将一个单体分割成几个微服务,每个微服务在一个专门的JVM上运行所带来的开销是巨大的。在性能和堆分配之间有一个令人不舒服的权衡。

当然,也有一些解决方法,从内存占用最小化技术到将一些东西作为WAR部署到应用服务器或Servlet容器。有些东西可以在OpenJ9上运行。还有Quarkus和Micronaut,它们可以减轻云部署的一些痛苦。但考虑到RAM的要求,这仍然超出了Go部署的两个数量级,而.NET的部署更有效率,而且大多是直接的。但是,即使是我的Haskell部署也只消耗了JVM部署所需资源的一小部分。而当我需要横向扩展时,运行JVM部署很快就会变得更加昂贵。

你如何处理JVM微服务部署,以减少内存占用和云费用?

13、对我来说,我通常不在Spring中编写微服务的原因是启动时间。当我需要横向扩展时,我需要让它发生得足够快,让用户注意不到影响。Spring本质上是不可能做到这一点的(比历史上好,但还是很糟糕)。同时,解释型语言会在几毫秒内启动,通常是在几十毫秒内启动。这意味着我可以在一秒钟内对流量的激增做出反应,而不会损失对客户的请求。另外,无论如何,解释型语言的编写、配置和构建都会更快。

当我的目标是一个更大规模的服务时,我通常会使用Java或Kotlin(偶尔也会使用NodeJS,这取决于领域和截止日期)。但是,选择不使用Spring是永远不可能的。不幸的是,我们有很多为Spring应用程序编写的实用程序,所以有时使用它在经济上是明智的。