最近几年好像大家都开始对微服务着迷,与此同时单体架构也在慢慢淡出人们的视线。
当然,热门的趋势总是来来去去,而且它们所受到的关注往往被媒体夸大了,实际情况并不总是如此。不过,对于微服务来说,人们似乎已经达成共识,认为这个趋势会一直存在下去。这是有道理的。从概念的角度来说,微服务扩展了工程师们几十年来采用的相同原则。
一旦你开始使用微服务架构,也许你需要本文中提到的5个规则,帮助你成功运行它们。
微服务的另一面
关注点分离(SoC)是一项设计原则,规定软件的构建应根据 "关注点 "或总体功能来确定不同的部分,30多年来一直被用来决定如何构建技术。在单体应用中,它体现在典型的3层架构中的表现层、业务层和数据层的分离。
微服务采用了这个概念,并将其颠覆。它们将同一个应用程序以这样的方式分离出来,应用程序的单一代码库可以被分解并单独部署。这样做的好处是巨大的,但也是有代价的,通常体现在时间和金钱两方面的运维成本较高。除了将现有的应用程序过渡到容器所带来的巨大的前期投资之外,维护该应用程序也带来了新的挑战。
挑战1:似乎很难监控整体
虽然单体应用程序也有其自身的挑战,但在单体中回滚一个“坏”版本的过程是相当简单的。在容器化应用中,事情就变得复杂许多。无论你是将单体应用逐步分解为微服务,还是从头开始构建一个新系统,你现在都有更多的服务需要监控。其中每一个都可能会:
- 使用不同的技术和/或语言。
- 运行在不同的机器和/或容器上
- 使用K8s或类似的技术进行容器化和编排
随之而来的是,系统变得高度分散,更需要集中监控。遗憾的是,这也意味着需要监控的东西也多了起来。以前只有一个单体进程,而现在可能有几十个容器化进程运行在不同的区域,有时甚至是不同的云。这意味着不再有一套单一的运维指标来统治它们,IT/运维团队可以用它来评估应用程序的一般正常运行时间。取而代之的是,团队现在必须处理数以百计(甚至数以千计)的指标、事件和告警类型,他们需要从中分离出有效信号和无效噪音。
解决方案
DevOps监控需要从扁平化的数据模型转向分层模型,在这种模型中,可以随时观察到一系列高级系统和业务KPI。只要有一点偏差,团队就必须能够进入指标层次结构,查看干扰来自于哪个微服务,并从那里了解实际发生故障的容器。这很可能需要从数据存储和可视化的角度重新调整DevOps工具链。开源的时序DB工具,诸如Prometheus和Grafana 7.0等使得这个目标非常容易实现。
挑战2:跨服务日志记录
在谈论监控应用程序时,首先要提出的事情之一是:日志、日志、日志。服务器每天都会产生的IT日志相当于碳的排放量,最终导致溢出的硬盘驱动器以及疯狂摄取、存储和工具成本。即使采用单体架构,你的日志也可能已经使你的工程师有些头疼。
使用微服务,日志变得更加分散。一个简单的用户业务现在可以通过许多服务进行,所有这些服务都有自己的日志记录框架。要解决问题,你必须从业务可能通过的所有服务中提取所有不同的日志,以了解问题所在。
解决方案
这里的主要挑战是了解单个业务如何在不同服务之间“流动”。为了实现这一点,需要对传统的单体程序在顺序业务执行期间通常如何记录所有事件的方式进行大量修改。尽管已经出现了许多框架来帮助开发人员进行处理(我们特别喜欢Jaeger的方法),但对于希望将单体重构为微服务的企业而言,转向异步、跟踪驱动的日志记录仍需要付出艰巨的努力。
挑战3:部署一项服务会破坏另一项服务
单片机世界中的一个关键假设是,所有代码都是在同一时间部署的,这意味着应用程序处于最脆弱状态的时间范围是一个已知的、相对较短的时间段(即部署后的前24-48小时)。在微服务的世界里,这个假设不再成立:由于微服务本质上是相互交织的,其中一个服务细微的变更可能会导致行为或性能问题,而这些问题会在另一个服务中体现出来。因此所面临的挑战是,当前出现故障的微服务使得另一个开发团队并没有预料到他们的代码会出现中断。这既会导致整个应用意外的不稳定性,也会导致一些组织内部的摩擦。虽然微服务架构可能让部署代码的过程变得更容易,但实际上却让部署后验证代码行为的过程变得更难。
解决方案
企业必须创建共享的发布日历,并且每当部署相关的微服务时,都要分配资源用于密切测试和监控整个应用的行为。在没有跨团队协调的情况下部署新版本的微服务,就像牛油果加吐司一样,是解决这一挑战的成功秘诀。
挑战4:难以找到问题的根本原因
在这一点上,你已经锁定了有问题的服务,提取了所有需要提取的数据,包括堆栈跟踪和日志中的一些变量值。你可能还有一些APM解决方案,比如New Relic、AppDynamics或Dynatrace。从那里,你会得到一些额外的数据,关于一些相关方法的异常高处理时间。但是......问题的根本原因呢?
你(希望)从日志中得到的前几位变量数据很可能不会是那些移动针的数据。它们通常更像是面包屑,指向下一条线索的方向,而不是更进一步的原因。在这一点上,我们需要尽我们所能,发掘出更多应用程序下的 "魔力"。传统上,这需要发出关于每个失败事务状态的详细信息(即到底为什么失败)。这里的挑战是,需要开发人员具有巨大的预见性,以知道他们需要哪些信息来提前排除问题。
解决方案
当微服务中的错误根源横跨多个服务时,制定一个集中的问题根源检测方法至关重要。团队必须考虑需要哪些信息颗粒来诊断未来的问题,以及它们应该在什么层级上发出日志,以考虑到性能和安全因素——这是一座高高的山,而且是一座永无止境的山。
挑战5:版本管理
我们认为值得强调的问题是,从典型的单体架构中的层模型过渡到微服务的图模型。由于超过80%的应用程序代码通常是第三方代码,因此在公司的不同微服务之间管理第三方代码的共享方式成为避免陷入前所未有的“依赖地狱”的关键因素。
考虑这样一种情况:一些团队在使用第三方组件或共享实例程序的X.Y版本(几乎所有公司都有),而其他团队则使用X.Z版本。这就增加了由于不同版本之间缺乏兼容性而产生的关键软件问题的风险,或者说,不同版本之间行为的轻微变化,可能会导致需要排查最特异和痛苦的软件bug。
而在这一切之前,我们还要提醒自己,任何一个微服务使用第三方代码的旧版本、更脆弱的版本,都会产生安全问题——这是黑客的天堂。允许不同的团队在孤岛般的repo中管理他们的依赖性,在单体世界中可能是可行的,但在微服务架构中,这是绝对不可以的。
解决方案
公司必须在重新设计他们的构建流程方面进行投资,以便为第三方和共享实用程序代码利用集中式artifact仓库(Artifactory将是其中之一)。团队应该只允许将自己的代码存储在单独的仓库中。
最后的思考
与科技行业的大多数进步一样,微服务采用了一个熟悉的概念,并将其颠覆。它们重新思考了大规模应用的设计、构建和维护方式。它们带来了许多好处,但也带来了新的挑战。当我们把这五个主要挑战放在一起看时,我们可以看到它们都源于同一个理念。因此,每当采用像微服务这样的新技术时,底线是既需要重新思考,也需要重新调整代码的构建、部署和观察方式。微服务所带来的优势是难以拒绝的——但风险也是巨大的。