这篇文章可能是给大家泼冷水,请各位理性看待。从书面上看,微服务听起来很好。它们是模块化、可扩展和容错的。很多公司使用这种模式取得了巨大的成功,所以微服务可能自然而然地成为卓越的架构和启动新应用程序的最佳方式。然而,大多数利用微服务取得成功的公司并不是从微服务开始的。考虑一下Airbnb和Twitter的例子,它们在超越了它们的单体后走了微服务路线,现在正在与它的复杂性作斗争。即使是使用微服务的成功公司,似乎也仍在摸索使其发挥作用的最佳方式。很明显,微服务有其自身的权衡因素。 从单体迁移到微服务也不是一件简单的事情,而创建一个未经测试的产品作为一个新的微服务则更加复杂。只有在评估了其他路径之后,才应该认真考虑微服务。
微服务只对成熟的产品可行
关于从微服务设计开始的话题,Martin Fowler洞察:
1. 几乎所有成功的微服务故事都是从一个单体开始的,这个单体变得太大,被分解了。
2. 几乎所有的案例都是以微服务系统的形式从头开始构建的,最后都陷入了严重的麻烦。
这种模式导致很多人认为,你不应该用微服务开始一个新的项目,即使你确信你的应用会足够大,使它值得。
第一个设计很少是完全优化的。任何新产品的前几次迭代都是在寻找用户真正需要的东西。因此,成功的关键在于保持敏捷,并且能够快速地改进、重新设计和重构。在这一点上,微服务显然比单体差。如果你没有搞定最初的设计,你就会有一个艰难的开始,因为重构一个微服务比重构一个单体要难得多。
你是一个初创企业还是在做一个新建项目?
作为一个初创企业(在这种经济环境下不太可能),你已经在与时间赛跑,在下一个坏事发生之前寻找突破口。你现在不需要可扩展性(可能在几年内也不需要),那么为什么要使用复杂的架构模型来忽视你的客户呢?
在从事新建项目时,也可以提出类似的论点,因为新建项目不受早期工作的限制,因此没有任何决策的依据。《构建微服务:Designing Fine-Grained Systems》一书的作者Sam Newman表示,用微服务来构建一个新建项目是非常困难的。
仍然相信,对现有的 "新 "系统进行分区要比对一个新的、新系统进行分区容易得多。你有更多的工作可以做。你有可以检查的代码,你可以与使用和维护该系统的人交谈。你也知道 "好 "是什么样子的--你有一个可以改变的工作系统,使你更容易知道什么时候你可能弄错了什么,或者在决策过程中过于激进。
微服务并不适合在企业内部使用
由于所有的移动部件,微服务部署需要强大的自动化。在正常情况下,我们可以依靠持续部署管道来完成工作--开发人员部署微服务,客户只需在线使用应用程序。这对于内部部署的应用程序来说是不可行的,因为开发人员会发布一个包,而客户则需要在他们的私有系统上手动部署和配置一切。微服务使所有这些任务变得特别有挑战性,所以这是一个与微服务架构不相称的发布模式。说白了,开发一个内部微服务应用程序是完全可行的。。然而,正如我们一路走来所意识到的,有几个挑战需要克服。在决定采用内部部署的微服务之前,请考虑以下几点:
1.企业内部微服务的版本管理规则更为严格。你必须跟踪参与发布的每个单独的微服务。
2.你必须进行彻底的集成和端到端测试,因为你不能在生产中测试。
3.如果不能直接进入生产环境,微服务应用程序的故障排除就会变得更加困难。
你的单体可能还有生命力
每个软件都有一个生命周期。你可能会因为一个单体的老旧和它的并发症而想把它废掉。但是扔掉一个正在工作的产品是一种浪费。只要稍加努力,你也许能从你目前的系统中再挤出几年好时光。
有两个时刻,似乎微服务是唯一的出路:
1. 纠结的代码库:很难在不破坏其他功能的情况下进行修改和添加功能。
2. 性能:你在扩展单体方面有困难。
模块化的单体
开发人员希望避免使用单体的一个常见原因是,单体有恶化成代码纠结的倾向。当我们走到这一步的时候,增加新的功能是很有挑战性的,因为所有的东西都是相互联系的。
但是,单体不一定是一团糟。以Shopify为例:他们拥有超过300万行的代码,是世界上最大的Rails单体之一。有一次,该系统发展得如此之大,给开发人员带来了很多麻烦。
该应用程序非常脆弱,新的代码会产生意想不到的影响。一个看似无害的改变可能会引发一连串不相关的测试失败。例如,如果计算运费的代码被调用到计算税率的代码中,那么改变我们计算税率的方式可能会影响运费计算的结果,但可能并不明显。这是高度耦合和缺乏边界的结果,这也导致了测试难以编写,而且在CI上运行非常缓慢。
Shopify没有将他们的整个单体重写为微服务,而是选择了模块化作为解决方案:
模块化有助于设计更好的单体和微服务。如果没有精心定义的模块,我们要么落入传统的分层单体(大泥球),要么更糟糕,成为分布式单体,结合了单体和微服务的最糟糕的特征。
模块化是一项大量的工作,这是事实。但它也增加了大量的价值,因为它使开发更直接。新的开发人员不必在开始修改之前了解整个应用程序。他们一次只需要熟悉一个模块。模块化使一个大的单体感觉很小。
模块化是过渡到微服务前的一个必要步骤,它可能是比微服务更好的解决方案。模块化单体与微服务中一样,通过将代码分割成独立的模块,解决了纠结的代码库问题。与微服务不同的是,微服务的通信是通过网络进行的,而单体中的模块则是通过内部API调用进行通信。
分层与模块化的单体。模块化单体与微服务架构的许多特征相同,但没有最困难的挑战
单体可以扩展
关于单体的另一个误解是它们不能扩展。如果你遇到了性能问题,并认为微服务是唯一的出路,请再想想。Shopify已经向我们展示了健壮的工程可以使单体在一个令人难以置信的规模上工作。
架构和技术栈将决定如何优化单体;这个过程几乎无一例外地从模块化开始,并可以利用云技术进行扩展。
部署单体的多个实例,并使用负载均衡来分配流量。
使用CDN分布静态资产和前端代码。
使用缓存来减少数据库的负载。
用边缘计算或无服务器功能实现高需求的功能。
如果它在工作,就不要修复它
如果我们用随着时间推移实现的增值功能的数量来衡量生产力,那么在生产力很强的情况下,转换架构就没有什么意义。
由于维护开销的原因,微服务最初是生产力较低的架构。随着单体的增长,它变得更加复杂,而且更难增加新的功能。微服务只有在线路交叉后才会有回报。
诚然,有些东西最终将不得不改变。但那可能是多年以后的事了,到那时,需求可能已经改变了--谁知道在此期间会出现什么新的架构模式呢?
布鲁克定律和开发人员的生产力
在《人月神话》(1975年)中,小弗雷德-布鲁克说:"为一个延期的软件项目增加人力会使它变得更延迟"。这种情况的发生是因为新的开发人员必须先接受指导,才能在复杂的代码库上工作。另外,随着团队的壮大,沟通的开销也在增加。更加难以组织和做出决定。
适用于复杂软件开发的布鲁克定律指出,在一个延期的软件项目中增加更多的开发人员只会使其花费更长的时间。微服务是减少布鲁克定律影响的一种方法。然而,这种影响只有在复杂而庞大的代码库中才能看到,因为在这种情况下,我们不能把开发分成不连续的任务。
在使用微服务之前,你必须确定布鲁克定律是否会影响你的单体。过早地切换到微服务,不会增加多少价值。
你准备好过渡了吗?
在你开始使用微服务之前,必须满足一些条件。在准备好你的单体的同时,你还需要:
1.建立持续集成和持续交付以实现自动部署。
2.实施快速配置,按需构建基础设施。
3.了解云原生技术栈,包括容器、Kubernetes和无服务器。
4.熟悉领域驱动设计、测试驱动开发和行为驱动开发。
5.重组团队,使之成为跨职能的团队,消除孤岛,扁平化层次,以便于创新。
6.培养一种DevOps文化,使开发人员和运营工作之间的界限变得模糊。
7.改变一个组织的文化可能需要几年时间。学习所有的知识需要几个月的时间。如果没有准备,向微服务的过渡是不可能成功的。
结论
我们可以用一句话来总结关于向微服务过渡的整个讨论:除非你有充分的理由,否则不要这样做。那些在没有准备和没有坚实设计的情况下开始微服务之旅的公司将有一个非常艰难的过程。在考虑将微服务作为一种选择之前,你需要实现关键的工程文化和伸缩特性。同时,如果你的系统表现良好,而且你还在以适当的速度开发功能,为什么要改变呢?
如有想了解更多软件设计与架构, 系统IT,企业信息化, 团队管理 资讯,请关注我的微信订阅号:
作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-Petter Liu Blog。