前言 近来,几乎人人都在谈论微服务。开发人员都在研究Eric Evan的著作《领域驱动设计》。团队正在重构一体化应用,寻找限界上下文,并定义通用语言。虽然有不计其数的文章、视频和座谈可以帮助您转换到微服务,但很少有人愿意多花些时间来探讨一下某个具体的应用是否应该采用微服务。

使用微服务架构有很多充分的理由,但天下没有免费的午餐。微服务虽有诸多优势,但也增加了复杂性。团队应该积极应对这种复杂性,但前提是应用能够受益于微服务。

切忌盲目跟风,请负责任地考虑是否采用微服务架构

Matt Stine和我在最近与一家客户一起研究了他们的一些应用。我们的讨论以“一切都应该是微服务”为出发点,因为这在如今已经“司空见惯”。结果谈话陷入了僵局,大家就各种实施细节争论不休。

Matt在白板上写下了一组原则。这些简单的句子在这一天剩下的时间里指导着我们,我们审视应用架构的每个部分,寻找微服务可以交付价值的地方。这个列表彻底改变了对话的氛围,帮助团队制定了明智的架构决策。

为了不滥用微服务,我们列出了这组原则,帮助您集中精力开展工作。通过阅读下面的这些原则,看看特定的应用能否因某一个原则而受益。如果对于以下一个或多个原则,您的回答是“是”,那么这个功能就适合采用微服务。如果对于每个原则,您的回答都是“否”,那么您可能会给系统引入偶发复杂性。

01

多个变更速度

系统的各个部分是不是需要以不同的速度或向不同的方向发展?如果是,就分别采用微服务吧。这让每个组件都有了独立的生命周期。

在任何系统中都是一些模块很少受影响,而另一些模块似乎每次迭代都会发生变化。我们来举例说明,假设有一款用于在线零售的一体化电子商务应用。

在日常开发工作中,购物车(Cart)和库存(Inventory)功能基本上不会受影响。但我们可能会不断地试验推荐引擎(Recommendation Engine)。我们还想努力提高搜索(Search)能力。如果将这两个模块分别放入微服务中,它们的团队就能以更快的速度进行迭代,从而让我们快速交付业务价值。

02

独立的生命周期

如果一个模块需要有完全独立的生命周期(是指代码提交到生产的流程),那么它应该采用微服务。它应该有自己的代码存储库、CI/CD pipeline等。

范围越小,测试微服务就越容易。我记得以前遇到过一个项目,它的回归测试套件需要80个小时!不用说,我们并没有经常执行完整的回归测试(虽然我们真的想这么做)。微服务方法支持精细的回归测试。这为我们节省了大量的时间。我们能够及早发现问题。

测试不是我们采用微服务的唯一理由。在一些情况下,业务需求可能促使我们采用微服务架构。让我们以Widget.io一体化应用为例。

企业领导可能发现了新商机,而上市速度至关重要。如果我们决定向一体化应用添加必要的新功能,可能要花很长时间。我们的行动速度无法达到企业的要求。

但作为独立的微服务,“项目X”(如下所示)可以有自己的部署流水线。这个方法使我们能够迅速迭代,从新的业务商机中获利。

03

独立的可扩展性

如果系统各部分的负载或吞吐量特征不同,它们的扩展需求可能也不同。解决方案就是把这些组件放入独立的微服务中!这样一来,服务能够以不同的速度扩展。

即使粗略地看一下一般的架构,我们也会发现不同模块具有不同的扩展要求。我们从这个角度看一下Widget.io一体化应用。

最有可能的情况是,其中的帐户管理(Account Administration)功能并不需要承受订单处理(Order Processing)系统承受的那么多压力。过去,我们必须扩展整个一体化应用来支持最不稳定组件。这种方法会导致基础架构成本增加,因为我们不得不在应用的某个部分出现最坏情况时“过度调配”。

如果将订单处理(Order Processing)功能重构为微服务,我们可以根据需要扩展和收缩。结果就如这张图所示:

04

隔离故障

有时,我们希望将应用与特定类型的故障隔离开来。例如,当我们依赖一项外部服务但这个服务无法满足我们的可用性目标时,该怎么办?我们可以创建微服务,将这种依赖关系与系统的其余部分隔离。之后,我们可以在该服务中构建合适的故障转移机制。

在这里顺便给大家推荐一个架构交流群:617434785,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源。相信对于已经工作和遇到技术瓶颈的码友,在这个群里会有你需要的内容。

再来看一看我们的示例Widget.io一体化应用。库存(Inventory)功能恰好与一个遗留的数据仓库系统交互,而后者的正常运行时间不够好。如果将库存(Inventory)模块重构到微服务中,我们就可以在可用性方面实现服务级别目标。我们可能需要增加帐户冗余以应对脆弱的数据仓库系统。我们还可以引入一些最终一致性机制,比如Redis中的缓存清单。但现在,转型到微服务减轻了由于不可靠的第三方依赖关系而导致的性能不佳。

05

简化与外部依赖关系的交互

这个原则与“Isolated Failure”类似。换一种说法是:我们更专注于保护系统免受频繁变化的外部依赖关系的影响。(这也可能是供应商依赖关系,即把一个服务提供商换成另一个,比如更换负责付款处理的供应商)。

微服务相当于一个间接的层,把您与第三方依赖关系隔离。我们可以在核心应用与依赖关系之间部署一个由我们控制的抽象层,而不是直接调用依赖关系。此外,我们可以构建这个抽象层,让应用更便于使用,因为隐藏了依赖关系的复杂性。如果未来发生变更,必须进行迁移,那么变更将只限于“外观”,不需要更大规模的重构。

06

根据工作自由选择合适的技术

利用微服务,团队可以自由使用自己喜欢的技术堆栈。在某些情况下,一项业务要求恰好适合一项特定的技术选型。而其他时候,技术选型由开发人员的偏好和熟悉程度决定。

注意:这个原则并不是说可以随意使用任意技术!请向团队提供关于技术选型的指导。过多的分散堆栈会在认知上增加开销,比基于“一刀切”模型实现标准化更糟糕。为一个堆栈及时更新第三方存储库就已经很有挑战性了,更何况是将这种费力工作扩大四倍或五倍,会大大增加公司的负担。请采取有效措施,关注那些您知道如何提供支持的“妥善方法”。

在Widget.io这个例子中,与其余模块相比,搜索(Search)功能可能会受益于不同的语言或数据库选择。如果需要,这么做非常简单。当然,出于其他原因,我们已经对它进行了重构!

文化

上面都是技术讨论。那么在文化上呢?

没有任何技术决策是凭空想出来的。因此,在深入了解精彩的微服务世界之前,先了解一下您的企业。您的组织结构是否能轻松支持微服务架构?根据康威定律,您的成功机率如何?

“经过深思熟虑的早期经验教训可能会抵消康威定律的效果。”

——- @jmckenty

Mel Conway在50年前总结说,任何企业设计的系统都会反映该企业的组织结构。换句话说,如果团队的组织结构不是小型自主团队,那么工程师不可能创造出由小型自主服务组成的软件。这种认识促成了反向康威操纵,即鼓励团队改变其组织结构,来反映他们渴望在应用中看到的架构。

您还应该考虑文化是否准备就绪。微服务提倡以小批量方式频繁进行更改,这种频率一般与传统的季度发布周期相冲突。利用微服务,您不会遇到代码冻结或“一窝蜂式”的代码集成。虽然基于微服务的架构肯定能在传统的瀑布式环境中运行,但您无法发挥它的全部优势。

还要考虑如何调配基础架构。关注自助服务和优化价值流的团队一般都采用微服务模式。Pivotal Cloud Foundry等平台帮助团队在几分钟内(而不是几周或几个月)快速部署、测试和优化服务。开发人员只需按一下按钮即可启动实例,这种做法能够推动实验和学习。Buildpack可以自动执行依赖关系管理。这意味着开发人员和运维人员可以专注于交付业务价值。

即使是你所在行业中的公司也可以从每年部署四次转型到一个月部署上千次。

最后,我们针对应用问两个具体问题:

这款应用是否有多个业务所有人?如果系统有多个独立的自主业务所有人,则会有两种不同变更来源。这种情况可能会导致冲突。利用微服务,您可以实现“独立的生命周期”,让不同的支持者满意。

这款应用是否由多个团队所有?多个团队开发一个系统的“协调成本”可能很高。因此请为他们定义API。之后,每个团队都可以使用Spring Cloud Contract构建独立的微服务,也可以使用Pact进行消费者驱动的合同

测试。

对于这些问题,如果您有任一项回答是“是”,那么您就应该使用微服务解决方案。

总结

微服务之路的想法是好的。但有不少团队在没有分析需求的情况下就踏上了微服务的浪潮。微服务非常强大,大家都想用!但一定要做出权衡取舍。而且必须要了解应用的业务推动因素,这是无可替代的,因为这对确定合适的架构方法至关重要。