微服务概述

什么是“微”服务?

如果你仔细观察,会发现我在上一行的标题中,将“微”打了个引号。

如果我们暂时去掉这个''微"字理解,微服务就是我们熟知的“服务端” 或者 “后端”。

现在让我们把微字加回来:-)

"微服务"(Microservices)由马丁·福勒(Martin Fowler)提出的一种架构理念,原文发表于2014年。

微服务是一种架构模式或者说是一种架构风格,它提倡将单一应用程序划分成一组小的服务,每个服务运行独立的自己的进程中,服务之间互相协调、互相配合,为用户提供最终价值。

我们抓三个关键点来理解:

  • 单一应用划分为一组更小的服务:将一个较大的、复杂的应用,拆分为多个小的服务。你可能会问:“这样不会增加复杂度么”?是的,会增加。但这种拆分也会带来明显的优点,我们后面会提到。

  • 独立的进程:每个微服务独立运行在自己的进程中,互不干扰。虽然这里并没有限制进程的部署方式,但可以想见,经过"划分"后的微服务,势必会产生众多进程。微服务是拆分而来的,他们之间势必存在逻辑的耦合。由此,会产生新的问题"微服务间的通信"。

  • 相互协调、配合:微服务的进程间需要通信、交互。从理论而言,所有IPC(Inter-Process Communacation,进程间通信)的方式都可以完成这个过程。但微服务的进程众多,很难完整地部署在同一台机器上,这势必产生跨主机的网络通信。所以,在微服务中,多采用RPC(Reomote Procedure Call,远程过程调用)的方式来完成通信。

上图展示了单体服务 和 微服务的区别。

为什么需要微服务?

在前文中,我们挖了一个坑:'微服务的划分会导致复杂度上升',为什么还要使用一项有缺陷的技术呢?

我们先讲第一个故事。

小张入职了一家互联网创业公司,一开始只有3个后端程序员,每天的工作是:和产品经理讨(si)论(bi)需求、写代(b)码(ug),改Bug,工作紧张但规律。服务端的上线窗口是周五下午:合并分支、代码Review、推送线上,一气呵成,不仅能准点下班,还能去吃个火锅。

过了两个月,行业赶上了风口,公司的业务快速发展,后端团队也快速膨胀到20人。然而,麻烦也接踵而至:大家修改的是同一个仓库下的服务端代码,"解冲突"成为了家常便饭,还发生了几次"一个小修改,破坏了其他业务主流程“的严重线上事故。

为了改善这种情况,老板招聘了2位QA(质量保证,测试)人员,由他们负责测试工作。然而,一个很小的改动都需要对整个后端服务的case进行全量回归测试。一个功能的开发需要1天,测试却耗费1周,迫于老板的压力,研发同学只能安慰自己:XX功能简单,不需要测试了,直接上线。

最终,周五成为了"噩梦日":周四晚上要提前开一个Excel表、统计好第二天要上线的需求,并按优先级排定顺序。周五全员提前1小时来公司,开始逐个逐个需求的"合并代码"”、"解冲突",“上线”、"观察" 、“回滚”、“修改代码”......

上线结束的收工时间从6点变成了9点,又逐渐拖到了11点,最后索性全员加班、通宵上线。技术团队的每一位同学,都感到身心俱疲。

听完这个故事,你是否有"似曾相识"的感觉?

科普一下,上述故事中的服务一般称作“单体服务” 或者 “巨石服务”(Monoliths)。

接下来,是第二个故事。

由于工作强度大、线上故障频发、团队士气低落,老板请来了老刘担任技术经理。

第一周:老刘带领团队将复杂、臃肿的"巨型服务"拆分成了“用户”、“订单”、“服务”三个微服务。

第二周:老刘将团队进行了上述类似的拆分,也分成了三个小组。

第三周:事情有了微妙的变化。分组后,合并代码引发的冲突减少了。开发业务时,多数的改动都封闭在单独的微服务内,改动造成的影响范围减少了,测试周期缩短了。

......

三个月后的一个周五的下午,(得益于提高的交付质量,以及微服务的独立并行上线),团队提前2小时完成了上线,距离上一次故障通报已经过去了两个月。

研发讨论群里,小张发了一条消息:“今天居然可以正点下班了,老刘真厉害!”

老刘回复:这是大家的努力的结果,真正“厉害”的应该是“微服务”。

听完这两个故事,我们来总结下微服务架构的两个优点:)

  • 逻辑清晰:一个微服务只负责一项(或少数几项)很明确的业务,逻辑更加简介清晰,易于理解。

  • 独立自治:每个微服务由一个小组负责。减少了跨团队的代码冲突,同时降低了改动的影响范围,提高了研发效率。

在故事之外,微服务架构还具有以下的优点:

  • 伸缩性强:相对于庞大的巨石服务,微服务更加独立,可以针对不同的性能需求,有选择的对不同微服务进行伸缩。举个栗子:明天有大促,产品预测:注册功能提升10倍,其他功能无波动。针对巨石服务,我们只能整体扩容10倍;微服务架构下,我们只需要10倍扩容用户微服务。

  • 技术异构性:每个微服务内可以使用不同的技术栈,甚至不同的开发语言。只要微服务之间使用统一的通信方式即可。

微服务架构有很多优势,那团队抓紧上马微服务吧?

微服务是“银弹”么?

直接泼一盆冷水:

There is no Silver Bullet. -- 《人月神话》

微服务不是“银弹”,它存在以下缺点:

  • 复杂度升高:在巨石服务中,所有修改都集中在同一个项目内;在微服务架构下,复杂功能的开发,需要同步修改多个微服务,复杂度骤然升高。

  • 性能损耗:原本在巨石服务中的方法调用,演变为微服务之间的跨进程、网络通信。性能会受到较大影响。

  • 可靠性陷阱:假设每个服务的可靠性都是99%,一个巨石服务,可靠性是99%、三个微服务的可靠性会下降到99% x 99% x 99% = 97%。

  • 运维难度加大:巨石服务被拆分成N个微服务,部署的数量翻倍的增长。此外,多组微服务的运行,也会增大运维、监控的难度。

有意思的是:"拆分"带来了优点,也引入了缺点。

夫尺有所短,寸有所长,物有所不足,智有所不明。 -- 《楚辞.屈原.卜居》

微服务架构也是如此,它的优缺点并存。

微服务适用什么场景?

什么场景适用微服务,什么场景不适用呢?

这篇文章[《When to use and not use microservices》](Best of 2020: When To Use - and Not To Use - Microservices - Container Journal)给出了一些建议:

适用微服务架构的场景:

  • 希望巨石服务能适应“可扩展性”、“敏捷性”、“可管理性”,提升交付速度时

  • 需要为(使用陈旧技术开发的)的老系统,迭代新功能时

  • 有一些相对独立的模块可以跨业务复用时:如登录、检索、身份验证等。

  • 构建需要快速交付、创新度高、敏捷的应用 / 服务

不适用微服务架构的场景:

  • 业务简单,无需处理复杂问题

  • 团队规模太小,尚无法负担微服务拆分带来的复杂度提升

  • 为了微服务而微服务

最后,引用马丁·福勒(Martin Fowler)论文的结尾做结束本节的讨论。

我们怀着谨慎、乐观的态度写了这篇文章。到目前为止,我们已经看到:微服务风格是一条非常值得探索的路。我们不能肯定地说,我们将在哪里结束,但软件开发的挑战之一是,你只能基于目前能拿到手的、不完善的信息作出决定。