深入探寻微服务【第一篇微服务的好】
引言
在开始聊微服务之前,我想先说一个现象。
不知道你有没有经历过这样的场景:一个项目从零开始,最开始只有两三个开发,大家写得很快,需求响应也很迅速。但是过了两年,团队扩展到几十人,代码库变得庞大无比,每次发布都需要小心翼翼,改了一行代码就可能影响到完全不相干的功能,构建一次需要十几分钟,线上出了问题要在一片代码海洋里定位——这种痛苦,我想经历过的人都懂。
这就是典型的单体架构之痛。而微服务,正是为了治疗这种“痛”而生的一种架构思想。
但我想先澄清一点:微服务不是银弹,它不是为了解决所有问题的万能钥匙。它是一把双刃剑,在解决某些问题的同时,也引入了一整套新的问题。理解微服务,本质上就是理解:它解决了什么,又带来了什么,以及我们为什么愿意为这些新问题买单。
这篇文章我会不带任何代码,不说任何框架,我们从头来理解微服务是个什么东西,以及它给我们带来了什么好处。
单体架构的困境
要理解微服务,首先要理解它的“前身”——单体架构。
1.1 什么是单体架构
单体架构,顾名思义,就是把一个应用的所有功能都打包在一个部署单元里。比如一个典型的电商系统,用户管理、商品管理、订单处理、库存管理、支付等等所有模块,都写在同一个代码仓库里,编译成一个WAR包或者JAR包,部署在一台服务器上运行。我们百万java学子写过的苍穹外卖和黑马点评就是典型的单体架构项目。
在最开始的时候,这其实是非常合理的做法:
开发简单:IDE打开一个项目,所有代码都在眼前
测试简单:启动一个应用,所有功能都能测试
部署简单:拷贝一个包到服务器,运行起来就行
运维简单:只需要关注一个进程的健康状态
但是,随着业务的发展和团队的扩大,这种“简单”正在一点点变质。
1.2 单体架构的痛点
痛点一:代码失控
当一个代码库有几十万行甚至上百万行代码,几百个表,各种模块之间有着千丝万缕的依赖关系时,没有人能说清楚整个系统是怎么运作的。你改了一个“看似安全”的工具类方法,结果某个遥远的模块出现了诡异的bug——因为那个模块依赖了你的改动,而你不知道。
痛点二:团队协作困难
假设有五个团队在同一个代码库上工作,他们都要修改不同的功能。分支策略变得异常复杂,合并冲突天天发生。A团队想上线一个新功能,但是B团队的代码还在测试中,两者被绑定在同一个发布周期里,互相等待、互相阻塞。
痛点三:部署效率低下
每次构建需要10分钟,跑完所有测试又需要15分钟。一天下来,真正有效编码的时间被大量稀释。而且因为每次改动都有可能影响全局,发布前需要做全面的回归测试,发布窗口越来越长,风险越来越高。
痛点四:扩展不灵活
整个系统是一个整体,当订单模块的流量暴增时,你没法只扩展订单模块——必须扩展整个应用。那些不需要扩容的模块也被迫跟着扩容,资源利用率很差。
痛点五:技术锁死
整个应用必须使用同一种技术栈。你想试试Go语言的性能优势?不行,因为Java项目没法混着Go部署。你想升级某个依赖库的版本?可能因为影响到其他模块而被拒绝。
这些问题本质上指向同一个根源:所有东西耦合在一起,无法独立变化。
而微服务的思想,正是要把“能够独立变化”这件事做到极致。
微服务的本质
2.1 什么是微服务
微服务没有一个官方的、唯一的定义。Martin Fowler和James Lewis在2014年那篇著名的文章《Microservices》中给出的描述是:
微服务架构是一种将单一应用程序划分为一组小型服务的方法,每个服务运行在自己的进程中,服务之间通过轻量级的通信机制(通常是HTTP/REST)进行协作。每个服务围绕业务能力构建,并且可以独立部署。
我提炼几个核心关键词来理解:
关键词一:“小”
每个服务的代码量应该是“一个人或一个小团队能在合理时间内理解和维护”的规模。这个“小”不是绝对的行数标准,而是一个认知负担的概念——一个人能hold住的范围。
关键词二:“独立进程”
每个微服务是一个独立的进程,有自己独立的运行环境。这意味着服务A重启不会影响服务B,服务A崩溃也不会拖垮服务B(当然,前提是调用方做好了容错)。
关键词三:“围绕业务能力构建”
这是最关键的一点。微服务的拆分边界不是技术层(比如把Controller层拆成一个服务,Service层拆成另一个),而是业务能力。比如电商系统按“用户”、“商品”、“订单”、“库存”来拆分,每个服务对应一个完整的业务领域。
关键词四:“独立部署”
每个服务可以独立编译、独立测试、独立发布。A服务一天发布十次,B服务一个月发布一次,互不干扰。
关键词五:“轻量级通信”
服务之间通过定义良好的API接口通信,通常是HTTP/REST或者消息队列。服务内部的技术实现对外部透明——只要接口不变,你用Java、Go还是Python重构,调用方完全无感知。
微服务的本质
如果用一句话概括微服务的本质,我想是:将复杂系统分解为多个可独立变化的部分,从而控制整体的复杂性。
这其实是计算机科学中一个古老而有效的思想——分而治之。不同的是,微服务把这个“分”从代码层面、模块层面,提升到了进程层面。
进程级别的隔离带来了一个质的变化:各个部分不仅逻辑上独立,物理上也独立了。这意味着它们可以各自演化、各自扩展、各自失败。
微服务带来的福利
在深入讨论微服务带来的问题之前,有必要先看看它带来的好处——因为正是这些好处让我们愿意接受那些随之而来的麻烦。
3.1 技术异构性
每个服务可以选择最适合自己场景的技术栈。订单服务需要高并发,可以用Go;数据分析服务需要丰富的AI库,可以用Python;核心业务服务追求稳定,可以用Java。新技术可以在小范围内试点,风险可控。
3.2 独立发布和快速迭代
这是最直接的好处。修改了订单服务,只需要构建、测试、发布订单服务。整个流程可以在几个小时内完成,而不用等整个大系统的发布窗口。
3.3 独立扩展
618大促期间,订单流量激增,只需要扩容订单服务的实例。用户服务和商品服务维持原有容量,资源利用更加精准高效。
3.4 故障隔离
支付服务因为第三方网关抖动而出问题,理论上只会影响支付功能,用户浏览商品、加入购物车等操作不受影响。系统整体的可用性得到了提升。
3.5 团队自治
每个团队负责一个或几个服务,拥有从需求到开发到上线到运维的完整所有权。团队可以自主选择技术、自主决定发布时间、自主管理自己的代码库。这种自治极大地提升了团队的积极性和效率。
总结
微服务就是解决,在单体项目不断的发展中遇到的团队协作困难,代码量巨大,各个功能强耦合在了一起的情况,按业务能力进行拆分,把一个单体项目拆分成多个服务,各自独立部署独立测试独立开发,但是我们说了微服务它不是银弹,它会引入很多问题,下一篇文章我们一起看看它究竟带来了什么问题。
更多推荐
所有评论(0)