ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

一人微服务架构复盘:从单体拆分为6个服务的实践经验

一人微服务架构复盘:从单体拆分为6个服务的实践经验 1. 从一人运维6个微服务说起很多人听到微服务架构脑子里想到的第一个画面就是几十人团队、多套环境、一堆技术委员会在那边开会扯皮。但实际上我花了一年多时间一个人把一个项目从单体拆成了 6 个独立部署的服务并且至今仍在线上稳定跑着。这个标题里写着一人6服务架构复盘就是想把我那套踩过坑、填过洞、最后稳定运行下来的架构方案原原本本拆给大家看。先交代下这个项目背景。整个项目是一个面向门店的预约与会员管理系统包含了小程序端、商户后台、总管理后台三个终端。业务量不大一台 4 核 8G 的服务器就能扛住绝大多数场景。按正常思路这种量级放到一个 Spring Boot 单体里绰绰有余我最初也确实是这么干的。但后面随着功能迭代开始出现几个很典型的痛点小程序端偶发慢查询会把商户后台的报表接口拖垮门店管理端发布新功能时小程序端的支付回调逻辑也可能因为部署节奏不一致而出问题还有一个更隐蔽的问题就是不同业务模块的生命周期完全不一样比如营销活动代码可能每周都要动而支付和会员体系的代码一两个月没碰一次。这就逼我不得不重新考虑架构方案。这篇复盘适合谁看如果你是独立开发者、小团队技术负责人或者公司在做的项目规模不大但已经出现了改一处、崩全家的苗头那这篇文章应该能给你省下不少折腾时间。我会从选型思路、服务拆分、基础设施、部署监控到踩坑实录完整地把一个人维护多个服务这件事讲透。2. 单体到微服务的临界点为什么一个人也需要拆分2.1 单体架构的舒适区是怎么被打破的先说说单体架构时期具体遇到了什么问题。最早我把所有业务都放在一个项目里用户模块、会员模块、门店模块、预约模块、营销模块、支付模块、报表模块全部堆在一个 Spring Boot 应用中。前期确实舒服本地起一个服务就能调试所有功能部署也简单——打一个 jar 包丢服务器完事。但到了第 8 个月左右项目进入密集迭代期问题就开始冒头了。最典型的一次线上事故是某个营销活动模块因为优惠券计算逻辑写了个死循环CPU 瞬间打满结果整个服务直接无响应小程序端、商户端、支付回调全部一起挂掉。那次业务停摆将近 30 分钟损失的不只是几个小时营收还有门店方对系统的信任。另外还有资源竞争的问题。报表模块有个比较耗时的聚合查询单次可能跑 2-3 秒平时没问题但每天凌晨定时任务跑全量统计时数据库连接池会被占满。这时候如果碰巧有用户做支付支付回调的数据库请求就得排队支付确认就会延迟非常影响体验。关键点在于单体的稳定性问题本质上不是代码质量问题而是隔离性问题。所有模块共享一个进程、共享线程池、共享数据库连接池任何一个模块的异常行为都可能波及全局。一个人维护项目没精力保证每一段代码都绝对健壮所以更需要架构层面提供兜底。2.2 拆分的三个触发信号以我的经验个人项目判断是否需要从单体转向多服务不需要看很多理论只需要问自己三个问题第一是否存在某个模块的故障会把其他模块拖垮比如上面说的内存溢出、CPU 打满、慢 SQL 耗尽数据库连接池。如果你对这个问题的答案是有那你就需要一个故障隔离的边界。第二是否存在不同模块的发布频率差异特别大注意这里的差异不是同一天多改几个接口的问题而是某些模块一周要发布三五次某些模块一个月都动不了一次。高频发布本身就会带来不稳定因素每次发布你都得重新验证全量功能。第三是否有多端共享服务的需求比如小程序端、商户后台、内部运营后台虽然当时是一个单体但三端的流量特点、权限模型、数据敏感度完全不一样。小程序端面向 C 端用户接口频率高、单次请求轻商户后台是低频、但单次请求重、需要大量列表查询。混在一起你就很难针对性地做参数调优。这三个问题我当时的回答都是是所以拆分这个决策就变得顺理成章了。3. 六个服务的划分逻辑边界比数量更重要3.1 为什么是 6 个而不是 2 个或 10 个很多人在服务拆分上很容易走极端。要么图省事用服务名把单体拆成两个就完事要么追求微服务感觉按数据库表级别拆出十几个服务结果服务之间的调用链比自己头发还乱。我之所以最后稳定在 6 个服务是因为每个服务的拆分都能对应到一个明确的业务语义和独立的故障边界。拆出来的 6 个服务分别是gateway 网关服务负责统一鉴权、路由转发、限流。它是所有流量的入口单独拆出来有一个天然的好处限流规则可以独立于业务服务更新和发布不需要动任何业务代码。user 用户与会员服务包含用户注册登录、会员等级、积分资产、成长值等。这个模块和钱、权益相关稳定压倒一切尽量减少变更。shop 门店与商品服务门店信息、营业时间、服务项目、商品 SKU、价格库存。这是一个相对独立的中台数据域被小程序端、商户后台、总后台共用。booking 预约服务核心交易链路之一包含排班、锁号、预约单生成、改约、取消。预约会涉及状态机流转逻辑复杂单独隔离可以防止其他模块变更影响它。payment 支付与结算服务接入支付渠道、处理回调、发起退款、生成对账单。这个服务应该是 6 个里面隔离等级最高的任何变更都要单独发布、单独验证。marketing 营销与运营服务优惠券、活动配置、满减规则、推送任务、报表聚合。它是迭代最频繁的模块也是最容易出 bug 的模块单独拆出来相当于把不安定分子关进独立房间。你看这 6 个服务的划分没有一个是因为技术兴趣全部是围绕变更频率、故障影响面、数据敏感性这三个维度来定的。3.2 数据库是分还是合一个务实的妥协方案关于数据库的拆分我最后采用的其实是中度共享策略并不是严格的每服务独享库。为什么因为一个人维护 6 个库是可以接受的但维护 6 套不同步的数据同步管道是不可接受的。具体方案是这样的每个服务有自己独立的主库实例在物理层面保证无跨库依赖但是在数据访问层上只允许读取其他服务的必要基础数据表。比如预约服务需要知道门店的营业时间预订服务需要读取用户的基础信息那我就直接配置一个只读用户允许预约服务的代码去访问用户库的 user_profile 表。这样做的核心意图是在写入路径上彻底隔离在读取路径上保持一定灵活性。起初我也试图设计一套严格的服务间禁止跨库查询规范让所有数据交互都必须走 API。但实施到第二周我就发现这套模式在大团队里跑得转是因为有足够的人力去维护几十个数据接口和配套的文档、监控。一个人搞这个最直接的后果就是为了查一个简单的状态字段不得不写一次远程调用、处理超时、加缓存一门心思扑在流程正确上反而忽略了业务的复杂度和交付节奏。这个折中方案的代价是如果一个服务要共享另一个服务的数据表结构变更时必须提前通知。所以我定了一个规矩——共享表只允许加字段不允许改字段类型、不允许删除字段。现在的数据库维护成本其实比全拆分的方案低很多大部分接口只需要本地 SQL 就能完成没有任何网络开销。3.3 服务间同步调用路径怎么控制拆了服务以后跨服务的同步调用是绕不开的。而同步调用路径越长系统的延迟和故障率就会越高这是由木桶效应决定的。整个链路中任何一个调用方出现网络抖动或代码 bug都会让你的接口最慢多少毫秒、最差挂掉多少次这两个指标的核心指标之一。我在设计上刻意控制了跨服务调用的最大深度要求任何一次用户请求的调用链最多经过三次服务跳转。比如小程序端请求创建预约这个动作实际的路径是gateway - booking - user就直接返回。绝不出现 gateway - booking - user - marketing - shop 这种五跳的链路。三次跳转以上的业务逻辑宁可后端做一点数据冗余或异步化处理。同时所有跨服务调用我都遵循一个规矩必须有降级方案核心是本地降级到缓存然后缓存降级到默认值。比如预约服务需要拿用户当前等级来判断预约折扣如果 user 服务超时预约服务不会直接报错而是从本地 Redis 缓存读取用户等级如果 Redis 也超时了就用默认等级来创建预约单把等级校验放到事后异步重对。这样一来即使依赖方挂了核心交易链路也不会中断。4. 一人运维 6 服务的基础设施自动化是一切的前提4.1 为什么上 Docker ComposeK8s 对一个人来说太重了服务拆到 6 个以后第一个让我崩溃的问题是部署。最开始我用传统的 jar 包方式部署打包、传服务器、停旧进程、起新进程。6 个服务每个服务都要执行一遍这套流程一次全量发布至少要折腾 40 分钟而且很容易出低级错误——比如上传漏了文件、忘记改某个环境变量、进程没起来就离开了终端。当时我也认真考虑过要不要上 K8s但评估完之后果断放弃了。K8s 带来的价值——自动伸缩、弹性调度、跨可用区容灾——恰恰是一个人的小项目最不需要的。一台服务器上跑 6 个服务资源伸缩的需求为零节点管理的工作量却是实打实的。为了用 K8s 而用 K8s等于用一个复杂的调度系统去解决一个本来不存在的资源调度问题自学和运维的隐性成本极高。我最后选择的是Docker Compose在单台服务器上以容器方式运行全部 6 个服务。每个服务打成独立镜像Compose 文件统一编排一条命令完成构建、启动、停止、扩容缩容。这个方案对个人开发者极其友好学习成本低、排障简单docker logs 直接看日志、服务器只需要装一个 Docker Engine。4.2 CI/CD 流水线从提交代码到上线只需要 5 分钟部署这件事自动化不到一定的程度一个人根本扛不住 6 个服务的更新节奏。我搭建了一套精简版 CI/CD核心工具就是 Gitea Drone。Gitea 作为 Git 仓库自己托管Drone 负责构建流程。之所以不用 GitHub Actions纯粹是因为代码仓库我放在了内网服务器上有自己的私有仓库需求Gitea 更轻量内存占用只有几百 MB。整个 CI/CD 流程是这样的开发分支合并到 master触发 Drone 流水线。流水线第一步做单元测试和编译打包。第二步构建 Docker 镜像并打上版本号标签示例registry.example.com/booking:20250112-1800。这个版本号用了时间戳加短提交号方便追踪线上镜像到底是哪个代码提交构建出来的。第三步把镜像推送到私有镜像仓库。第四步通过 SSH 登录到生产服务器执行docker compose up -d bookingDocker Compose 检测到镜像 tag 变化后自动完成拉取和重建。这里有一个细节值得展开。Drone 构建机上我不装任何编译环境全部构建动作都在容器里完成。比如前端项目就使用node:20-alpine镜像后端项目就使用maven:3.9-eclipse-temurin-17镜像通过 volumes 挂载代码目录的方式执行构建命令。构建环境的容器化让我本地电脑和 CI 服务器的环境完全解耦再也不会出现本地能编译、线上编译失败的经典场景了。4.3 监控与告警一个人怎么盯住 6 个服务一个人维护 6 个服务最怕的不是服务挂了而是服务挂了但人不知道。所以我必须把发现故障→收到告警→定位问题这个事件尽量自动化。如果等到用户来反馈说明服务已经挂了一段时间了影响已经扩散开了。我用的监控方案是 Prometheus Alertmanager配合 Grafana 展示面板。每个服务在启动时都会暴露/metrics接口Prometheus 每 15 秒拉取一次指标。我重点关注三类指标请求 QPS、P99 延迟、错误率。指标本身只是一个点真正的关键在告警规则的制定上。我的告警规则有两条是踩坑以后才加上去的错误率连续 2 分钟大于 1% 就触发告警级别为 warning错误率连续 5 分钟大于 5% 就触发 critical会调用 webhook 推送到我的企业微信。第一条规则看似很普通但它是整个监控体系的基石。很多人容易犯的错误是规则设得过于宽松比如错误率 10% 才报警等触发的时候用户已经感受明显了。1% 的错误率目测可能只影响几十个用户但连续 2 分钟保持 1% 以上的错误往往意味着某个接口出现了系统性异常早发现早处理才是唯一正确策略。日志方面6 个服务的容器日志全部通过json-file驱动输出为 JSON 格式同时用 Filebeat 将它发送到 Elasticsearch用 Kibana 做查询。这套组合搭建成本高一些但对于多服务的日志查询价值很大——按 traceId 搜索一次跨服务请求的全链路日志能省下大量排查时间。4.4 多环境策略一套环境还是两套环境大团队常见的环境划分是 dev、test、staging、prod 四套起步但这套玩法放在个人项目上纯粹是自我折磨。最终我只保留了生产环境 一个测试环境的双环境策略。测试环境实际部署了全部 6 个服务的副本但资源占用是受限的每个服务只分配了最小内存。这样做的好处是新功能开发时可以直接在测试环境联调验证不用担心污染线上数据。联调通过后再走 CI/CD 发布到生产。两台服务器都在同一云厂商处在同一个 VPC 内网数据传输走内网地址省掉了大量公网流量的开销和延迟。关于测试环境的治理我加了一条硬性约束测试环境的数据不允许手工修改。不试一把你都不知道环境会被污染成什么样子。更靠谱的做法是代码里写死一套测试数据配置文件每次启动时自动用初始化 SQL 重置数据库保证测试环境的数据始终处于固定状态避免上次手工改了某个字段这次联调找半天问题的低级局面发生。5. 服务拆分后那些躲不掉的问题与排查实录5.1 分布式事务不用 Seata我用这些土办法服务拆分以后最直接的技术难题就是分布式事务。举个真实例子用户在小程序端发起预约并支付操作时涉及预约服务创建预约单、支付服务发起支付、会员服务扣减积分三个操作。在单体时代这可以用一个本地事务简单搞定拆分成三个服务以后就变成跨越三个数据库的写入不可能再依赖数据库的本地事务了。我在复盘时认真考虑过引入 Seata 这类分布式事务框架但最终的结论是不上。分布式事务框架本身的复杂度非常高需要额外的协调器、注册中心和代理同时它们对性能和场景的适用范围也有一些前提要求真正落到一个人维护的项目里性价比待定。我最后采用了一种本地消息表 定时对账的最终一致性方案来处理核心场景。具体做法是这样的。每个服务的数据库里都加了一张outbox_event消息表。当业务主流程执行时在同一个本地事务里写入业务数据和事件记录。比如预约服务创建预约单时同时往 outbox 表插入一条预约单已创建的事件。本地事务保证这两条记录的原子性不会出现业务数据成功、事件记录丢失的问题。然后每个服务启动一个轻量级定时任务每隔 30 秒扫描 outbox 表把未发送的事件发送到消息队列。下游服务消费消息后执行自己的业务动作。如果消息发送成功本地就把状态标记为已发送如果下游处理失败消息就会进入重试队列最多重试 3 次仍然失败就通过告警通知我人工处理。这套方案的核心思路是用一张本地数据库表来模拟事务消息把分布式事务问题降级为单机事务 异步消息 定时兜底。虽然时间复杂度上做不到强一致但对于预约类业务来说短暂的延迟最终达到一致性是完全可接受的。比如支付回调后更新预约单状态用户感知上最多晚几秒看到已支付标记完全不影响业务。5.2 Redis 里锁的学问秒杀场景下的经验教训6 个服务共享一个 Redis 实例里面最容易出问题的是分布式锁。有一次我做了一期限量秒杀活动商品只有 50 份结果活动一开始我发现预约服务的下单接口 QPS 瞬时冲到好几百然后——超卖了。排查下来问题出在我的锁实现方式上。第一版代码用的是最简单的 SETNX 来做锁SET resource_name value NX EX 10。思路是每个请求过来先尝试加锁加锁失败的请求直接返回手慢了。但有个致命的细节释放锁的时候没有校验持有者标识。假如请求 A 加了锁但因为某些原因执行业务超过了 10 秒的过期时间锁自动释放了。此时请求 B 成功加锁并开始执行业务。等到 A 处理完它直接执行 DEL 释放锁——但此时这个锁已经属于 B 了A 这个 DEL 把 B 的锁误删了C 也能加锁成功。锁形同虚设超卖就是这么来的。修复方式是参考 Redisson 的看门狗机制自己实现了一套简化版本。每个锁在创建时生成一个 UUID 作为持锁标识释放锁时用 Lua 脚本原子地比对持锁标识再删除避免误删。同时锁的持有时间不再设死而是用一个后台守护线程每 3 秒检查一次锁是否还存在且持有者是自己如果是就续期 10 秒。这样即使业务执行时间远超预期锁也不会提前失效。这里面有个更底层的教训分布式锁解决的是并发下的互斥问题不是幂等问题。就算锁机制完全正确也需要在数据库层面给唯一业务单号加唯一索引作为最终的兜底防线。我现在 6 个服务的核心表全部设计了至少一个业务唯一键比如预约单号、支付流水号、积分变动单号。即使应用层的幂等逻辑出现漏洞数据库唯一键也会报错拦截保证数据本身就是不会重复的。5.3 一次支付回调与预约服务的死锁现场这个案例我要单独拿出来讲因为它是 6 个服务拆分以后我遇到的最难排查的问题之一也是让我学会明确依赖方向的关键事件。现象是小程序端偶尔出现用户支付成功后预约单状态迟迟没有更新但过一段时间又自己恢复了。起初觉得是网络问题没在意。直到有一天订单积压了上百条用户反馈集中爆发我才开始认真排查。我同时打开了 payment 服务和 booking 服务的日志根据 traceId 串联了一次完整支付回调的日志链路payment 服务正确收到了支付回调更新了本地支付单状态为已支付然后它发起 HTTP 调用 booking 服务执行确认预约单的操作booking 服务收到请求后在自己的数据库事务里更新预约单状态但是 booking 服务在更新预约单之前会先查一次营销服务的优惠券核销状态而优惠券核销状态需要调用 marketing 服务的接口这中间有一次远程调用超时了结果 booking 服务的本地事务回滚预约状态仍然停留在待确认;这个调用链里存在一个很隐蔽的死锁点booking 服务在本地事务开着的情况下发起了对 marketing 的同步远程调用。远程调用耗时不可控它会让本地数据库事务长时间持有锁。如果同一个服务另一条路径需要对同一行数据做更新就会互相等待最终触发数据库死锁或者长时间锁等待大量的预约单就这样卡住了。这个问题的根因不在网络而在服务依赖设计。修复方式分两步走第一步把查询优惠券核销状态这个动作从预约确认的事务中移出去改为异步查询。核心预约主流程不再依赖营销服务的任何接口只能依赖本地数据。第二步给 booking 服务内部增加一条规则本地数据库事务内禁止同步远程调用。所有需要远程数据的操作要么在本地事务开启之前先处理好、要么拆成异步消息来处理。5.4 一个小技巧统一错误码与响应体服务拆多了以后联调成本的上升体现在一个很琐碎的地方——每个服务返回的错误格式都不一样。有的服务返回{code: 500, msg: error}有的服务返回{success: false}有的服务直接一个字符串。前端和网关层处理起来特别难受。我花了半天时间做了一个全局统一的工作设计了一套标准响应体所有服务必须遵循。响应结构固定为{ code: 0, message: success, data: {}, traceId: a1b2c3d4e5f6 }code 分为三层网络层错误5xx网关识别业务层错误4xx业务逻辑拒绝系统层错误5xx 或 5xx 以上的特定取值对应具体微服务的内部异常。traceId 由网关在入口生成通过 HTTP Header 向下游传递所有服务在日志中统一打印保证一次请求的所有日志可以通过 traceId 串成一条链路。这个改动看似工程量不大但收益极高。前端拿到错误码后不需要针对每个服务解析不同的错误结构统一展示提示文案我在排查问题时通过 traceId 能准确地跨服务定位问题到底出在哪一环监控告警也简洁了只需要统计 code ! 0 的比例变化就是错误率的准确度量。5.5 常见问题速查表这一年踩过的典型坑问题现象根因解决思路服务 A 调用服务 B 偶尔超时服务 B 的数据库连接池被慢 SQL 占满独立为 B 配置独立的连接池参数并为慢 SQL 增加熔断与限流高峰期支付与报表操作互相影响共享数据库连接池导致的性能隔离失败在物理层面独立数据库实例并分别在各自服务层配置独立的连接池发布营销服务后小程序端登录异常网关携带的老 token 密钥与用户服务新密钥不匹配将共享密钥与各服务独立密钥分开管理网关只做透传业务服务自行校验某定时任务执行期间接口响应变慢定时任务与实时请求共享同一线程池为定时任务配置独立线程池设置核心线程数与队列上限跨服务查询报错排查半天才发现是字段名不一致不同服务对同一实体的命名规范不同建立公共数据字典列出所有实体在 6 个服务中的统一字段命名这张表是几十次线上问题之后浓缩出来的经验也是我每次调整架构时都会翻出来做对照检查的清单。6. 复盘里的关键权衡一人微服务的取舍准则6.1 那些看起来很好但我不做的方案这一年多的架构迭代过程中有几个方案在我脑子里被反复斟酌过但最后都没有落地。不是说它们不好而是以一个人的资源复杂度收益比不划算。第一是服务网格Service Mesh。Istio 这类工具提供的灰度发布、流量镜像、mTLS 等特性确实很吸引人尤其对于多语言技术栈团队服务网格的价值无可替代。但我的 6 个服务全部是 Java/Kotlin用 OpenFeign / RestTemplate 就能解决服务发现和负载均衡引入 Sidecar 反而让每次发布都要多管理一个代理容器排障链路从看应用日志变成看 Sidecar 日志 应用日志排查体验会更差。第二是分库分表中间件。目前单表最多的数据量在一个月百万条左右MySQL 单表完全能扛住。分库分表最大的价值是解决单库单表的存储和性能瓶颈现在用不上。一旦引入 ShardingSphere 这类框架配置复杂度、运维成本、跨分片查询的限制都会成倍增加属于典型的为不存在的问题买单。第三是容器编排升级到 K8s。前面说过单机 Docker Compose 已经够用了。K8s 的价值在于跨节点调度与弹性伸缩这在单机场景下毫无意义与其为了学习 K8s 而强行上 K8s不如把这些时间花在提升业务代码的质量上。6.2 一个人维护多个服务的容量边界在哪聊完做了和不做的选择我想把一个人到底能维护多少个微服务这个问题正面回答一下。以我的实际体验来看在基础设施自动化相对完备的前提下一个人维护 4-8 个服务是一个比较舒服的区间。低于 4 个拆分的收益不明显高于 8 个每天的监控查看、依赖关系梳理、发布节奏管理就会开始占据过多精力压缩实际写业务代码的时间。我自己的观察是维护服务数量不是核心矛盾核心矛盾是服务间依赖的复杂度。6 个服务如果全是中心辐射式的依赖关系那就还好——所有调用都经过网关或者都依赖一两个基础服务。但如果服务之间出现了网状依赖数量哪怕只有 4 个出问题的概率也会指数级上升。所以我在架构调整时真正关注的不是How many services而是每个服务在依赖图上处于什么位置。6.3 哪些服务永远不应该被拆出去复盘过程中我也总结出一个经验有些模块就算再想拆也绝对不能拆出去。最典型的是用户权限和操作日志。用户权限体系涉及登录态验证、路由访问控制、接口权限校验几乎所有服务都需要依赖它。如果单独拆成一个服务每一次请求都要经过远程鉴权延迟损耗不说还会制造出权限服务挂掉全站登录失败的巨大单点故障。我处理这个问题的办法是将权限校验做成一个本地 SDK打进每个服务里。权限数据通过配置中心分发到每个服务本地缓存 定期刷新请求校验走本地逻辑权限变更最多延迟几秒生效。操作日志也是一样的道理。当初我把审计日志设计成一个独立的 logging 服务要求所有业务服务通过消息队列异步发送日志。这个架构在逻辑上是合理的但实际运行中常常出现消息堆积、日志丢失的情况最后我改成了每个服务直接写本地文件日志由 Filebeat 统一收集到 Elasticsearch。操作日志本身对实时性要求不高不需要独立的服务进程反而在收集层统一处理更可靠。7. 最后复盘视图这套架构一年下来的真实体感架构运行到现在最直观的效果是稳定性提升。过去单体时期一个月至少出两三次大小事故现在半年可能才出现一次需要人工介入的异常而且大多是第三方依赖导致的比如短信服务商 API 偶尔挂掉或者云厂商网络波动。这种稳定性提升不是我代码写得多好而是架构层面的隔离性天然兜住了不少低级失误。从维护成本来看也远比想象中低。每天早晨我会花大约 15 分钟做一次全局巡检看 Prometheus 的错误率趋势、Elasticsearch 有没有异常堆栈、备份任务是否正常执行。每周发布 2-3 次每次从合并代码到上生产大概 20 分钟。这个节奏对一个人来说是可以长期持续的不会有守着系统不敢动的紧绷感。我个人的一个体会是一个人搞微服务最关键的认知是要接受设计往往是折中的产物。这套 6 服务架构对比教科书式的微服务其实做了很多不标准的妥协允许跨库只读、不用分布式事务框架、权限 SDK 本地化。但这些妥协都是有意识的取舍不是偷懒或者侥幸。如果再从这套体系往上走一步下一步我会考虑的是将中间件部分独立成服务比如把 Redis 集群化到独立节点增强缓存层的可靠性或者引入轻量级 Dapr 来管理状态与发布订阅摆脱手写 outbox 消息表的繁琐。但那一天可能要到服务的调用量再上一个台阶或者服务的数量继续增加了才会到来。在那之前这套一人 6 服务的架构就是我目前能维持的最高性价比。对同样打算走这条路的朋友我的建议是不要在架构上追求标准答案要追求的是你的时间、你的精力、你的业务体量三者之间最舒服的平衡点。架构这件事最适合的才是最好的。
返回列表