译者 | 陈峻
审校 | 孙淑娟
目前,业界最常见的软件范例有:单体(Monolith)和微服务架构两种类型。两者的逻辑结构如下图所示。
通常:
- 微服务架构是将应用程序表示为微小的、松散耦合的服务集合。由于整体的复杂性被转移到了服务的协调级别上,因此每个服务都代表了一种业务功能,可以更加容易地去定位相关代码。
- 而单体架构是将几个离散的功能组成一个单元,作为一个整体进行测试、部署和扩展。由于所有组件都是相互依赖的,因此通常不能够单独运行。这就意味着某个模块中的错误,可能会减慢、甚至破坏整个应用程序。
1.微服务架构的优点
一直以来,我们都沿用且谙熟单体架构,下面,我们先主要来讨论微服务架构的各项优点:
- 易于扩展
- 应用组件相互独立
- 有清晰的边界,并能通过HTTP实现通信
- 可以使用不同的编程语言和数据存储
- 开发过程可被分到多个团队
- 可被独立部署
- 易于更新和维护
- 使用较小的代码库
2.微服务架构的缺点
- 难以监控
- 具有更为复杂的服务部署
- 服务之间的通信需要额外安全加固
- 性能会有所降低
- 鉴于分布式系统的远程调用较慢,因此经常存在着编程难度大和失败的风险
- 增加了运营的复杂性
3.何时选择微服务
2001年,面对各种应用请求的增加,编码问题突显、开发的延迟、以及服务间的相互依赖性等问题,Amazon逐渐意识到需要从头开始重构其系统,因此它将其单一的应用程序分解成小型的、独立的特定于服务(service-specific)的应用程序,开创了微服务的架构。该架构实现了由一种服务接受订单,另一种服务生成待购买的推荐商品列表,而第三种服务负责提供简单的身份验证服务等模式。正如Martin Fowler早在2015年,针对如何构建实用的软件,所给出的建议那样:“几乎所有成功的微服务案例都是从拆分一个巨型的单体架构开始的。”当然,仅仅根据现代化趋势来选择微服务,不一定是正确的。通常,我们认为如下的应用和代码设计需求,更适合企业选择转向微服务:
- 繁重的系统负载,需要与不同的支付系统进行交互。
- 用户需求不断增长和规模持续扩大,现有应用系统常出现中断。
- 单体应用变得不够灵活且无法升级。
- 为了在竞争激烈的业务环境中取得成功,需要加快应用的开发和发布时间,并可在后续着手进行功能的更新与升级。
- 需要实施人工智能之类高级的商业智能方案,以获得更深入、更具竞争力的业务数据、报告和分析。
- 目前的基础设施无法提供所需的横向可扩展性,无法处理大数据的处理负载。
上图是Amazon在2008年完成的被称为“死亡之星”的微服务基础设施
4.迁移至微服务所面临的挑战
企业在从单体架构向微服务架构的迁移过程中,往往会遇到各种技术和组织方面的挑战,因此我们有必要了解与之相伴的各类风险:
- 麻烦且耗时。由于从单体应用整体迁移到微服务是非常耗费时间和精力的,因此企业往往选择以“小步快跑”的方式进行分步迁移。如果需要在迁移的过程中引入新的服务特性,那么开发团队还要投入更多的精力。
- 成本较高。无论是从开发与编写代码的角度,还是从支持、运维、以及更改的角度,迁移到微服务的成本都比较高。企业需要在构建基础设施、开发文档、以及重构应用等方面进行大量的投资。
- 由于微服务是一个分布式系统,因此开发团队需要选择,并实现基于消息传递或RPC的进程间通信机制。
- 移动代码库。为了顺利地将数据从现有的单体架构提取至配合微服务的数据库和代码库,我们有可能需要重构其实现的过程,并通过完备的测试覆盖率,以避免引入新的bug。
- 组织的转变。为了实现迁移,企业需要将现有的大型项目团队,拆分成能够自主开展工作的小型团队。同时,企业仍需要保持组织架构的一致型。
- 团队应对其服务负责。在完成迁移后,各个团队将拥有自己的代码库,一旦出现服务交付的失败,他们将不再可以归咎他人,而需要从自身找原因,动手解决,负责到底。
- 此外,在系统不宕机的情况下进行迁移,并保证用户持续有权访问应用程序。这本身就有一定的风险。
可见,由于需要一定的资源投入,微服务架构可能并不总是对初创型或中型企业有利。
5.从审查和分析开始迁移
正如前文所提到的,从一个单体架构迁移到微服务架构不但繁琐耗时,而且存在着风险。那么,我们怎么能够在迁移之前就认定微服务一定适合本企业呢?《微服务迁移模式》一书的作者--Sam Newman,建议开发人员在动手之前考虑如下三个方面的问题:
- 您希望达到什么目的?
- 您考虑过使用微服务的折中方案吗?
- 您怎么判断迁移的有效性?
下面,我们根据Sam Newman的建议,提出一套分析方法:
6.设定目标
- 定义迁移对于业务和最终用户的好处,明确企业想通过微服务获得什么。例如:是为了快速开发的整体进程,还是需要减少服务的相互依赖、亦或增加正常运行时间、以及增强可扩展性。
- 同时,我们需要事先预测系统在完成迁移后的负载和用户数。
7.盘点业务与功能现状
企业的应用架构师需要能够找到关联的代码对象,并将它们与系统中的业务功能相匹配。
- 在现有的单体架构中,可能许多函数由于在其使用域中尚未被明确地定义,或者是业务流程的逻辑较为混乱,因此往往无法被直接迁移或替换。例如:某个组件持续与其他多个组件相关联,那么就很难被拆分为多个普通的微服务。
- 分析当前的功能,并考虑对其进行优化。例如,通过剔除大量不必要的信息,来优化数据库的查询,或者可以直接更换新的硬件,以及通过开发新的功能,来引入微服务。
8.团队的能力和折中方案
- 评估团队的DevOps成熟度水平,包括:是否了解DevOps的核心实践,是否具备基本的自动化文化?运营团队是否支持脚本式部署?是否拥有代码即基础设施?是否已有代码评审的标准?团队只有具备了这些成熟的开发和运维实践能力,才能发挥微服务架构的优势。
- 由于依赖性在服务之间创建了连接,模糊了组件的边界,并导致它们必须组合成单个的模块功能,因此团队只能尝试着从应用的垂直或水平方向进行扩展。
- 根据项目的特点,仅分离并迁移诸如:电子邮件的发送、通知的推送或电话的呼叫等部分受限的功能。当然,如果您只想从仪表盘系统内剥离出来,从已连接的数据库中收集与分析数据,进而单独形成微服务的话,那么应全面考虑相互之间的关联性。
9.选择可扩展平台
为了保证在构建和迁移至微服务时,用户的体验不会受到影响,开发团队应邀请用户一起进行业务需求分析,构建详细的业务逻辑和数据流。有时,您可能需要一个专有的平台来扩展微服务的资源,并能够支持自动化的调整。在此方面,您可以使用由云服务提供商托管的无服务器类型的基础设施,例如:Google Cloud、Microsoft Azure和Amazon Web Services等。
10.考虑创建跨职能团队
在迁移的过程中,企业需要团结包括开发人员、质量保证(QA)人员、操作运维人员、以及企业所有者等角色,以微服务为驱动,来创建可以从事设计、构建、部署和维护的服务型团队,并尽量简化不必要的审批流程。杰夫·贝索斯曾说:“我们试图创建一支规模不超过两个比萨饼的队伍。”他称之为“双披萨团队规则”。
下面,我将向您介绍从单体架构迁移到微服务架构的一些值得注意的参考经验。
11.定义边界
正确的边界往往是有效的微服务架构的基础。相反,如果边界定义错误,则可能导致在新的微服务中,各项功能被频繁更改,特别是那些提供调用的微服务接口,很可能会在随后的集成测试中持续“浮动”。而且,由于不同微服务出自不同的团队,因此它们会牵扯到团队之间的各种反复协商与较量。
一个典型的域分离的例子源于软件公司Istio。由于前期定义不足,在迁移到微服务后不久,Istio团队便从用户处得到了各种反馈。他们很快地意识到,微服务并非像他们最初想象的那么实用。其主要原因是:所有控制面的服务都是被一股脑部署和使用的,并且共享着相同的管理和安全域。因此,为了大幅降低Istio的操作复杂性,以更少的精力满足业务需求,并能够更容易地开发出服务产品,他们决定从微服务架构回归至单体架构,并按照相关的技术标准来构建单体架构,识别架构中的业务域边界,并使用公共的API作为接口,来予以实施。
12.选择单体架构中可以被迁移的功能
在迁移之前,一个由工程师和作用域专家组成的团队,可以通过了解现有的实现方式、依赖关系、以及内部事件等途径,来确定哪些功能组可以作为微服务,提供最大的产品价值;而哪些剩下的功能,则可以酌情保留在单体架构中。
13.微服务的独立数据存储
每个微服务都需要有一个数据存储库,这在某种程度上给分离数据的管理增加了难度。由于单个存储系统很容易因为失去同步,而出现不一致性,因此您需要使用能够执行主数据管理(master data management,MDM)的工具。例如,它可以通过检查每个订阅者ID的数据库,及时发现其中是否存在相同的ID。据此,就算某个服务停止了工作,它也能够确保用户数据的安全性。当然,最理想的状况是将数据同时存储在微服务和单体表中。
14.保留微服务的代码
通常,我们与其在性能良好的微服务中添加、重写一段代码,不如为新的或更改后的代码创建或部署一个新的微服务。据此,我们不但可以简化新代码的测试,而且能够减少现有服务在微服务中出错的可能性。
15.微服务的单独构建
通过对每个微服务采取单独的构建,我们可以在存储库中,以适当的修订级别获取组件文件。
16.在容器中部署微服务
为了尽量简化,我们最好使用同一种工具,在容器中部署微服务。例如,Docker便是被广为推荐的一种容器标准。
17.典型的成功迁移案例
Netflix(奈飞)
为了能够全天候地运营,Netflix需要一种架构来优化交付速度,并扩展到下一个数据量级。因此,Netflix决定摆脱数据中心里由关系型数据库所带来的,在垂直向扩展时的单点故障,使用NoSQL数据库对数据模型进行非规范化处理。同时,该公司采用了由云服务提供的高度可靠的、可横向扩展的分布式系统,并通过选择AWS作为云服务提供商,获得了大规模且广泛的服务和功能。此外,微服务架构也方便Netflix将系统分成独立的服务,其中包括:存储所有观看节目的服务,负责每月信用卡支付的服务,以及分析观看历史以提供类似电影节目的服务。该公司的全部迁移过程耗时整整七年。
Netflix微服务基础设施的逻辑图
Wix.com
由于Wix.com的应用程序是彼此连接的,因此系统一旦在某个部分出现问题,都会导致整个系统的崩溃。对此,Wix.com开创了新的集成和端到端测试模式,运用JSON/RPC协议,在SpringMVC的基础上,构建了一套微服务框架。通过迁移,它们解决了处理微服务之间的通信、故障与调试等的技术债。
Cloud Elements
Cloud Elements使用诸如Minikube和Docker之类的工具,管理本地和远程运行的服务。由于所有的微服务都在Node.js中,因此他们使用诸如Ava等基于npm的单元测试包,实现了代码测试的全覆盖,以应对业务的指数增长,并根据新增的需求不断迭代其微服务。
Best Buy(百思买)
过去,相互依赖的架构造成了Best Buy在业务部署上的难题。长时间的宕机给其在线业务的维持带来了不小的挑战。开发团队往往需要把新的功能逐个打包,再累计发布。如今,他们通过诸如:Chef和Jenkins等工具,实现了持续集成与部署,并且将数据库迁移到了Riak(一个分布式NoSQL键值数据存储)上。
18.小结
综上所述,我们是否应该跟上软件架构的趋势,放弃单体架构,投入微服务的怀抱,目前尚无绝对的定论。我的观点是:如果目标项目既没有高负载,又无频繁地与外部服务交互的需求,那么我们便可以选择或维持单体架构;而如果系统必须在大量的负载和服务请求下工作,那么微服务架构会是更好的选择。
我们再来看企业的组织结构层面。如果贵公司只有一个开发团队,那么建议您集中精力构建和维护单体架构;但是如果您有几个IT团队,可以同时开发同一个产品的话,微服务会比较合适一些。
客观而言,微服务架构有利有弊,它只是构建软件的另一种方式。是否应该选择完全取决于应用程序的业务需求。当然,您也可以从一个简单的单体架构开始,随着服务需求的增长,慢慢将应用组件独立出来,并迁移到微服务中。这可能是更为稳妥的应用实践。
原文链接:https://dzone.com/articles/Monolith-vs-microservices-architecture-split-or-no
译者介绍
陈峻 (Julian Chen),51CTO社区编辑,具有十多年的IT项目实施经验,善于对内外部资源与风险实施管控,专注传播网络与信息安全知识与经验;持续以博文、专题和译文等形式,分享前沿技术与新知;经常以线上、线下等方式,开展信息安全类培训与授课。