跳转到主要内容
AG·SORA
技术

单体还是微服务:选择合适的业务应用架构

发布于 9 分钟阅读作者:agsora.tech
AG·SORA / BLOGAG·SORA技术单体还是微服务:选择合适的业务应用架构agsora.tech
本文目录

一家物流初创公司决定从第一天起就把应用做成二十个微服务,因为大型科技公司都是这么干的。八个月后,这支六人团队花在管理服务间网络、部署和监控上的时间,比开发功能还多。而从一个简单应用起步的竞争对手,已经发布了三个版本,并拥有付费客户。

“单体还是微服务”这个问题,常被讨论得好像只有一个正确的现代答案。然而架构是关于取舍的:每个选择在一方面带来便利,在另一方面增加负担。正确的选择取决于团队规模、业务阶段、增长模式和运维能力,而不是技术大会上的潮流。

本文用企业主和产品经理都能理解的语言,说明这两种方式的差异,包括隐藏成本、单一应用开始拖后腿的迹象、模块化单体这条中间道路,以及如何在不让业务停摆的前提下逐步拆分系统。目的是让您能更有批判性地与技术团队或供应商交流。

摘要

  • 单体是作为一个整体部署的单一应用;简单,起步快
  • 微服务把系统拆成独立的小服务;灵活,但运营成本高
  • 对大多数中小企业来说,模块化单体是最健康的起点
  • 只在有真实理由时才拆分服务:规模、团队或不同的部署需求
  • 用绞杀者模式逐步迁移,比整体重写更安全

什么是单体,什么是微服务

单体是这样一种应用:从商品目录、购物车到支付和报表的所有功能,都在同一份代码库里,并作为一个包部署。修复一个功能时,整个应用都要重新部署。“单体”一词听上去常带贬义,但许多非常成功的系统多年来一直这样运行。

微服务把应用拆分为许多小服务,每个服务负责一项业务能力,如订单、库存或通知。每个服务有自己的代码库、部署,往往还有自己的数据库,并通过 API 或消息在网络上通信。不同团队可以独立开发和发布各自的服务。

最重要的区别在于边界与通信。在单体中,一个部分调用另一个部分只是普通的函数调用,快速而可靠。在微服务中,这种调用变成了网络请求,可能很慢、失败或部分中断,于是分布式系统的全套难题随之而来。

整齐布线的网络电缆的服务器机架
把应用拆成许多服务,意味着要管理许多通过网络相连的部分。

常被低估的单体优势

单体容易理解。新来的程序员可以在笔记本上运行整个应用,从头到尾追踪流程,并快速测试改动。调试发生在一个进程内,有完整的调用栈,而不是跨越五个各自保存日志的服务。

数据库事务很简单。创建订单、扣减库存、开具发票,可以放在一个事务中,要么全部成功,要么全部回滚。在分布式系统中,维持这种一致性需要 saga 和补偿等复杂模式,容易出错,也难以测试。

运营成本低。一个应用意味着一条部署流水线、一个监控位置和较小的基础设施。对小团队来说,节省的不只是金钱,还有可以用来开发客户想要的功能的时间和精力。

单体何时开始拖后腿

缺乏纪律、任其生长的单体会变成“大泥球”:各部分相互依赖,在一处做一个小改动,就会在别处意外地弄坏东西。部署变得缓慢而令人胆怯,测试要花几个小时,每次发布都需要整个团队协调。

另一个迹象是扩展需求不均衡。如果商品搜索模块的流量是报表模块的一百倍,为了支撑搜索而复制整个应用就很浪费。把负载最重的部分拆出来,就能以更低的成本单独扩展它。

第三个迹象是组织摩擦。当几个团队的几十名程序员在同一份代码库里互相等待、互相冲突时,速度就会下降。此时清晰的服务边界能帮助每个团队独立工作和发布,这才是微服务的真正好处:组织层面的规模,而不仅仅是技术层面的规模。

微服务解决的是组织问题,而不是代码问题

康威定律指出,系统设计会映射组织的沟通结构。如果您只有一个小团队,把系统拆成几十个服务只会带来协调负担而没有收益。当有多个团队需要独立行动时,再考虑微服务。

微服务的隐藏成本

第一是运维复杂度。您需要容器编排、服务发现、API 网关、密钥管理,以及为几十个服务做部署。如果没有平台团队或成熟的 DevOps 能力,这些负担会直接落在功能开发人员身上,拖慢一切。

第二是可观测性。一次用户请求可能经过许多服务,因此需要分布式追踪、集中日志和各服务的指标才能找到问题的源头。没有这些,故障就成了解决起来代价高昂的谜团。

第三是数据一致性和版本管理。每次 API 契约的变更都必须妥善管理,以免破坏其他服务;分散在许多数据库中的数据也让跨领域报表更加困难。许多组织最终不得不增加数据仓库,只是为了回答过去一条查询就能解决的问题。

第四是延迟和可靠性。每一次网络跳转都会增加耗时和失败的可能。系统必须通过超时、重试和熔断器来设计成能够承受缓慢或宕机的服务。这些都是实实在在的工作,在单体中并不存在。

编辑器中显示彩色程序代码的笔记本屏幕
代码内部清晰的模块边界,与服务器之间的服务边界同样重要。

中间道路:模块化单体

模块化单体是由边界明确的模块组成的单一应用。每个模块,例如商品目录、订单和计费,只通过清晰的接口与其他模块通信,不得直接访问其他模块的数据库表。部署仍然是一个包,所以运营起来很简单。

这种方式带来微服务设计上的大部分好处,即职责清晰和变更隔离,却没有分布式系统的成本。如果将来某个模块需要拆出去,它的边界已经整洁,把它抽成独立服务就容易得多。

为了保持纪律,可以使用在测试流水线中自动检查的架构规则,例如禁止订单模块导入计费模块的内部代码。只写在文档里的规则会在截止日期临近时被打破;由失败的测试强制执行的规则则能留存下来。

实用的决策框架

首先问有多少个团队在做这个产品。如果是一到三个小团队,模块化单体几乎总是最佳选择。接下来问是否有某个部分在规模或可靠性上的需求截然不同,例如图像处理或批量发送通知;这样的部分是第一个被拆分的候选。

还要问运维成熟度。对于一个应用,您是否已经有良好的自动部署、监控和恢复计划?如果没有,把它乘以二十个服务只会放大混乱。在增加运行部件的数量之前,先把运维基础打牢。

  1. 01从模块化单体和明确的模块边界开始
  2. 02衡量:部署时间、发布频率和扩展瓶颈
  3. 03找出真正需要不同规模或发布节奏的模块
  4. 04拆出一个模块作为试验,并评估其成本
  5. 05只有当收益被证明超过运营负担时才重复

逐步拆分系统

如果您已经有一个难以修改的大型单体,请抵制全部重写的诱惑。整体重写往往比估计的耗时长得多,而在此期间旧系统还在不断变化,团队追逐的是一个移动的目标。许多这样的项目在耗尽数年预算后被取消。

使用绞杀者模式:在旧系统前放置一层路由,然后一次把一项能力迁移到新服务。从孤立且价值高的部分开始,如通知或搜索。把一小部分流量导向新服务,比较结果,有把握后再完全切换。旧系统一点点缩小,直到不再需要。

留意数据。拆分代码比拆分共享数据库容易。规划好每张表的所有者,并在迁移存储之前提供跨模块访问数据的接口。通过事件或复制进行的临时同步可以衔接过渡期。

案例:成长中的网店

一家网店从一个同时处理商品目录、订单和支付的应用起步。头两年里,这个单体运行顺畅,三个人的团队可以每天发布。当促销活动导致搜索流量激增时,只有搜索模块不堪重负,其余部分一切正常。

团队没有把一切都拆开,而是把搜索拆成独立服务,配上专用的搜索引擎并独立扩展。订单和支付仍留在单体中,因为它们需要事务一致性。结果是基础设施成本合理,复杂度仍在小团队可管理的范围内。

教训是:依据证据拆分,一次一个部分,并且只在存在可衡量的问题时才拆。好的架构随业务需求一同成长,而不是走在它前面。

可以向供应商或技术团队提出的问题

当供应商提议使用微服务时,问它要解决什么具体问题,以及他们如何衡量。问上线后由谁来运营系统,监控和灾难恢复如何进行,预计每月的基础设施成本是多少。含糊的回答说明这个决定是由潮流而不是需求驱动的。

还要问模块边界如何保护、数据库如何管理,以及将来拆分某个部分有多难。好的供应商会乐于解释他们为何在早期选择模块化单体,并展示随着业务增长的合理演进路径。

结语

单体与微服务之争并不是陈旧与现代之争,而是适配度问题。对大多数中小企业而言,从整洁的模块化单体起步,能带来速度、低成本和成长空间。当组织规模和技术需求确实要求,且运维能力已经就绪时,微服务才值得考虑。

把重点放在最关键的事情上:清晰的模块边界、自动化测试、可靠的部署和良好的监控。有了这个基础,您随时可以调整架构,而不必把业务押在一个过早做出的决定上。

不确定哪种架构适合您的业务应用吗?

AG·SORA 团队可协助评估需求,设计契合您业务阶段的架构,并分步骤构建。首次咨询免费,无任何义务。

免费咨询

免费清单:如何选择软件公司

签约前评估供应商的 24 个要点,可保存为 PDF。

获取清单

准备好构建与您业务共同成长的系统了吗?

与 AG·SORA 团队讨论您的需求, 完全免费,无需承诺。