微服务这几年越来越火,大家聊的也比较多,我刚开始学时大家也兴奋不已,为适应公司发展把单体项目拆分为微服务,当然后来肯定是一地鸡毛。我经历了公司从电商公司到 SaaS 人再到后面集团内部架构成熟稳定,业务也是经历高速发展,技术上也发生了翻天覆地变化。我把遇到的坑总结出来,抛砖引玉引发大家的思考和交流。
另外,微服务的定义大家可能早就耳熟能详了,不熟悉的可以参考维基百科:https://zh.wikipedia.org/wiki/微服务
。
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/ruoyi-vue-pro 视频教程:https://doc.iocoder.cn/video/ 初创期,为了快速验证业务价值,整个团队都在单体应用上开发,业务需求较多但并不复杂,团队7-8人4-5个服务,业务主要集中在某1-2个应用,迭代过程中也没有遇到什么问题,但第一版上线后需求逐渐增加开始暴露一些问题,从开发-->测试-->发布,遇到了代码合并冲突、代码遗漏问题,也想过一些办法效果不是很好(全靠人肉始终不是办法)。
业务上升期团队扩招,成员扩到20个左右,业务扩张继续在单体服务内开发已经不适合了,出现了下面这些问题
稳定性差,某些迭代 bug、Panic 是无法快速回滚,只能硬着头皮修复,例如:a 迭代先发布,b 迭代再发布,a 迭代 bug 只能修复不能回滚解决问题; 性能差,单 pod 是有 cpu、内存限制,某些模块高峰期 cpu、内存基本打满了,其它业务响应慢只能靠充钱解决,并不是长久之计; 扩展性差,多个业务都在一个服务内,也没考虑过做抽象提高扩展性,怎么方便怎么来模块之间相互耦合; 开发效率低,代码冲突、环境冲突、测试冲突和发布冲突严重,不同的迭代出现你等我,我等你的现象,开发周期严重拉长,有时候到无法容人地步。 大家可以对号入座,思考下是否正在经历?
问题明确了微服务拆分是大难题,到底应该按照啥粒度拆分合理?网上谈微服务文章多把你教会的少,基本没有参考价值,团队内也没有经验丰富的老手,只能摸着石头过河。索性我们按照功能来划分,一个功能一个微服务,有些复杂业务甚至达到 3 个微服务,没考虑太多先拆再看。
我们拆服务用了一些骚操作,开发语言是 GO,rpc 没有大规模的应用经验,平时用 get get 引包方式比较爽,a 服务调用 b 服务改成 a 服务 go get b 服务对外暴露代码,把业务代码当作三方库来用,在打鸡血的时期是非常爽的,需要某个功能吼一声“团队那个同学”帮我写一个对外暴露的函数,需求是「xxxx」。后来证明 go get 方案埋了天坑,坑的一群人哇哇叫,后来持续 4 年才逐步解决。
经过1年多服务拆分,微服务发展到 120+(下面都是团队拆分后我统计的)我们当时认为比较合理的。后面适应公司发展团队被拆小了,服务被划分到各个团队,我们团队12人有80个+应用,人均7个。
后来我们团队业务边界扩大,其它团队业务逐渐合并过来服务超过 100 个,还有异构技术栈,有部分是 java 应用(20+)后来也做了重构 java 切 go了。
回头看,微服务拆分只像一个笑话「自嘲下」,我们拆分方式也并不是微服务,只是把功能拆分到另一个服务而已,反而留下了一堆坑。
由于前期疯狂拆分服务,微服务配套能力完全缺失的,可以理解为服务在裸奔。另外,一堆 go get 代码,大家都不敢轻易修改,怕改了之后无法向下兼容业务不可用,下面这几个问题困扰了我们很久(后来有一批更优秀的人进来,问题才得到解决,我乘此机会深入学习)
一堆 go get 代码,不敢轻易修改,怕改了之后无法向下兼容导致业务不可用。另外 go get 了一些非常基础能力,例如「组织架构」,后来重构组织架构因为 go get 还做了双写新老库; 维护成本高,人均10个服务,某些迭代甚至几十个服务一起发布,CI/CD 自动化流程直接卡住; 服务拆分后疏于管理,代码混乱不堪稳定性差,有时研发需要花一周时间值班排查问题,不做其它业务开发。 接下来我们重新思考了微服务的坑
服务划分过细,服务关系复杂,单个服务复杂度下降了,整个系统复杂度反而增加了(a调b,b调c,c调d,d调a等)看上去就是一张大网
服务数量多,团队开发效率反而降低,人均10个服务复杂度主要体现
开发功能研发要明确业务边界吧,代码应该写在对应的服务(很多初中级研发根本无法识别,需要对业务非常熟悉的人排版); 需要打开多个工程,本地测时需要启动多个项目(硬件差的同学本地调试不了); 发布要操作多个服务,服务之间可能有依赖关系,a必须等b发布再发布; 通过http/rpc调用,每次调用都有网络IO开销,假设单次平均调用时20ms,经过6次调用就是120ms 链路长,问题定位复杂,服务拆分后调用链路被扩散了一次调用经过多个微服务处理,其中某个服务出问题会导致调用失败,快速定位具体是那个服务故障本身就是一件比较复杂的事;
需要自动化能力才能持续交付,代码开发-->提交-->构建-->部署qa-->部署线上都需要自动化能力才能持续交付;
go get 方案带来了很多隐藏问题,所以 go get 必须废弃,服务间通信使用 http/RPC 。
了解这些坑之后,针对这些坑要有对应的解决方案
基建层面,RPC、服务治理、日志、监控、持续集成/部署、运维自动化、灰度、链路跟踪、服务编排等,这些都是必须配套的; 跟拆分类似,合并不能过于激进,跟随迭代/版本逐步演进,合并不能太粗防止服务臃肿。 基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/yudao-cloud 视频教程:https://doc.iocoder.cn/video/ 早期根据业务功能拆分,微服务粒度拆分太细导致问题,这次合并肯定不能这么干。最终我们按照团队来拆,比如我们团队是三级架构域(营销业务方向),业务方向可以继续向下划分4级架构域(小组概念):获客、运营、内容、活动等,每个小方向2-3个人,每个业务方向申请1-2个微服务,流程复杂场景申请2个(例如:自动化营销方向拆了3个服务),服务拆分粒度出于几点考虑
1个微服务2-3人负责开发和维护,小组内一个主 owner,剩余研发同学负责打配合,他们是可以参与架构设计、需求讨论的,基本能保证每个研发对系统能深入了解,但要有人牵头对整条业务线负责; 2-3人组是相互 backup 的,假设组内有1个同学请假,另外两人顶上不至于出现单点故障,出问题找不到人的情况; 业务不稳定,迭代多的情况建议大家采用上述2个方案,到业务稳定期微服务代码改动不多并不需要这么多研发了,1个研发维护1个甚至多个微服务都是可以的。
讲完服务拆分粒度,下面聊聊微服务拆分逻辑
基于业务逻辑拆分,将系统逻辑梳理清楚,按职责范围划分好,每个单独的逻辑拆分一个独立的服务,以 CMS 平台为栗,有文章、h5、表单、话术库、文件系统、素材包等(10多种素材),我都将其定义成内容,虽然功能多但只拆分了1个独立服务。按逻辑拆分方式也会引入另一个问题,不同研发和架构师对职责范围划分是不同的,也可能导致服务拆分过细或过粗,不用怀疑肯定会出现这类情况; 基于变化性拆分,将系统按照稳定性进行排序,将不迭代、不变动服务拆分为稳定服务,将迭代多、变化快的拆分为变动服务,以自动化营销为栗,规则引擎开发一次未来基本不变动的拆分为稳定服务,事件引擎(编排全平台事件)、面向用户经常变动业务逻辑拆分为变动服务,后来证明这种拆分方式是合理的; 基于可靠性拆分,将系统按照可靠性进行排序,按照 P0、P1、P2 标识,将可靠性要求高的 P0 核心服务和可靠性要求低的 P1、P2 的非核心服务拆分不同的服务,以登陆服务、组织架构服务为栗,这几个服务是核心 P0 服务,需要高可用,系统一旦故障整个业务不可用,P1、P2 非核心服务可不用也只会影响该模块不会导致平台故障; 基于性能拆分,将系统按照性能要求进行排序,将性能要求高的单独拆分独立服务,避免性能高服务占用内存、网络、cpu 等资源导致其他业务异常,我们系统是出现过的,以营销自动划系统为案例,我们拆分了任务系统、流程编排系统,业务高峰期负载高不会相互影响。 聊了服务拆分逻辑应该不会让你抉择困难哈,上述逻辑 2,3,4 都是相通的,比如规则引擎基于可靠性、变化性、性能单独拆分出来都是说的通的,往往拆分服务时都会基于这3点共同抉择,自行灵活应用。
聊完服务拆分,接下来聊服务合并了,服务合并时我司基础组件已经比较成熟了配套完善,基础组件这块不赘述。服务合并需要有大毅力并且懂得规划,从2022年Q1-到2024年Q4,我一直都在做这件事儿,每个季度「服务治理」必定出现在我的季度目标内,并且按周和季度跟进。怎么判断服务应该被合并捉或者下线?聊聊我的治理思路
基于流量统计,统计平台服务流量,从高到低排序,流量低说明业务价值也不高,这部分业务下线或者合并到其它应用; 基于迭代统计,统计平台服务迭代,按照时间排序,2-3年没有迭代的业务价可能价值也不高,需要识别出来下线或者合并; 基于业务数据统计,统计该模块的业务数据,根据数据判断业务价值,逐步下线或者合并; 迭代频繁业务,采用重构策略,全新业务、全新架构替换现有业务和架构,比如:营销自动化替换营销计划、CMS 内容平台替换素材中心等,这类 case 在我们业务方向非常多,有一段时间重构项目立项全平台最多; 切记、切记、切记,一定要提前规划好,制定明确目标每周跟进。服务合并也不能操之过急,持续迭代演进确保服务合并是符合当前架构演进方向的,每个季度有进度最终结果都不会差。
下面是微服务合并史
2022 年Q1,服务69个,甩了一批服务出去并且下线了几个,Q1开始重点关注服务治理工作; 2022年Q3,服务65个,下线4个经过几个季度进展缓慢; 2024 年 Q4,服务 39 个,中间业务边界扩大接手了 20+ 服务,从 100+ 干到了 39 个,另外 10+ 服务还在重构。 短短几点道尽了这几年心酸,到目前为止服务治理并没有结束,未来还需持续努力,加油!!!
采访了一位老员工,经历了架构演进最痛苦阶段。
微服务拆分合理是“银弹”,拆分不合理是“煤焦油”,这么说一点都不过份。