微服务架构的转换并没有想象中那么容易,大部分技术领导者往往会低估项目的复杂性,从而犯下灾难性的错误。

在将单体系统转换为微服务之前,或者从零开始架构微服务,往往需要仔细思考清楚即将发生的技术和组织挑战

因此,我们对来自5个不同国家(从以色列到美国)的技术领导者进行了13次采访,总结并归纳了这些案例到这篇文章中。

这篇文章适合于拥有以下想法的读者:

  • 从单体系统转换到微服务架构。
  • 从富有经验的技术领导者那里收集见解。
  • 了解微服务的缺点和优点。
  • 避免灾难性的错误。
  • 在微服务方面做出更好的技术决策。

理解为什么

你可能犯的最大错误是没有带着明确目的就尝试转换成微服务架构。因此,你应该需要清楚并有真正的理由来支撑自己为什么要做这件事。

如果有一个当前运行良好的工作系统,那么你改变它的驱动力是什么?

仅仅因为微服务架构的流行而焦虑?但这并不意味着你必须跳上这一波浪潮。那么,这可能不是你的软件的最佳技术选择。

所以说,理解原因是至关重要的。这也同David Dawson, Steven McCord, 和 Avi Cavale所强调的观点一致。

“当客户要求我帮助他们实现微服务时,我问的第一个问题是,为什么?我所追寻的答案是:“我们想要系统变得更快 “和 “我们想利用云技术的优势”。但是,我会让他们意识到,微服务如果想要做得好,比架构一个单体系统更昂贵、更困难。这不仅仅会操作你的数据,而且会将你的数据模型形成关系网。这些操作将随时随地进行数据分区,往往可能伴随着数据丢失。这一切可能将你自己陷入到分布式计算的大坑之中。” - David Dawson,系统架构师

👉 推荐阅读:

明确定义什么是微服务

“不一定需要选择微服务,我可能会选择中等规模的服务。这不是从一个单体到数百个服务,而是更大的服务,与工程团队和业务垂直领域保持一致。” - Daniel Ben-Zvi,SimilarWeb的研发副总裁

如果你没有在什么是服务、微服务和功能之间找到正确的平衡点,那么你就会遇到:

  • 将你的应用分散得过少,因此不能享受微服务架构所带来的好处。
  • 过度分散你的应用,这意味着管理微服务本身的沉重代价将破坏微服务架构所能提供的价值(Avi Cavale)。

因此,对于你的公司来说,有一个非常明确的微服务特征的理念是很关键的。

你们是怎么做的?来自一个真实的微服务案例

“我们通过观察哪些代码片段,如果发生改变,就会产生指数级的测试案例来确定什么是微服务。我们开始剔除这些代码,因为我们的目标是减少我们为每一个变化所做的测试案例。如果这是你的目标,那么你对微服务的定义就与别人说的’我希望计费是一个微服务’不同。” - Avi Cavale,Shippable公司的联合创始人兼CEO

👉 推荐阅读:微服务与单体架构的对比

微服务架构的优势和劣势

微服务架构的优势

可扩展性:你可以分析看看每个小部分有什么要求,这将能够独立扩展应用程序的不同部分。

“对我来说,另一个最大的好处是,可以在任何虚拟机之外扩展这些容器。可以把这些容器放在我想要的任何一种配置中,因此我的应用程序完完全全具有可移植性。” - Steven McCord,ICX Media的创始人兼CTO

更容易维护:让不同的团队能够以相对独立的方式来处理不同的组件。

部署和配置最小化互相干扰:你可以在不影响其他服务的情况下部署和配置系统的微小部分。多个团队可以向生产环境提供不同的结果,而不会相互干扰和踩坑。

方便问题隔离:更容易隔离和检测问题。

更容易招聘:当你寻找开发人员或第三方供应商时,你只需要着重培训他们系统的这一小部分的相关内容。

职责清晰界定:一个团队负责一个特定的微服务。

足够深入了解:从事该工作的团队对其有深入的了解。

广泛的编程语言:可以使用不同的编程语言,这更多取决于什么最能满足微服务的目的。

更容易监督和理解:可以将你的庞大的代码库分成更多较小的项目。这允许你和你的团队更好地理解项目和它的代码。

更容易开放组件:当边界和接口被明确定义后,向新的业务部门或外部实体开放组件或现有功能就容易多了。

微服务架构的劣势

部署和互操作性:缺点是,部署和互操作性将会成为主要关注点。

编程语言太多:这可能会限制你的代码重用性和可维护性,而且可能会让招聘变得更加复杂。

组件工作耦合:服务的组成总是需要它们一起工作运行。但这样会带来问题,那就是改变一处端点会破坏旧版本中的其他依赖服务。

更难进行集成测试:与所有东西都放在在一个地方的单体系统相比,更难对整个系统进行集成测试。

架构必须从一开始就经过深思熟虑:如果服务之间有太多的内聚力,那么就会失去大部分甚至所有的优势。

需要在通信方面付出更多:在服务之间的通信方面,必须进行投入更多成本。很多故障也可能发生在服务的通信之间。

难以监控整个系统:拥有大量的组件,这将是运维人员的噩梦。

学习成本:需要付出更多时间来学习如何使用微服务架构。

复杂性:越来越多的微服务使得整个系统更加复杂,更难监督整个操作。

“所有这些组件都是随意储存的。如果你没有很好的工程流程,最终会有一大堆东西储存在那里,可能根本就不会被使用。” - Avi Cavale,Shippable公司的联合创始人兼CEO

“在一个基于微服务的平台上调试生产问题是一个完全不同的操作。如果没有适当的监控、日志和追踪设施,系统的复杂性便会大大增加。这就像穿过一个迷宫的过程。因此工程实践和标准化变得至关重要。” - Daniel Ben-Zvi,SimilarWeb的研发副总裁

将日志记录在一个地方是具有挑战性的:第三方日志聚合服务,如Loggly、Splunk或Heroku,是非常好的解决方案,但它们的价格非常昂贵。根据我的经验,遥测特别是集中式日志是一个最大的痛苦。你必须考虑到每项服务的粗制滥造程度。如果你不这样做,你可能最终只在日志信息方面支付50-60%的费用。(Sonu Kumar,微软的网站可靠性工程师)

微服务架构的最大挑战和解决方案

当需要转换到微服务架构时,以下这些将是技术领导者和开发团队可能面临的最大挑战。

  • 挑战1:一次性转换系统
  • 挑战2:拆分系统
  • 挑战3:组织上的认同
  • 挑战4:团队

🔴 挑战1:一次性转换系统

“从单体架构转换到微服务架构,不是一次就能搞定的。如果是一个单体服务器,那么可能有存储库、部署任务、监控和许多其他的东西紧紧围绕着它配置部署。改变这一切并不容易。” - Brujo Benavides,Inaka的前CTO

“如果一个公司从来没有任何关于微服务的经验,即使是一个绿地项目也会比他们想象中的更要难。” - Viktor Tusa,LogMeIn的DevOps工程师

✅ 可能的解决方案

我们当时的做法是保留单体服务器,但任何新增加的内容都作为微服务来开发的,所以最终所有的东西都是从原来的服务器中分离出去的,直到最后成为我们最古老和最大的微服务。(Brujo Benavides)

🔴 挑战2:拆分系统

如果组件和服务从项目一开始就被耦合在一起,那么拆分它们可能是相当有挑战性的。(Robert Aistleitner)。

首先需要定义各部分之间的互动和流程。如果你并没有很好的定义方式,系统就会产生很多的问题。(Jose Alvarez, StyleSage的高级开发人员)

“这没有任何模式;有许多不同的规则可以将一个系统拆分成微服务,但没有人会告诉你在你的应用中应该如何做。因为这不会有两个完全相同的微服务”。- David Papp,Recart公司的首席架构师

✅ 可能的解决方案

“将单体系统拆分成微服务的唯一方法是,首先检查单体系统,看看它最大的痛点在哪里。应该把系统的这部分单独拎出来,并改造成微服务。” - Andras Fincza,Emarsys的工程副总裁

如果没有恰当的部署监控,你将不会看到你的系统是如何工作运行的。因此我们应当监控系统如何工作,它们在做什么。如果部署监控了系统,可以很容易地发现和解决问题。(Jose Alvarez)

逐步地、逐个模块地拆分一个单体系统是最好的方法。如果你想一次性做完所有事情,这必定会失败。

监测工具推荐:

  • New Relic
  • Datadog
  • Influxdb
  • Grafana

🔴 挑战3:组织上的认同

“获得组织上的认同可能是最难解决的部分”。 - Steven McCord,ICX Media的创始人兼CTO

这并不是一个技术上的决定。所以你需要明确说明微服务架构的好处,以此说服你的公司重新分配资源。在组织接受这样的变化之前,这是一个漫长而乏味的过程,组织越大,这个决定时间就会越长。

✅ 可能的解决方案

说服你的组织转换到微服务架构的最好方法是,只将系统中的一个非关键部分改造成微服务。这样你就可以用一个真实的、可运行的微服务来证明它的优势。

🔴 挑战 4: 团队

“最大的挑战发生在团队本身,因为它需要开发者拥有不同的思维。” - Avi Cavale,Shippable公司的联合创始人兼CEO

开发人员必须花更多的时间来理解什么是端到端的方案。他们需要熟悉技术,可能需要转换思维方式,这都是需要时间来沉淀。

对于那些一直在一个可以做端到端测试的世界里工作的人来说,这是不舒服的,现在你突然把它分解成许多小部分。这更像是一种文化上的改变。(Avi Cavale)

✅ 可能的解决方案

从非常小的部分开始,并在这部分获得受益,然后选择一些不是应用程序的关键部分。找一个小团队,把应用程序的那一部分改造成一个微服务。证明它实际上是更好的,然后一步一步地扩展到整个组织(Avi Cavale)。

避免犯这些错误

“避免一次性将整个系统转换到微服务”。- Andras Fincza,Emarsys公司的工程副总裁

“我想你可能犯的最大错误就是,还没有对转换为微服务架构可能产生的影响建立一个概述。在真正开始实施新方法之前,你必须拥有很多可移植的部分。” - Robert Aistleitner,Usernap的工程副总裁

“在单体系统中,改变内部接口很容易;只需从头到尾重构你的代码并运行你的测试。对于微服务,你的API必须是要看得比金子还贵。它是被依赖的,你不一定知道你所有的用户。如果没有对API的未来兼容,将来会产生很多麻烦。另外,确保你有一个分布式跟踪系统。” - Daniel Ben-Zvi,SimilarWeb的研发副总裁

“避免在没有搞清楚平台和依赖关系的情况下,就试图转换到微服务。另外,认为微服务就一定是好的,因为每一个微服务都可以用不同的语言编写,这是一种不好的观点。” - Viktor Tusa,LogMeIn的DevOps工程师

“处理数据是至关重要的。破坏数据是很容易的,但想要恢复却真的很难。数据迁移应该分更多的步骤进行。” - Andras Fincza,Emarsys的工程副总裁

“微服务之间共享数据是一个大忌。如果两个服务在操作相同的数据,你就会开始遇到一致性问题,并分不清所有权。” - Daniel Ben-Zvi和Varun Villait

“把一个应用程序分成太多和太小的部分,或者强迫把一个系统转换成不应该是微服务的微服务–而仅仅只是因为随大流”.–Csaba Kassai,Doctusoft的首席开发人员

转换微服务架构的最佳实践

在微服务之间建立隔离,使它们能够根据你的需要快速作出改变。这通常需要在几个层面上进行隔离:

运行时进程:这是最明显的,也是一般情况下的快速选择。以前你只有一个进程,现在你有了更多的进程。这里的主要成本是采用某种形式的分布式计算,这很难做得很好。这可能导致你采用容器化、事件架构、各种http管理方法、服务网格和熔断器。

团队/文化:分开团队,并给予每个团队自主权,就意味着你分隔了了人与人的交流。这往往会导致知识孤岛和工作重复(选择权与资源效率选择的工作)。

👉 推荐阅读:Peter Naur的 Programming as Theory Building

数据:采用像微服务这样的分布式计算方法的最大影响在于它对你的数据的影响。你已经以某种形式分离了你的数据,因此你需要在系统层面上重新整合它,以便给人以 “一个系统 “的印象。这在扩展方面带来了一些有趣的潜在好处,但它也需要比简单的单体数据架构方法多更多的思考。(David Dawson)

你应该为一个特定的微服务选择什么技术?

这里往往是不同意见开始碰撞出火花的地方……

一方认为,使用什么技术和编程语言并不重要。

“几乎所有的问题都可以用技术来解决。建议不应该花太多的时间来寻找正确的技术,而是以迭代的方式来做,这样就有更多的时间来思考它,并观察它在迭代中的效果如何。这样一来,错误的决定就可以得到缓解”。- Andras Fincza,Emarsys的工程副总裁

“大多数的现代语言(Python、Java、C#、Node/JavaScript)都同样快速和可扩展。从这个角度来看,语言并不重要。每种语言都有它们的优点和缺点。大多数时候,语言的选择是基于个人的喜好而不是技术上的争论”。- Viktor Tusa,LogMeIn的DevOps工程师

花费大量的时间来选择最好的技术是不值得的,因为差异实在是很小。

“选择技术的重要性被过分高估了。如果运行成本很重要,那么可以接受,但对我们来说并不那么重要”。- Andras Fincza,Emarsys的工程副总裁

“如果是一个全新的项目,那么我就使用我的程序员最熟悉的语言。如果不是新建项目,那么我就使用在客户端对系统中的业务实体覆盖率最好的语言”。- Viktor Tusa,LogMeIn的DevOps工程师

“微服务的好处之一就是它被封装在一个微服务中,只需要给一个外部的微服务接口来和它通信。我们只需要一个接口,并不关心其他内容。” - Steven McCord,ICX Media的创始人兼CTO

选择合适的技术不仅仅是一个技术问题,同时也是一个招聘决定。

如果你选择了一个有10种不同编程语言的微服务架构,那么需要确保你的团队能够处理这个问题。

“我不建议混用太多的编程语言,因为雇用人员会变得更加困难。另外,程序员的上下文切换也会拖慢开发速度。” - Robert Aistleitner,Usernap的工程副总裁

“必须有意识地选择你想建立什么类型的开发团队。如果你想使用许多不同的编程语言,你需要建立一个机动性强的团队,能够使用和学习不同的编程语言。” - Steven McCord,ICX Media的创始人兼首席技术官

一些技术建议

“我强烈建议使用管理服务,如谷歌云平台的AppEngine。它将管理服务变得更轻松。另外,在选择语言/技术/框架时,为特定的微服务用例选择合适的语言/技术/框架总是很重要的,不要因为你熟悉某个东西就强制使用它。"–Csaba Kassai,Doctusoft的首席开发者

来自Brujo Benavides的案例

另一方面,一些技术领导者很乐意推荐一些技术,这些技术可以很好地适用于特定角色的微服务。

在为微服务选择技术时,建议考虑:

  • 可维护性
  • 容错性
  • 可扩展性
  • 架构的成本
  • 部署的便捷性

Brujo的团队在微服务方面使用的一些框架/技术的案例。

  • 用于网络爬虫的Scrapy
  • Celery + RabbitMQ用于微服务的通信
  • NLTK + Tensorflow(和其他一些)用于机器学习部分
  • AWS服务

👉 推荐阅读:基于云的应用程序的技术选择案例研究

选择适当技术的过程

在为微服务选择编程语言/技术时,需要考虑很多事情。

最重要的事情之一就是看你的开发人员有什么能力,以及一种语言/技术背后有多大的支持(工具、社区……)。根据我的经验,公司往往会倾向于根据其开发人员的能力来选择一种编程语言。- Csaba Kassai,Doctusoft的首席开发人员

“尽量使用那些背后有大量支持(资源和活跃的社区)的技术。我推荐Ruby和JavaScript,因为你可以得到很多支持,如果出现问题,很多人可以帮助你。我认为只要你确保有很多人在使用它,选择这种语言应该不是问题。因为在这种情况下,就算你的团队不具备这种知识,也可以依靠外部资源。” - Varun Villait,Industry公司的CEO

“另一个因素则可能是一种语言存在哪些库,可以用来加快项目的进度。如果选择的理想语言没有某些库,那么可能不得不重新发明轮子,这可能是另一种时间的成本。显然,像容错性和可扩展性也应该是一个重要因素。如果你不得不在几个月后从头开始写一些代码,因为最初的选择不能扩展,那么你可能最好早点咬紧牙关。我认为这一切都归结于一个特定的团队情况和他们愿意做出的投资。” - Greg Neiheisel,Astronomer的联合创始人兼CTO

来自Emarsys的案例

在Emarsys,如果他们想采用一种新的编程语言,开发人员需要提供真实的、符合逻辑的理由,并与首席开发人员协商。团队会聚集在一起,讨论这项技术的优点和缺点。

他们总是能用不同的技术创造出一个顶级的解决方案。这让他们可以实验某项技术的边界,看看它是否可以应用于某项微服务。这对于揭开一项技术的局限性是完美的方法。

“建议使用你的团队已经熟悉的语言。这样他们可以更舒服地工作,进展也会更快。” - Andras Fincza,Emarsys的工程副总裁

来自similarweb的案例

作为一家大数据分析公司,我们要处理非常大规模的挑战,这增加了选择错误技术的风险和影响。单线程框架,如NodeJS,虽然很适合网络约束服务,但在处理实时密集型数据处理时将无法扩展。

工程师们通过平衡战术和战略需求,并通过观察技术和组织的限制来决定使用哪种技术。我们是否处于快速原型设计阶段?该服务是否处理大量的数据?我们是想在我们的堆栈中加入一项新技术,因为我们相信它的生态系统,还是使用我们已经掌握的现有技术?我们想当小白鼠吗?我们能找到对它充满热情的工程师吗?我们是否愿意长期致力于这项技术?一项技术的生态系统是一个主要因素。我们想参与开源社区,宁愿使用和贡献于现有的框架,而不是重新发明轮子。

一般来说,我们不希望技术太过分散;否则,你就无法获得专业知识。

定义明确的指导目录,甚至是一份检查清单,可以帮助促进健康的决策过程,缩小可能的技术选择,选择可能最适合你的团队和产品的技术。

来自David Dawson对选择技术的建议

  1. 从数据架构的角度来看,需要的是能够提供数据的,并且可以很容易地在服务之间的通信中同步一致可用的状态。这方面有多种方法,这些也是我在微服务部署中实际上寻找的。因此,你可以观察实现这类模式的各种框架和技术(这就是Kafka、Spring Data Flow、Akka和相关技术所在)。

  2. 一旦我们决定了这些模式和方法,就需要将其与所拥有的资源结合起来。如果你已经决定采用带有大量反应式编程的数据流方法,并且已经有了Java开发人员,那么选择Spring、Spring Cloud Data Flow和Kafka是有意义的,并且可能会部署到某种形式的Cloud Foundry(如果拥有资源的话!)。 如果需要大量较重的数据转换,可以使用Spark或Kafka Streams来帮助实现。如果有JavaScript开发人员,那么以上就没有意义了。相反,你会寻求在JS运行时采用一些功能语言(clojurescript等),再次使用一些类似的反应式集成技术(Kafka在这个领域肯定会掀起波澜),并从那里开始。

关键结论

  • 不要为选择完美的技术而紧张。而是采取一种迭代的、实验性的方法。
  • 每个微服务架构都是独一无二的;选择的技术应该与系统的需求相一致。
  • 请记住,太多不同的技术会使招聘变得更加复杂。

结论

当谈及转换到微服务架构时,总是伴随着很多挑战。

在将你的系统转换为微服务之前,应该需要清楚并有真正的理由来支撑自己为什么要做这件事。当然,最好了解一下微服务带来的优势和劣势。之后不要盲目跟随最新的潮流,应当要先考虑你的系统的独特功能,只改变系统中痛点最大的部分。也并不建议从头开始就使用微服务架构,因为一开始就明确定义微服务的边界是很困难的事情。

如果你决定转换微服务架构,可以采取渐进的方法,拿出系统中一小部分非关键的部分做出转换,看看它的改造效果如何。这也是为创建更多的微服务而获得组织支持的一个好方法。

为微服务选择完美的技术,没有最好的方法。每一个技术相关的决定都会受到你的团队当前知识的影响,也会受到公司未来招聘计划的影响。在某些情况下,为微服务选择技术更像是一个招聘决定,这取决于你想在未来建立什么样的开发者团队。

本文翻译自Microservice Architecture: All the Best Practices You Need to Know