【趋势】使用微服务,你考虑好了吗?

微服务已经成为了当前最热门的架构模式,然而也许微服务对你来说并不适用,继续阅读来寻找答案吧。


目前,几乎所有人都对微服务趋之若鹜。打开你的新闻聚合客户端你会发现,几乎每篇文章都在讲微服务架构,没有一个公司不是通过微服务技术拯救了他们的研发部门。也许你曾经在这么一家公司工作过,通过这种轻量魔术般的服务来解决了所有遗留系统带来的问题。

当然,事后看来,我们反而离真相更远了。就像我们能看到视力表最末行,其实是由于提前看过了视力表导致的。

作为一个尝试将单体应用拆分为微服务来拯救世界的公司员工,我将讨论微服务运动的一些主要谬误和陷阱。当然这篇博客并非简单的将微服务与不好划等号,只是希望大家通过阅读它能够思考微服务架构是否真的适合你们。

到底什么是微服务?

世界上没有标准的定义,微服务应该包含什么、不应该包含什么。当然一些人已经成功实施微服务的人将规范编撰成册。

我再强调一点,微服务不是一个单体。确切的说,单个微服务只处理一个非常有限的领域,它只处理它在你的技术栈中应当处理的工作。一个更确切一点的例子比如:一个银行在线银行业务中有一个“交易服务”(起名太困难,你懂就好),现在你打算增加一个访问用户交易记录的业务,你应当把它放到交易服务之外。

另外,大家谈论微服务时,总是隐含地讨论微服务彼此之间需要远程通讯。尽管他们是显而易见的不同进程,并且通常运行在不同的计算节点上。所以通常服务之间使用REST或者其他RPC协议进行通讯。

刚刚开始时,这一切看起来还非常简单。似乎我们只需要简单的把领域服务通过RESTAPI暴露给其他微服务,让微服务之间通过网络访问即可。然而根据我的经验,大多数人认为的五项事实实际上并非实情:

  1. 微服务能让代码更简洁;
  2. 只完成一项任务的代码更容易实现;
  3. 微服务比单体应用要快;
  4. 工程师不必同时在一个代码仓库里面开工;
  5. 更容易自动扩容缩容(在Docker的帮助下)。

谬误1:微服务能让我的代码更简洁

“不要把网络边界当作写更好代码的借口。”

一个简单的事实是,任何技术栈,包括微服务在内,都不能成为写更简洁更易于维护的代码的动力。虽然当条件减少时,你写出来不科学的代码的可能性会降低,但是这就像是通过减少商店里的贵重物品来降低犯罪率一样,没有解决任何问题。

一个流行的方法是围绕一个领域的逻辑服务构建你的代码结构。这反映了微服务的理念:它可以帮助你显式地管理领域所需的依赖关系,并使得关键业务逻辑不会蔓延到多个地方。此外这些服务之间的调用不再过度使用网络,也避免了一些潜在问题的发生。

这种方法的好处在于,基于良好的前期设计和对领域的准确理解,你很容易将它抽取出来,一旦你决定了采用微服务架构,它能帮助你非常准确地围绕微服务构建面向服务架构。一个坚固的SOA方法开始于代码本身,并随着时间地推移,将它扩展到整个技术栈当中。

谬误2:微服务容易实现

“分布式事务从来不简单。”

虽然最开始看起来非常简单,但是大多数领域(尤其是对那些初创公司需要经过多次原型迭代和改造的领域)并不适合将他们规规矩矩地划分成为不同的领域。通常一个特定的子领域需要访问其他子域的数据来正确地完成相应的工作。当需要向它自己以外的领域写入数据时,事情会变得更加的复杂。一旦你打破了自己的业务范围,并且需要其他人参与请求流来存储修改数据时,那你就必须面对分布式事务(有时被称作Sagas)。

在一个请求中涉及到多个远程服务需要通讯时,复杂的问题便随之而来了。例如调用是否可以并行,或者必须串行完成?你是否意识到这些调用中任何一个环节都有潜在地发生错误的可能性(包括应用错误和网络错误)?这对请求本身来说意味着什么?通常每个分布式事务都需要他们自己来处理可能发生的故障,这很可能带来巨大的工作量,不仅仅是错误的解析、错误的处理,更包括如何在出现错误时恢复事务。

谬误3:微服务更快

“一些简单的优化可以在单体系统中获得巨大的性能提升。”

这条似乎很难被否定,因为事实上你可以通过减少单个系统的依赖或者做事情的数量来提高他们的速度。但这是一个看起来如此的方法。我并不怀疑转向微服务架构后通过代码路径的隔离让系统速度提升,但是你也应该意识到,系统内增加了通过网络的调用。网络请求永远不会像同一系统中调用那样快,尽管通常它可以足够快。

此外,许多关于性能提升的故事实际上是在宣传一种新的语言或者技术栈带来的好处,而不仅仅是通过将代码架构迁移到微服务上。将原有系统从RubyonRails、Django或者NodeJS迁移至像Scala和Go(微服务架构中两种流行的选择),这样语言技术本身就能带来很多性能改善。但是这些语言并不真的“关心”是否工作在“微”服务里面,他们只是单纯的为了提高性能而存在。

此外,对于大多数应用来讲,CPU和内存永远不是性能瓶颈,I/O才是。通过网络进行的调用,会为你的系统增加更多的I/O请求。

谬误4:对开发人员更简单

“开发人员工作在彼此隔离的代码库时容易导致‘不是我的问题’综合症。”

虽然听起来一个小团队专注于一个问题上,处理问题会更加简单,然而这会带来许多其他的问题,比如更难以从根本上解决问题。

最大的问题是你必须多做许多工作,你必须运行越来越多的服务,即使为了很小的一个变化。这样你不得不投入一些精力来建立和维护能让工程师在本地运行他们的办法。Docker技术可以让着更容易些,但是仍需要有人来维护他们。

另外,这让写测试也变得更加困难,因为一个恰当的集成测试意味着需要理解并覆盖所有服务之间的彼此调用,以及捕获处理相应的错误等。这也意味着需要花更多的时间来理解系统才能更好的开发。虽然我永远不会说工程师花时间理解系统是在浪费时间,但是我要警告大家的是,不要过早地添加这些复杂性,除非你真的认为你需要他们。

最后,它也会造成一些社交上的问题。跨越多个服务的Bug需要多处修改才能解决,多个团队需要同步协调他们解决问题的进程。它也有可能造成一种情况,就是人们对Bug缺乏责任感,并尽可能地将问题推给其他团队。当工程师在同一个代码库中进行工作时,他们共享所有的知识,承担共同的责任,而不是成为孤立王国的国王和王后。

谬误5:可扩展性更强

“扩容微服务就像扩容单体应用一样简单。”

将服务打包成离散单元,然后通过类似Docker的方式进行扩展,这似乎是一个水平伸缩的好方法,不过遗憾的是,这种说法并不对。

说它不正确,是因为这种方法不仅仅能用于微服务,更可以用于单体服务。你可以为你的单体应用创建逻辑集群,只处理某项业务的流量。比如API请求、前端仪表盘和后台任务服务器可以在相同的代码库里面,但并不需要每个都处理三个不同的业务。

好处就像是微服务一样,不同的集群承担不同的工作负载,可以单独扩容一个集群来应对流量的激增。所以,虽然微服务提供了很多方法,你同样可以把这些方法引入到单体应用中去。

到底什么时候应该使用微服务架构呢?


“当你准备好成为一个工程化组织时。”

最后我想说,时间恰当时,可以迁移至微服务(或者你知道这是否是正确的开始方式)。

实现微服务的一个至关重要最坚实可行的重要步骤是,你能够正确理解你正在工作的领域。如果你不理解它,或者你正在试图弄清它,那么微服务则是有害无利。当你真正深刻地理解你的领域,知道边界在哪里依赖是什么,那么迁移至微服务架构才有可能是正确的选择。

另一个重要的事情是处理你的业务流,具体来说,就是业务如何进行分布式事务。如果你知道每一类请求通过系统的路径,并且了解每个路径上可能失败的位置、方式和原因,那么你可以着手开始构建一个处理请求的分布式模型。

除了了解您的业务流之外,还需要监控你的工作流程。监控是微服务和单体之争的事情,但是它应当是你的工程化的核心工作之一。因为你需要大量的数据来发现系统为何性能不佳甚至引发错误。只有你能找到一个可靠的方法来监视系统的各个部分,你才可以知道如何来优化它。

最后,当你真正可以向研发团队和业务方展示价值时,迁移到微服务才可以帮助你承担增长的业务、扩容和赚钱。虽然说尝试新鲜事物是有趣的,但是你真正开始前,应当明白对于许多公司来说,什么是他们的底线。如果因为一篇博客文章告诉你单体应用不科学,而导致新功能的延期交付进而影响到业务收入时,你必须去迎合你的业务。有时候这些权衡是值得的,有时候不是。能正确认识到当前应当着力解决的问题,并以此来做技术的权衡,长期来看才是真正有益的。

写在最后的

如果你问我应当怎么做,我建议通过代码中清晰定义的模块结构来建立内部服务,并且随着时间的推移,逐渐将他们划分成独立的服务。这种方法不一定是最好,但也不失为避免烂代码进入系统的一个方法。当你准备好时,它能很快地帮你迁移到微服务架构上。

相关内容推荐