微服务那么火,我也该用微服务吗?——多个变更速度

259 阅读7分钟
原文链接: mp.weixin.qq.com

在这个系列的第一部分,我们列出了一组原则,帮助您判断何时使用微服务才是更有效的框架。今天我们来细讲一下第一个原则:多个变更速度

回顾

回想一下Widget.io这个示例,它是一款典型的购物应用。

我们发现购物车(Cart)和库存(Inventory)功能已经有段时间没有更新了。与此同时,推荐引擎(Recommendation Engine)和搜索(Search)功能却频繁修改过。

将推荐引擎(Recommendation Engine)和搜索(Search)这两个模块分离到微服务中,可以让各自的团队能够以更快地速度迭代。这种方法将帮助我们快速交付业务价值。

在这个虚构的例子中,我们可以简单地说“这些模块经常变化”。但这在现实世界是行不通的。我们如何找出应用中以不同速度发展的各个部分呢?更具体地说,如何找出变更速度远远快于其余部分的组件呢?

通常,软件开发人员更注重逻辑。但现在我们让感性和理性共同发挥作用。应用的哪个部分最可能受益于快速迭代,您可能已经隐隐察觉到了,此时请相信您的直觉!

但您不应该完全依赖感觉。我们可以使用源代码管理系统来查看代码的“热图(heat map)”。以Git存储库为例,可以使用常用的Linux工具,通过几个命令行选项来运行Git日志。我们可以使用类似如下的命令生成提交次数最多的“前十个文件列表”:

我们对一个热门开源项目(比如Spring)运行这个小脚本。(它不是一款一体化应用,只是做个范例。)查看日志后,我们看到了以下内容:

注意第四个条目:AnnotationUtils.java。这个文件引人注目,值得研究。

还有哪些其他方法可以找出适合进行微服务重构的候选组件?

面对一体化应用,您现在的任务有点像软件考古。您需要深入代码库去寻找。这项工作让人想起了“搅动”这个概念(concept of churn),它首先由Michael Feathers提出。“搅动(churn)” 是一种可以制定重构决策的方法。当您查看指定项目的文件“搅动”情况时,您几乎总能看到“长尾”分布。通过查看这个直方图,您会发现一些文件不断变化,而另一些文件从初次提交之后就没有变过。根据Feathers的工作成果,Chad Fowler创造了Turbulence,利用它可以查看代码库的“搅动”与复杂性状况。

我们还可以利用全新的“代码鉴定”工具(比如CodeScene)深入了解项目。CodeScene可以识别代码中的热点,帮助我们找出不易维护的区域。借助这些结果,我们还能发现应用中可能因指定开发人员离去而会面临风险的部分。

以Clojure这个项目为例:

通过深入了解Clojure的主要模块,core.clj跃入我们的眼帘。

“搅动”数量非常高,而且很显然Rich Hickey是主要作者。

我们可以在项目中使用这类工具,通过它们帮助您识别微服务转型的首要候选组件。

还有其他简便方法吗?只需看一下GitHub中的最后一次提交。您必然可以发现一些文件是最近修改过的,而其他文件几年都没有更新。Spring的文件就如下所示:

如果某个文件很久没有变更过,“变更速度”这个因素就不会促使我们对它采用独立的微服务模式。但是,如果看到一些“始终在变化”文件,我们就应该深入了解这些区域。

您还应该查看错误跟踪器和项目管理工具。缺陷密度可能把您引向有趣的方向。查看待办事项列表中的故事也很有意义。哪些模块看起来获得了大量关注?这些模块值得研究。

利用这些工具和我们的直觉,我们就能知道哪些组件的变更频率更高。现在,我们需要将它们与应用的其余部分解耦。如何做到这一点呢?

幸好,有一项经过验证的技术适用于这个任务!

应用扼杀模式

扼杀模式由Martin Fowler提出,是一种处理遗留系统重写的方法。Fowler的灵感来自于他在去澳大利亚的旅途中遇到的扼杀藤蔓。这些藤蔓把种子撒在无花果树的枝杈上。藤蔓慢慢地向土壤延伸,同时慢慢杀死寄主树。

扼杀应用:使用事件拦截和资产捕获来替换遗留应用。灵感来自于澳大利亚覆盖无花果树的扼杀藤蔓,扼杀应用会拦截事件和捕获资产,慢慢从宿主遗留应用中提取行为

如果运用到软件当中,这种方法表明突然的“淘汰和取代”升级是充满危险的。相反,扼杀模式认为,我们应该在旧系统的边缘构建新系统,随时间推移慢慢淘汰遗留应用。

扼杀模式(Strangler Pattern)

扼杀模式大大降低了项目的风险。您可以逐步改进应用,而不是进行大爆炸式的转型。运用一系列易于理解的小规模步骤提高成功率。您的团队还可以定期交付价值,同时认真监控实现淘汰一体化应用这一最终目标的进度。

当遗留系统的业务逻辑未知且准确性很重要时,使用数据驱动型扼杀模式. 

利用数据驱动型方法,我们可以进一步推进扼杀模式。已经找出了要重构的应用部分?但我们很可能不了解此模块功能的方方面面。不过我们可以应用实际数据来做指导,而不是冒着理解不全面的风险,为关键业务系统带来错误。

数据驱动型扼杀模式

数据驱动型扼杀模式在客户端(手机、Web浏览器、另一款应用)和遗留系统之间引入了一个代理层。这个代理层会拦截所有请求和响应,并记录结果。

代理层通过两种方式为您带来回报。第一,它可以提供关于当前系统的行为方式的重要信息。第二,利用这些数据,您可以测试新功能,以确保其适合遗留系统。

下面是这种配置的简单方框图:

显示代理层的方框图

在某些情况下,新的微服务甚至能够与遗留系统并行运行。代理层可以将请求路由至一体化遗留应用和新的微服务。它可以比较结果。如果结果不匹配,该层会默认“切换到”遗留系统,并记下“遗漏”,以待进一步检查。根据这些数据,我们可以继续强化新的微服务,同时针对新代码库将测试案例添加到测试套件中。这种方法进一步增加了我们对新代码的信心。

总结

我们已经完成了走向更大世界的第一步。我们的直觉以及一些代码考古学帮助我们找出系统中的多个变更速度。把多变的功能提取出来,采用微服务,最终结果将简化代码,并支持快速开发,这种开发的风险更低。

此外,在应用扼杀模式时,您可以放心维持现有功能,而不会产生新的错误。

当然,“变更速度”并不是我们转向微服务的唯一原因,请期待我们这个系列的下一篇文章!我们将介绍“独立的生命周期”。

准备好分解您的一体化应用了吗?

作者简介

Nathaniel T. Schutta是一名软件架构师,专门关注云计算以及构建实用的应用。作为多语言编程的倡导者,Nate撰写了多本著作,同时他是一位资深的发言人,定期在全球的各种会议、No Fluff Just Stuff座谈会、见面会、大学和用户组做演讲。Nate与Neal Ford和Matthew McCullough合著《Presentation Patterns》。

点击阅读原文,查看英文博客