微服务实践的血与泪,从拆分到合并
共 5539字,需浏览 12分钟
·
2024-12-02 18:24
你知道的越多,不知道的就越多,业余的像一棵小草!
你来,我们一起精进!你不来,我和你的竞争对手一起精进!
编辑:业余草
来源:juejin.cn/post/7442153919055364136
推荐:https://t.zsxq.com/le3MZ
背景
微服务这几年越来越火,大家聊的也比较多,我刚开始学时大家也兴奋不已,为适应公司发展把单体项目拆分为微服务,当然后来肯定是一地鸡毛。我经历了公司从电商公司到 SaaS 人再到后面集团内部架构成熟稳定,业务也是经历高速发展,技术上也发生了翻天覆地变化。我把遇到的坑总结出来,抛砖引玉引发大家的思考和交流。
另外,微服务的定义大家可能早就耳熟能详了,不熟悉的可以参考维基百科:https://zh.wikipedia.org/wiki/微服务
。
聊聊我们微服务发展
单体应用也很好
初创期,为了快速验证业务价值,整个团队都在单体应用上开发,业务需求较多但并不复杂,团队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、服务治理、日志、监控、持续集成/部署、运维自动化、灰度、链路跟踪、服务编排等,这些都是必须配套的;
-
跟拆分类似,合并不能过于激进,跟随迭代/版本逐步演进,合并不能太粗防止服务臃肿。
微服务拆分思路
早期根据业务功能拆分,微服务粒度拆分太细导致问题,这次合并肯定不能这么干。最终我们按照团队来拆,比如我们团队是三级架构域(营销业务方向),业务方向可以继续向下划分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 在我们业务方向非常多,有一段时间重构项目立项全平台最多;
-
高优先级需求走技改单独开发-》测试-》上线。
切记、切记、切记,一定要提前规划好,制定明确目标每周跟进。服务合并也不能操之过急,持续迭代演进确保服务合并是符合当前架构演进方向的,每个季度有进度最终结果都不会差。
下面是微服务合并史
-
2021 年团队拆小,团队内服务 89个;
-
2022 年Q1,服务69个,甩了一批服务出去并且下线了几个,Q1开始重点关注服务治理工作;
-
2022年Q3,服务65个,下线4个经过几个季度进展缓慢;
-
2023年Q1,服务54个,下线11个;
-
。。。。
-
2024 年 Q4,服务 39 个,中间业务边界扩大接手了 20+ 服务,从 100+ 干到了 39 个,另外 10+ 服务还在重构。
短短几点道尽了这几年心酸,到目前为止服务治理并没有结束,未来还需持续努力,加油!!!
采访了一位老员工,经历了架构演进最痛苦阶段。
总结
微服务拆分合理是“银弹”,拆分不合理是“煤焦油”,这么说一点都不过份。