Sean Kelly 是 Komad 的首席工程师,在去年举行的波士顿 Golang 开发者见面会上,他做了一次关于微服务使用体验的闪电式演讲,之后他写了一篇文章。他以人们应该有所期待的内容作为开场:
我即将讲到一些有关微服务的谬论和误解,有些人坚定地认为对一个遗留的单体应用进行拆分就能挽救局面。我不希望这篇博文的观点变成“微服务 == 拙劣”,如果阅读这篇博文的人有想不明白迁移到微服务是否真正适合他们的话,那么最好请他们离开。
当然,有关微服务的讨论都是从试图定义清楚微服务是什么或不是什么开始的。不过,就像 Sean 指出的那样,根本不存在“完美”或被一致认可的定义。
这意味着在实践过程中,微服务只能在有限的领域发挥作用,所以它在你的架构里只做那些必要的事情,不会超出对它定义的范围。
大部分微服务开发者使用 REST(HTTP)或 RPC 协议作为微服务内外部的通信手段,导致开发者们认为微服务开发是一件很简单的事情。
我们只是用某种 REST API 封装了领域的一小部分,然后让它们通过网络进行交互。
不幸的是,这也恰是 Sean 想要表达的核心观点。从他的经验来看,这会把我们引向五种似是而非的微服务“真相”。首先,它们会让代码更干净。不过不管怎样,就像他说的,“你不必因为网络边界问题的存在才想把代码写好”。
事实上,微服务或者其它任何一种用来构建技术栈的手段,都不是写出干净或可维护代码的必要条件。因为涉及的因素少了,写出糟糕或缺少想法代码的几率也跟着减小,这个才是事实的真相。不然的话,等于说通过移除商店橱窗里的诱人商品就可以降低犯罪率。实际上问题并没有得到解决,你只是简单粗暴地舍弃了一些可选的东西。
Sean 说更粗粒度的“逻辑”服务架构或许会是更好的方案,至少在刚开始的时候是这样的。根据 Sean 的说法,使用这种方案替代微服务的好处之一是它可以减少网络通信开销。他还说这种方案与面向服务架构非常类似。那么问题来了:在面向服务架构和微服务架构之间有什么不同点吗?我们之前也针对这个问题进行过讨论。
Sean 所说的微服务的第二个“真相”是“目的性简单的事情容易完成”。
事情在刚开始可能看起来很简单,但大部分领域(特别是在那些需要构建原型、建立枢纽且要多次重定义领域的初创公司里)并不适合被分割成更小的块。有些领域经常需要从外部获取数据来完成内部的工作。如果需要把写数据的工作委托到领域外部,那么情况会变得更加复杂。一旦冲破自己能够支配的区域,在请求链条里引入第三方来操作数据,那么你就进入了分布式事务的领地(有时也被称为 Sagas)。
好吧,我们得承认 Sagas 只是分布式事务的一种形式,并非所有的分布式事务都是 Sagas!Sean 的主要意思是说,把多个远程服务调用包含在一个请求里会带来很多复杂性。例如,它们应该被并行调用还是串行调用?错误应该如何处理?最近我们就从 Alvaro Videla 那里听到一些关于这些复杂性的例子。
Sean 所说的第三个“真相”是“微服务比单体更快”。
这点很难撇清楚,因为通过减少工作量或减少启动依赖项也能够让系统快起来。不过这终究是个非正式的结论。我相信正在使用微服务的同僚们能够看到被分离出去的个体服务代码确实是快了起来,不过同时也在互相调用间加入了额外的网络开销。网络调用永远不可能跟本地调用一样快,虽然通常被认为“足够”快。
Sean 认为,有些人所说的微服务变快,可能是由其它因素导致的,特别是当使用了新的编程语言或新的技术栈进行重构或重新实现。如果这些语言或技术栈被用在原来的单体系统上,或许性能也会得到改善?
第四个“真相”是“开发者可以更容易地在独立代码库上工作”。Sean 可能因此得出的结论是“太多的开发者工作在独立代码库上会导致‘不是我的问题’综合症”,引入微服务架构可能导致的问题会让它所带来的任何一个优势都黯淡无光。
最大的一个问题是,你必须不断增加服务数量来完成哪怕很小的一个改动。这意味着你要投入时间和精力为开发者构建和维护一个可以在本地运行所有组件的简便方案。[…] 另外,这也会加大编写测试用例的难度,编写一个恰当的集成测试用例要求对所有涉及到的服务调用了如指掌,并且要考虑所有可能出现的错误情况。
第五个也是最后一个“真相”——“因为有了 Docker,处理自动伸缩变得非常容易”。
为了横向扩展,把服务打包成相互独立的单元,然后使用 Docker 这样的容器来部署,可以说这是一个不错的方案。不过,如果说只有在微服务架构里才能这么做那就不对了。其实单体应用也可以使用这种方式。[…] 如果微服务在一开始让你选择了这种方式,那么你也可以把它应用在单体系统上。
Sean 在结束他的演讲(博文)之前,讨论了开发者应该在什么时候使用微服务。他认为开发者和架构师是否理解自己的工作领域是很重要的,并以此展开讨论:
如果你无法理解你所工作的领域,或者还在理解的路上,那么微服务可能带来的问题会比好处多。如果你对它们有了深入的理解,你就会知道边界在哪里,就会知道依赖关系是怎样的,那么微服务会是正确的选择。
Sean 接着讨论了理解工作流的重要性(又一个关于分布式事务的问题)。除了理解工作流,能够对它们进行监控也非常重要,甚至比在单体系统里还要重要,因为你会发现,要精确定位造成性能瓶颈或发生错误的微服务会更难。在某种程度上,Sean 提出的在使用微服务之前先把架构理解透彻的建议跟过去其他人所说的如出一辙,比如 Simon Brown 在谈论分布式泥球时所说的:
如果你正在构建一个单体系统,而它正在变成一个大泥球,那么也许你该想想是否对自己的软件架构做了足够的功课。你是否真正理解它们核心的结构化抽象?它们的接口和责任是否有清晰的定义?如果你还没有搞清楚这些问题,那么你凭什么认为使用微服务架构会给你带来好处?当然,虽然物理上的服务分离没有什么捷径可走,不过在单体系统组件上应用服务分离也是可以达到预期效果的。
让我们回到 Sean 的话题上。基于以上内容,针对人们看待微服务的方式,Sean 会给出怎样的建议?
如果有人问我这个问题,我的建议是构建“内部”服务。通过在代码里定义清晰的模块,再根据实际需要把它们归并到各自的服务里。当然,这样做不是必需的,它本身也不是坏代码的灵丹妙药。但它会让你的系统走得更远,跑得更快,然后你可以尝试逐步往微服务迁移。
查看英文原文: Komad Principal Engineer Sean Kelly on Microservice Fallacies
感谢夏雪对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们。
评论