2018年“微服务”已死?

微服务在过去几年成为一个非常受欢迎的话题。所谓的“微服务疯狂”就像这样:

Netflix在devops上非常棒,Netfix也做微服务,因此:如果我做微服务,我非常擅长devops。

很多情况下,我们已经付出了巨大的努力来采用微服务模式,而不必知道如何将成本和收益应用于解决当前的具体问题。

我将详细描述微服务是什么,为什么这种模式非常吸引人,以及一些因微服务提出的关键挑战。

如果你正在考虑微服务是否适合你的模式,我会用一系列简单的问题来结束这个问题。 问题列表参见文末。

什么是微服务?为何微服务如此火热?

让我们从头开始。以下是一个假想的视频共享平台的实现方式,首先是以一个单体(monolith,译者注)的形式,然后以微服务的形式实现:

两者的区别在于第一种是单一的大单元, 一块巨石。 第二是一组小的,具体的服务、每个服务都有特定的作用。

细致地观察上图,很容易看出许多潜在的好处:

独立开发:小型、独立组件可以由小型独立团队构建。一个小组可以改变“上传”服务,而不会干扰“转码”等其它服务,甚至不了解这个服务。 熟悉组件的时间大大减少,开发新功能也更容易。

独立部署:每个单独的组件都可以独立部署。 这样可以以更快的速度和更少的风险发布新功能。“Streaming”组件的修复或功能可以部署,而不需要依赖其他组件。

独立的可扩展性:每个组件可以相互独立地进行缩放。在繁忙时段发布新节目时,可以扩容“下载”组件,以处理增加的负载,而不必扩容每个组件,这使得弹性缩放更加可行,并且降低了成本。

可重用性:组件执行一个小的,特定的功能。 这意味着它可以更容易地适用于其它系统,服务或产品。“转码”组件可以被其它业务部门使用,甚至可以变成一个新的业务,也许为其它组提供转码服务。

微服务模式的好处显而易见,但是 - 为什么这种模式最近才流行? 我以前都干了些什么?

这个问题有两个答案。 其中之一是,限于我们的技术能力,另一个是最近的技术进步使我们能够把它提升到一个新的水平。

当我开始写这个问题的答案时,它变成了一个长篇大论,所以实际上我将把它分成另一篇文章,稍后再发表。在这我将跳过从单个程序到多个程序的过程,忽略ESB和SOA,组件设计和有限的上下文等等。有兴趣的人可以分开阅读更多关于这个历程的详细信息。 相反,我会说在很多方面我们已经这样做了一段时间,但是随着最近容器技术(特别是Docker)和配合技术(如Kubernetes,Mesos,Consul等等)的普及, 从技术的角度来看,这种模式变得更加可行。

所以,如果我们把它看作是我们可以实施微服务安排的话,我们就需要仔细考虑:我们已经看到了理论上的收益,但挑战又如何呢?

微服务有什么问题呢?

如果微服务是如此之好,那有什么大不了的问题呢?

以下是我见过的一些最大的问题。

开发人员的复杂性增加

对于开发者来说事情会变得更加困难。在开发人员想要在旅行中工作,或者他们开发的功能跨许多服务的情况下,开发人员必须在他们的机器上运行或者连接到微服务。 这通常比简单地运行单个程序更复杂。

这个挑战可以通过工具得到部分缓解,但随着构成系统的服务数量的增加,开发人员在整个系统运行时将面临的挑战也越来越多。

运维者的复杂性增加

对于运维团队来说,潜在的复杂性是一个巨大的挑战。他们不是管理几个正在运行的服务,而是管理数十,数百或数千个正在运行的服务。 有更多的服务,更多的沟通途径,以及更多潜在的失败。

Devops的复杂度增加

阅读以上两点,可能会感到运维和开发是分开处理的。考虑到devops作为一种实践的普及(我是一个很大的支持者),无法减轻它的复杂度吗?

面临的挑战是,许多组织仍然依靠独立的开发和运营团队来运行 - 而一家组织则更应该采用微服务。

对于已经采用了devops的组织来说,降低复杂度仍然很难。既是开发者又是运营者,已经非常艰难(但是要建立好的软件却很关键),同时也必须了解容器编排系统的细微差别,特别是快速发展的系统是非常困难的。这使我想到下一点。

需要非常专业的知识

当由专家完成时,结果可能是美好的。 但想象一下,一个组织通常不可能只靠一个单体系统就能顺利运行。有什么可能的原因会增加系统的数量,从而增加运维的复杂性呢?

是的,通过有效的自动化,监控和编排等,这一切都是可能的。 但挑战很少是技术 - 挑战是找到能够有效使用的人。 目前这些技能需求非常高,可能很难找到。

真实世界的系统往往界限不分明

在我们用来描述微服务的好处的所有例子中,我们谈到了独立的组件。 但是在很多情况下,组件并不是独立的。 在论文中,某些领域可能看起来有限,但是当你进入泥泞的细节时,你会发现他们比你预期的更具挑战性。

这是事情变得非常复杂的地方。 如果你的边界实际上没有被很好地定义,那么会发生什么,即使理论上可以孤立地部署服务,你会发现由于服务之间的相互依赖关系,你必须将一组服务作为一个集合来部署。

这意味着你需要管理协同工作的版本,这些版本的服务在合作时经过验证和测试。而你实际上没有可独立部署的系统,因为要部署新功能,需要仔细编排许多服务的同时部署。

状态的复杂性往往被忽略

在前面的例子中,我提到一个功能部署可能需要同时部署多个版本的许多服务。 假设合理的部署技术将缓解这种情况,例如蓝/绿部署(大多数服务编排平台很容易处理),或者并行运行多个服务版本的服务,以及决定使用哪个版本的消费通道。

如果服务是无状态的,这些技术可以减轻很多挑战。无状态的服务非常坦率,容易处理。 事实上,对于无状态的服务,那么我会倾向于考虑跳过微服务,并考虑使用无服务器(Serverless)模型。

实际上,许多服务需要状态。我们的视频共享平台中的一个例子是订阅服务。订阅服务的新版本可以以不同形状将数据存储在订阅数据库中。 如果同时运行这两个服务,则一次运行两个schema。 如果进行了蓝绿色部署,而其它服务依赖于新形状中的数据,则必须同时更新这些数据,并且如果订阅服务部署失败并回滚,则可能还需要回滚,并且级联响应。

同样,有人可能会想到,在NoSQL数据库中,这些schema问题会消失,但事实并非如此。不强制执行schema的数据库不会导致无schema系统 - 它们只是意味着schema往往是在应用程序级而不是数据库级进行管理的。理解数据的形成和演变这一基本挑战是不能消除的。

沟通的复杂性往往被忽略

当你建立一个相互依赖的大型服务网络时,可能会有很多的服务间通信。 我们必须考虑到网络调用会失败,这意味着当一个服务调用另一个服务时,它应该至少需要重试几次。当一个服务可能调用很多服务时,我们最终会遇到一个复杂的情况。

想象一下,用户在视频共享服务中上传视频。 我们可能需要运行上传服务,将数据传递到转码服务,更新订阅,更新建议等等。 所有这些调用都需要一定程度的协同,如果调用失败,我们需要重试机制。

这个重试逻辑可能难以管理。试图同步做事往往会不可靠,失败点太多。 在这种情况下,更可靠的解决方案是使用异步模式来处理通信。 这里面临的挑战是异步模式固有地使系统有状态。 如前所述,分布式状态系统和有状态系统很难处理。

当一个微服务系统使用消息队列进行服务间通信时,你基本上有一个大的数据库(消息队列或代理)将这些服务粘合在一起。同样,虽然起初看起来似乎不是一个挑战,但schema会限制你。 X版本的服务可能会包含某种格式的消息,当发送服务发送的消息更改时,依赖于该消息的服务也将需要更新。

可以有许多不同格式的消息处理服务,但很难管理。现在,在部署新版本的服务时,你可能会有两次不同版本的服务尝试处理来自同一队列的消息,甚至可能是由不同版本的发送服务发送的消息。 这可能会导致复杂的边缘情况。 为了避免这些边缘情况,仅允许特定版本的消息存在可能更容易,这意味着你需要将一组服务的一组版本作为一个整体来部署,以确保先前版本的消息得到适当的排除。

这再次突出表明,当你考虑细节的时候,独立部署的想法可能不会像预期的那样简单。

版本控制可能很难

为了缓解前面提到的挑战,版本控制需要非常谨慎的管理。再次,可以有遵循像semver 类似的标准解决问题。 Semver是一个好的选择,但你仍然需要跟踪可以一起工作的服务和API的版本。

这可能会非常迅速地变得非常具有挑战性,并且可能会导致您不知道哪个版本的服务实际上可以一起正常工作。

在软件系统中管理依赖关系是非常困难的,无论是节点模块,Java模块,C库还是其它。独立组件消费同一个实体的冲突是很难处理的。

当依赖关系是静态的时候,这些挑战是很难处理的,但可以进行修补,更新,编辑等等。但是如果依赖关系本身是实时服务,那么你可能无法更新它们 – 你可能必须运行服务的许多版本(已经描述过这些挑战),或者下架整个系统直到系统得到修复。

分布式事务

在需要一个操作保持事务完整性的情况下,微服务可能会非常痛苦。 分布式状态很难处理,很多小的单位可能会很难进行编排事务。

试图通过使操作幂等性,提供重试机制等来避免这个问题可能是可行,在许多情况下可能起作用。 但可能有一些情况,只需要一个事务或失败(回滚,译者注)或成功,而不会处于中间状态。在微服务模式中需要解决分布式事务一致性问题的可能是非常高的。

微服务可能是变相的庞然大物

是的,单独的服务和组件可能是单独部署的,但是在大多数情况下,你将不得不运行某种编排平台,比如Kubernetes。 如果你使用的是托管服务,例如Google的GKE或Amazon的EKS,则会带来管理群集的复杂性。

但是,如果你要自己管理集群,那么你将管理一个庞大而复杂的关键任务系统。虽然单个服务可能具有前面所述的所有优点,但你需要非常小心地管理群集。这个系统的部署、更新、故障转移等等都可能很困难。

在许多时候,总体收益仍然存在,但重要的是不要轻视或低估管理另一个庞大而复杂的系统的额外复杂性。 托管服务可能会有所帮助,但在这些服务都是新的(例如,Amazon EKS只是在2017年底才宣布)。

微服务疯狂之死!

通过仔细考虑决定可以避免疯狂。为了帮助解决这个问题,我列出一些问题以及相关答案:

最后的思考:不要混淆微服务和架构

我故意避免这篇文章中的“a”字(英文中的‘a’冠词,译者注)。 但是,我的朋友佐尔坦(Zoltan)在论证这篇文章的时候提到了一个很好的观点。

没有微服务体系结构。微服务只是组件的另一种模式或实现,没有什么比这更重要。无论微服务是否存在于系统中,都不意味着系统的体系结构得到了解决。

微服务在许多方面与打包和运维操作的技术过程有关,而不仅仅是系统的固有设计。考虑组件的适当边界仍然是工程系统中最重要的挑战之一。

无论你的服务是否在Docker容器中,你总是需要仔细考虑如何将系统部署在一起。没有正确的答案,却有很多选择。

• 我希望你觉得这篇文章有趣! 一如既往,如果有任何疑问或想法,请在下面评论。

译者介绍:

楼炜 Jet,云技术社区金牌翻译,现任云星数据副总裁兼研发中心总监,业内资深的云计算专家, 10年云计算经验,7年+ IaaS、PaaS经验。著有: 《企业级IaaS架构的深度解析》、《企业级私有云构建的架构师阵型及架构策略》等文章

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20180226A1DRZJ00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券