资讯详情

资讯详情

系统拆分与组合:微服务架构设计的核心权衡与实践指南

做架构设计这么些年我最深的感受是架构这件事学到最后不是在背模式不是在画复杂的地图而是反复拿捏两件事——拆和合。微服务是拆分层是拆模块化是拆服务编排是合接口聚合是合数据组装是合。市面上那些听着很唬人的词分布式架构、领域驱动设计、事件驱动、五层解耦剥掉外壳之后内核无非都是“怎么拆、怎么合”这个问题的一种答案。这篇文章我想把“系统拆分与组合”这件事讲透。先讲清楚为什么要拆、拆哪些东西、拆到什么粒度才算合适再讲拆完之后怎么把零件重新组合成一个能稳定跑的系统最后用一个我亲手经历过的订单系统改造案例把从单体拆到微服务、又从过度微服务合并回来的完整过程走一遍。内容适合正在做系统设计、准备微服务改造或者被现有代码库复杂度折磨得睡不着觉的后端开发者和架构师。先说句实话架构设计没有标准答案但拆和合的底层逻辑是通用的。看懂这篇文章你可能还是不会一步到位画出完美架构但至少拿到一个复杂系统时你知道从哪里下刀、用什么方法缝合。1. 先说清楚架构到底拆什么合什么1.1 人脑装不下一个2000行的类我见过太多系统一开始只是“简单写写”业务逻辑全堆在一个服务里Controller牵着ServiceService牵着DAO一个下单方法拖出十几个if-else。等代码涨到二十万行的时候加一个字段要改八个地方部署一次提心吊胆半天新人接手两个月都理不清数据流。为什么会这样根本原因是人脑处理复杂度的能力是有限的。心理学里有个著名的米勒定律说人同时能记住的信息块是7正负2个。落到代码上就是一个函数超过几十行、一个类超过几百行、一个模块的依赖关系超过十几个的时候普通人的脑子就开始转不动了。拆分的第一个目的就是降低单点的认知负担。把一个2000行的类拆成5个400行的类每个类各管一摊事每个方法只做一件事人才能看得完、改得动、测得过。这跟写文章一样一篇文章全是密密麻麻的字没人愿意读拆成章节、拆成段落读者才跟得上节奏。当然拆不只是为了看得顺眼。更实际的价值在于独立变更。同一个代码库十几个人并行开发天天冲突合并一次代码跟打仗一样。把系统按边界拆开之后订单团队只管订单支付团队只管支付两边各改各的互不打扰。1.2 拆是手段合才是目的很多架构新手容易走极端一听到“拆分”就热血沸腾觉得拆得越碎越高级。把订单服务拆成订单创建服务、订单查询服务、订单状态机服务、订单历史归档服务一个下单流程要经过四五个RPC调用。拆完之后发现单个服务确实简单了但整个系统的复杂度反而爆炸了。这里要记住一个关键认知拆完不代表架构就完成了把拆开的东西重新组合成一个能协同工作的整体才是架构真正的主战场。就像一台发动机拆成几百个零件每个零件都不复杂但真正考验工程师的是把这些零件按正确的时序、正确的咬合方式装回去还能让它平稳运转。系统拆分解决的是“每个零件简单”的问题系统组合解决的是“整体如何协调”的问题。前者的手段是划分边界、控制依赖后者的手段是接口设计、数据流转、服务编排、事件驱动。两者缺一不可只拆不合系统是一堆孤岛只合不拆系统是一团乱麻。1.3 康威定律组织架构先于系统架构讲拆合原则之前必须提一个容易踩坑的隐形变量——康威定律。这条定律说得很直白系统的结构最终会镜像组织的沟通结构。也就是说如果公司的组织架构是乱的团队和团队之间职责不清、沟通靠拉群、扯皮靠开会那你无论设计多漂亮的服务边界最后写出来的代码一定是藕断丝连的一坨。所以做系统拆分之前先看一眼团队结构。如果支付业务是A组和B组共同维护的今天A组加个需求明天B组改个接口那支付这个域就不具备独立拆分的条件。反过来如果你想把某个模块拆出来最好先让一个团队完整负责这个模块的迭代和运维。架构的边界必须和组织权责的边界对齐否则拆出来的服务只会成为沟通成本更高的扯皮现场。我见过不少团队倒过来操作先把服务拆了然后才去调组织架构中间足足痛苦了半年每一次需求评审都要四五个团队的人在一起对口径。所以这里给一句实操忠告拆系统之前先确认人和事能不能一起拆。2. 拆分的五个真实维度2.1 纵向拆分分层不是越多越好纵向拆分就是大家最熟悉的分层架构。传统三层架构是表现层、业务层、数据层后来进化出领域层、基础设施层、应用层再后来还有人搞五层解耦架构。核心思想是把不同职责的代码放到不同的层级用接口隔开禁止跨层调用。分层的价值在于让依赖方向变得可控。表现层依赖业务层业务层依赖数据层箭头始终向下谁也绕不过谁。改数据库不影响上层接口换UI也不动业务逻辑这就是解耦。但分层有一个常见误区层不是越多越好。有人把系统分成接口层、应用层、领域层、防腐层、基础设施层、缓存层、存储层结果一个简单请求要穿透七个层每个层只是贴标签式地转发参数。这种分层看起来专业实际上全是空转。我自己的实践是分层的数量以“清晰”为准不以“够多”为准。对于一个业务系统表现层、应用层、领域层、基础设施层四层基本够用。每层必须有真实逻辑在发生如果一个层只做参数透传那就是多余的可疑层。分层这事的核心不是“层层有编号”而是每一层都只依赖它下面那一层任何一层出问题时不影响其他层的替换。2.2 横向拆分按业务边界切服务纵向分层解决的是层级之间的解耦横向拆分解决的是模块之间的隔离。横向拆分最常见的落地方式就是按业务域切服务这也是微服务架构的基本逻辑。做横向拆分时最怕的是凭感觉切。有人按功能切一个上传功能一个服务有人按页面切一个订单页面一个服务还有人按数据表切一张表一个服务。这些都是短视的做法切完之后你会发现服务之间互相调用、数据互相拉扯拆了个寂寞。真正靠谱的切分依据是“业务领域”和“业务能力”。以电商订单流程为例一个订单的生命周期包括创建订单、支付、库存预占、发货通知、售后处理。这里面涉及的能力域至少有订单域、支付域、库存域、物流域、会员域。每个域都是一个高内聚的领域集合域内的实体和行为是紧密关联的域与域之间则通过明确的事件或接口交互。判断两个功能该不该分到同一个域里有一个很实用的标准看它们是不是经常因为同一个需求一起变更。如果一个业务改动会同时牵动订单表、库存表、支付流水表那说明它们本质上是一个高内聚的域强行拆开只会让跨服务事务成倍增加。反过来如果两个模块各自演进、很少同时修改那就具备拆分的条件。2.3 技术维度拆分共性能力下沉除了按业务拆系统中还存在另一类适合拆出来的东西——公共技术能力。比如用户认证、权限校验、消息发送、文件存储、配置管理、日志采集这些能力不归任何具体业务管但每个业务都离不开。这类能力应该下沉成独立的基础服务或公共组件而不是在每个业务服务里各写一套。否则就会出现十个服务有十套登录逻辑、五套文件上传组件的灾难现场。下沉的好处是统一治理、统一升级、统一安全管控业务方只需要通过SDK或者HTTP接口接入即可。不过下沉也要把握分寸。基础设施服务一旦独立它就变成了一个被所有业务依赖的关键节点它的每一次变更都会影响下游所有服务。所以在技术维度拆分的实操中我建议两条原则第一共性能力必须稳定接口设计要尽量向后兼容不要天天改签名第二下沉的手段要灵活不是所有公共逻辑都必须单独部署成一个服务很多场景下打成公共SDK包比独立部署更务实。2.4 判断边界是否拆对的三个硬标准拆分对不对别听人吹概念用这三个标准自己检验依赖方向是否一致。检查服务间的依赖图正常的依赖应该是单向的、分层的。比如订单服务依赖库存服务库存服务不能反向依赖订单服务。如果出现A依赖B、B依赖C、C又依赖A的循环说明边界切错了。变更影响是否可控。改一个内部实现时最多影响多少个外部方如果改一个订单服务内部逻辑要通知六个团队联调说明边界切得太粗或太细都不对。理想的边界是内部怎么改都不影响外部只有接口变更才需要协作。是否具备独立部署条件。服务能不能单独测试、单独发布、单独扩缩容如果每次发布都必须和另一个服务绑在一起发布说明它们之间根本不是服务划分只是代码目录划分。这三个标准不只看设计文档要拿真实的发布记录和线上依赖拓扑去验证。很多团队设计图上画得清爽实际代码里服务间调用了十几个接口全靠运维手工协调发布顺序这种“假拆分”比不拆还累。2.5 什么时候不该拆拆分是有成本的。服务拆分意味着网络调用、数据分片、分布式事务、运维监控、联调排错每一项都比单体内复杂得多。所以必须承认一个现实有些系统现在就不该拆。什么情况下不该拆第一团队只有三五个人业务还在快速试错期这个阶段的首要任务是验证业务逻辑拆服务只会拖慢迭代速度。第二业务复杂度不高单体代码也就几万行一个应用能轻松扛住所有流量没必要为了“微服务”的虚名制造分布式复杂度。第三你的服务和团队之间职责完全纠缠不清强行拆就需要重构组织架构成本比收益高。我的建议是先用模块化和清晰的分层把单体内部理干净必要时再用代码目录模拟边界等业务复杂度和团队规模都上来了再考虑把模块物理拆成独立服务。演进的节奏永远是先松耦合、再物理隔离直接一步到位往往是以灾难收场。3. 组合的六种方式拆完的模块、服务、类需要靠组合机制重新组装成完整的系统。组合方式的优劣直接决定了系统最终是“和而不同”还是“面和心不和”。3.1 进程内组合依赖注入与接口聚合最基础、使用频率最高的组合发生在进程内部。Java的Spring、Go的Wiring、C的构造注入本质上都是同一个思路定义接口把具体实现从外部注入进来。依赖注入的好处是让模块之间的组合变得可插拔。订单服务需要支付能力不需要自己去new一个支付实现而是通过构造函数声明“我需要一个PaymentProcessor”由容器决定传入微信支付还是支付宝支付。以后想换实现、想加缓存代理、想做测试替身都不需要改业务代码换一条装配线就可以了。这个层面的组合有一个容易忽略的要点不要用服务定位器反模式。有人嫌构造函数注入参数太多干脆在一个全局静态类里塞一堆Service业务代码里随手一调。表面上是解耦了实际上所有模块都反向依赖这个全局容器依赖关系全被隐藏了代码的正确性只能靠运行时才知道。构造注入参数多通常说明接口设计过碎可以尝试把多个接口聚合成一个门面接口而不是放弃显式依赖。3.2 进程间组合网关编排与流程编排服务拆到不同进程之后进程内注入这套打法就不够了必须引入进程间组合。最常用的两种手段是API网关聚合和独立流程编排服务。API网关聚合也叫BFF模式核心思路是让网关层直接编排底层服务的调用把多个内部服务的数据聚合后返回给前端。比如移动端首页需要同时展示用户信息、订单状态、优惠券数量、推荐商品如果是纯微服务模式端上要连续发四个请求用BFF之后客户端只调一次网关网关并行调四个服务组合好再返回。比BFF更重一点的组合形态是流程编排。适合那种涉及多服务、有明确先后顺序、需要保证事务语义的业务流。比如“创建订单后扣库存再发消息通知仓储”这种情况下可以引入一个流程编排引擎或者用代码写一个编排服务显式控制每一步的调用顺序和失败补偿逻辑。这里有一个让很多人纠结的问题编排Orchestration还是编排歌舞Choreography我的答案是带严格状态的业务用编排追求链路松耦合的事件流用广播。比如下单流程这种有强状态、有先后依赖的必须用编排一个环节出问题马上知道往哪补偿而像“用户注册之后发欢迎邮件、初始化推荐偏好、记录埋点”这种没有强顺序、失败也不影响主流程的场景用消息广播就够了。两者是配合关系不是二选一的互斥关系。3.3 数据层面的组合查询模型与CQRS很多人拆服务的时候只拆了代码数据库还共用一个最后落得个服务边界清晰、数据边界混战的局面。但反过来如果无脑按服务拆库又会遇到一个头疼的问题原来单库里一条JOIN就能查出来的聚合数据跨库之后怎么查数据层面的组合方式我认为有三个层次。最底层的是服务间互调接口拿数据在内存里组装这是最正统的方式适用数据量小、实时性要求高的场景。再进一层是数据冗余读服务需要订单的一些信息就在自己的库里存一份只读副本通过事件去更新这样查询不跨服务性能和可用性都更好。再激进一些的是CQRS模式把读模型和写模型彻底分离专门建一个查询库或者查询服务通过事件同步数据专门应对复杂的查询聚合场景。具体选哪一层要看你对数据实时性的容忍度。我见过太多团队一上来就搞CQRS事件溯源结果连基本的数据一致性都处理不了。实操建议是优先用内存组装真扛不住了再上数据冗余读模型单独建库要等事件机制成熟了再说。架构的复杂度和业务需要的实时性严格匹配不要额外加戏。3.4 事件驱动的组合消息队列与最终一致跨服务组合中最强的解耦手段是消息队列。A服务不用管B服务存不存在、活不活着只需要往消息管道里发一个事件B服务按自己的节奏消费。事件驱动让服务从“你求我办事”变成“我通知你发生了某件事”这是质的区别。以订单支付成功为例。支付服务不需要主动去调用积分服务、短信服务、推荐服务、财务报表服务只需要发布一个OrderPaidEvent。谁关心这个事件谁就订阅它。后面接入第100个订阅方支付服务一行代码都不用改。事件驱动还有一个传统同步调用无法比拟的优势削峰填谷。双十一大促的瞬时流量如果全靠同步调用压给下游下游服务直接被冲垮用消息中间件缓冲一笔一笔慢慢消费下游稳如泰山。但事件驱动最大的难点在于一致性。本地数据库操作和消息发送这两件事天然原子性很难保证。我的处理办法是本地消息表步骤很简单先在同一事务里写业务数据和消息记录再通过后台任务把未发送的消息投递到MQ消费方处理完成后回调确认。这样整个可靠性建立在数据库事务上实践中非常稳。3.5 组合逻辑优于时序逻辑一个硬核类比这个点我用一个数字电路的概念来类比说明学过Verilog或者数字逻辑的读者会秒懂。在硬件设计里二进制转格雷码这种纯转换逻辑一定用组合逻辑不用时序逻辑。为什么因为组合逻辑的输出只取决于当前输入没有历史状态因此可预测、易验证、天然没有时序竞争而时序逻辑引入了触发器、时钟、状态任何一个状态没更新到位就会出bug。系统架构里的“组合”和“状态”的关系遵循同样的逻辑。能用无状态组合完成的事就不要引入带状态的耦合流程。比如服务编排中每一步调用是纯函数式组合只要输入一致输出必然一致排查问题非常容易但如果每一步都要依赖服务自己的内部状态比如“当前订单到没到某个节点”“这个用户的流程走到哪了”那就引入了分布式的时序状态任何一个状态不一致都会导致线上事故。我见过一个活生生的例子有团队把一个审核流程的状态散落四个服务里各存一份然后靠定时任务去同步状态三天两头出现“用户显示已通过但审核记录还是待审”的错乱。后来改成编排服务统一保存流程状态、下游服务全部做无状态处理问题才消失。组合的本质是让系统尽量往“纯函数”的方向靠拢把容易出问题的状态集中管理。3.6 UML组合与聚合生命周期决定依赖学过UML的应该记得类关系里有一种是组合一种是聚合。组合用实心菱形表示聚合用空心菱形表示。两者区别很直接组合关系中部分和整体的生命周期是一致的整体没了部分也没了比如“订单”这个整体摧毁了订单明细作为部分也应该被清理聚合关系中部分可以脱离整体单独存在比如“用户”加入“会员群组”群组解散了用户仍然存在。这个建模概念放在系统架构里直接影响你怎么做模块归属和服务边界。两个对象如果生命周期一致比如订单和订单项、钱包和支付流水它们天生应该放在同一个服务里用组合关系管理不需要跨服务调用。两个对象如果生命周期互相独立比如用户和订单、商品和促销活动它们才有充分理由拆到不同的服务用聚合的方式通过接口协作。很多服务边界切完之后出现严重的跨服务联查和互相锁定一个重要根源就是把本该组合的东西拆开了或者把本该聚合的东西焊死了。遇到这类问题回头画一张UML关系图用组合/聚合来重新审视边界往往比在代码里纠结更有效。4. 实操实录一个订单系统拆了再合的过程前面讲了不少原则和方式可能还有点抽象。下面用一个我实际经历过的订单系统改造案例把“拆了再合”的完整过程还原出来。这个案例不飘、不吹全是在生产环境真的踩过的路。4.1 背景单体订单服务为什么撑不住接手这个系统时它是一个典型的单体应用所有订单相关逻辑都在一个服务里代码量大概二十万行。下单、支付回调、售后、退款、订单查询、库存扣减、发票管理全部在同一个代码仓库共用同一个MySQL数据库。当时最痛的问题有三个。第一个是发布风险高一个地方改错就影响全量发布每周四晚上的发版日所有人都紧张兮兮第二个是代码冲突严重团队成员按模块分工但落到Git里全在改同一个Service类一个需求能冲突三回第三个是数据库压力集中订单表、订单明细表、支付流水表、库存表都在同一个实例上一到高峰期锁等待特别多。其实这个体量的系统还没到必须上微服务的程度。但团队从业务上确实有独立扩展支付能力、独立部署库存接口的诉求。所以我们决定走“渐进式拆分”的路线不追求一步到位先拆能产生明确收益的边界。4.2 第一轮拆分按业务域和数据库边界切第一轮拆分的范围被严格限定在三个域支付域、库存域、订单域。为什么先拆这两个因为支付要对接的外部渠道多而且支付相关的代码频繁需要升级和调整把它独立出去可以隔离高频变动库存服务则是因为库存预占接口被仓储端和销售端两边都在调独立出去能统一出口。拆分的第一步是定接口契约。我们把订单服务对支付服务的调用方式从前面的方法内部直接调用改成RPC接口调用接口的参数和返回值统一封装成DTO。同样的订单服务对库存服务的操作也收敛成一个减库存接口。第二步是拆数据库。支付相关的表迁移到独立的支付库库存相关的表迁移到独立的库存库。这一步工程量大但必须做否则服务拆了数据还挤在一起等于没拆。第三步是做链路梳理。下单的主流程被梳理成创建订单订单库状态为待支付预占库存库存库锁定库存数量发起支付对接支付渠道支付异步回调后更新订单状态、扣减库存、发送消息中间的库存预占和支付回调我们没有做成同步强事务而是通过消息队列解耦。下单时先预占库存支付成功回调后异步扣减库存如果支付取消则释放预占库存。这样避免了单笔交易跨三个库的分布式事务。4.3 拆分后的代价分布式事务与调用链变长服务拆出去之后单体时代被掩盖的复杂度立刻浮了出来。最大的就是一致性问题。原来同一个库事务一开订单状态和库存扣减要么都成功、要么都回滚拆库之后一个事务管不到三个库了。我们当时的处理方案是Saga模式的简化版先创建订单、再预占库存、再发起支付。如果支付超时失败就反向调用库存服务释放预占库存同时把订单状态更新为取消。为了确保补偿操作不丢每次状态变更都记录到一张状态机日志表后台有定时任务扫描碰到状态卡住的单子自动补偿。第二个代价是调用链变长。一次下单在单体里就是本地方法调用几十毫秒搞定拆开后变成了下单RPC、库存RPC、支付RPC动不动上百毫秒。对内部系统还好但对C端用户体验有影响。我们做了两个优化一是网关处做并行调用把不需要依赖顺序的调用同时发起时间从串行累加变成瓶颈最大值二是对非核心链路上的通知类操作比如发送短信、推送消息全部改成异步事件不占主流程时间。第三个代价是数据查询难。原来后台运营要查一笔订单连带支付流水和库存明细一个SQL就出来了拆库后要调三个服务接口再拼装。我们当时的方案是做了一个运营查询服务专门从只读从库拉数据聚合后输出给运营后台。这就用到了前文说的数据冗余思路。4.4 第二轮调整把拆坏的服务合并回去拆分持续半年后我们回过头来审视服务边界发现有些拆是“为了拆而拆”。最典型的是订单明细服务。当时觉得订单主表和明细表数据结构不同查询逻辑差异大就单独拆了一个服务出来。结果运行大半年才发现订单明细服务的下游调用方只有订单服务自己其他业务根本不会直接访问订单明细。为了处理这个几乎没有业务含义的边界每次下单都要先调订单主服务、再调明细服务纯粹多一次RPC开销。更要命的是订单主服务和明细服务之间钉死了事务边界每次写操作都要考虑两个服务的数据一致性。几番权衡之后我们决定把订单明细服务合并回订单主服务将两个服务重新变回一个进程内的模块。这次合并之后相关接口的RT直接降了三分之一代码数量少了四千多行。第二处合并是把售后服务和订单服务重新合并了一段。售后业务和订单状态紧密耦合售后单的创建前提是订单处于某个状态跨服务就只能反复查询订单状态产生大量RPC。后来我们把售后的核心流程挪回订单服务内部只保留售后相关的查询逻辑在外部。这个调整不是全部回退是我们意识到拆分不该只按业务名词切要看功能的真实使用链路。4.5 拆合之后的最终形态那次调整结束后系统的服务数量从最多的12个收敛到7个但这个7个服务的形态比原来12个的时候运行稳定得多。发布的独立频率从每周一次提升到每天能滚动发布三轮晚间高峰期的链路超时率从0.5%降到了0.05%跨服务的数据库强事务基本消灭只保留Saga补偿这种软事务。这个案例给我的启发是架构演进不是一条直线拆错了回头合并不可耻。衡量好坏的标准只有一个上线后的系统是不是更稳、更快、更好改了。如果拆完反而变慢变乱那就应该有勇气合回去。5. 拆合过程中的常见坑与排查清单5.1 服务依赖循环的排查拆出来的服务之间最常出现的恶性问题就是循环依赖。A服务调用B服务一个接口B服务处理过程中又回头调了A服务的接口。这种循环在单体代码里编译器还能帮你检查变成跨服务RPC后只能靠运行时发现轻则线程池占满重则直接雪崩。排查循环依赖我的做法是先画服务依赖图。依赖图工具可以从调用链监控系统里自动生成比如SkyWalking的拓扑图、Zipkin的依赖分析。拿到图后盯箭头把所有服务的调用关系画出来如果发现一个闭环那就必须断掉。断掉的手段不外乎三种把被依赖的公共逻辑下沉到另一个服务里两个服务共同依赖它或者把其中一个方向的调用改成消息异步断了同步的环再或者直接在代码层面合并这两个服务反正它们已经物理上耦合了。5.2 数据一致性问题的处理拆分之后最多的问题发生在数据一致性上。典型的案例就是订单服务在库里写了订单状态为“已支付”但库存服务扣减库存失败最后用户钱扣了货没发。这类问题没有银弹最常见的解决方案有两个。一个是Saga事务把一个长事务分解成多个本地事务每一步记录状态任一步失败就做前向补偿。另一个是本地消息表MQ本地事务里写业务数据和消息投递到MQ后让下游消费下游消费成功再回调确认消费失败就重试重试到一定次数进死信队列人工兜底。排查一致性问题时一定要先确认幂等有没有做好。消费者处理同一事件可能两次数据库里的更新必须能重复执行而不产生副作用。常见的做法是消费记录表或者唯一业务键约束。我踩过的大坑之一就是只做重试不做幂等最后同一张订单被重复发券运营主管直接找上门来。5.3 服务粒度失控的迹象判断服务拆得粒度是否失控可以看几个信号。第一服务数量远超团队人数。一个十几人的团队维护三十多个服务每人平均维护三个服务联调成本极高这一定是拆过头了。第二服务间调用量占比过高。当一次用户请求后端平均要跨服务调五六个接口才能返回服务的独立性已经失去意义。第三部署依赖关系复杂每次发布都要按特定顺序执行。如果出现这些信号别犹豫及时做合并。合并服务不需要把所有代码都删掉把几个服务的代码放到同一个仓库、同一个部署单元内部模块之间用函数调用替代跨服务RPC通常就能解决大部分问题。服务合并并不丢人我看到的大厂架构文档里也有大量“服务合并”的专项。5.4 链路追踪与日志的配套服务拆分后一次请求会横跨多个进程。如果日志系统还是单体的那种往文件里瞎打出问题时就等着崩溃吧。排查跨服务问题最重要的配套工具是链路追踪。我们当时接入的是全链路Trace方案核心就两件事在入口网关生成一个全局唯一的TraceId并把TraceId传递到每一次子调用、消息事件的Header里日志框架把所有本地日志都带了这个TraceId。这样出了问题用TraceId一搜整条调用链的日志全出来了哪个环节慢、哪个环节报错一目了然。这个配套必须跟拆分同步做不能等拆完了再补。我接手过一个拆到一半的项目服务拆了十多个链路追踪全没有线索出了问题只能让各个团队的运维同时打开各自的日志慢慢翻一个跨服务问题能排查三个小时。后来补上Trace体系同样的排障场景十分钟内就能定位。5.5 拆合过程中的一个实用检查法最后分享一个我自己反复用的检查方法。在每个迭代周期结束时把系统的服务依赖关系和团队发布的记录拉出来对一遍看哪些服务的调用方向发生了反转哪些服务的发布频率异常偏高哪些服务的调用量极少但有复杂的业务逻辑。调用方向反转说明边界已经快崩了发布频率偏高的服务往往承担了过多职责可能又需要再拆调用极少但逻辑复杂的服务则适合合并到主链路里降低维护成本。架构没有一劳永逸这些调整本身就是架构师日常要做的事。这件事没有什么高深理论也不需要等大版本的重构窗口平时开发中顺手修整比憋大招式的“架构升级”靠谱得多。我做架构这几年最大的体会就是好架构不是一次设计出来的是像照顾植物一样经常修剪、定期调整慢慢长出来的。最后再啰嗦一句判断一个系统是不是健康别看设计文档上花了多少漂亮的图去数发布频率和平均排查问题的时长这两个数字反应的都是真实的拆合质量。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →