最近我刚带着团队把一个饮食健康管理系统从单体架构重构成微服务架构,技术栈正是SpringBoot + Vue + SpringCloud + 微信小程序。前后折腾了小半年,踩了不少坑,也积累了不少实战经验。今天就把整个项目的核心设计、技术选型思路、实操细节和排坑记录整理出来,给准备做类似系统或者正在做微服务改造的朋友一个参考。
先交代一下这个系统是干什么的。用户通过微信小程序记录每日三餐、体重、运动情况,系统根据这些数据给出营养摄入分析、饮食建议和健康报告;后台管理端用Vue搭建,运营人员可以维护食谱库、营养素数据库、发布健康资讯;后端则拆成了用户服务、饮食记录服务、营养分析服务、推荐服务、消息服务等多个微服务,通过Spring Cloud体系做服务治理和网关路由。
这套系统适合谁参考?如果你正在做毕业设计、个人项目,或者公司里需要从零搭建一套微服务架构的完整业务系统,这篇文章可以给你一个成体系的设计蓝图;如果你已经会SpringBoot单体开发,但对微服务拆分、分布式事务、服务间通信这些概念还停留在理论阶段,这篇文章里的实操细节和问题排查也能帮你少走弯路。
1. 整体架构设计与技术选型
1.1 为什么饮食健康系统需要微服务架构
很多人一听到"微服务+分布式"就觉得是在炫技,一个小项目不需要这么重。我一开始也这么想过,但真正梳理完业务需求之后发现,这个场景其实非常适合微服务架构。
饮食健康管理系统的业务链条很长:用户注册登录、饮食记录上传、OCR识别菜品(有的版本还会接入图像识别)、营养数据分析、个性化食谱推荐、健康报告生成、消息推送,再加上后台的食谱管理、用户管理、数据统计。这些功能对资源的消耗差异很大:OCR识别是计算密集型,营养分析是数据处理密集型,而用户登录和食谱查询是典型的IO密集型。如果全部塞在一个单体应用里,某个模块流量突增就会拖垮整个系统。
举个例子,我们上线初期做了一次健康打卡活动,用户集中在早上和中午上传饮食照片,OCR识别服务的CPU瞬间拉满,导致普通用户的登录请求也变慢了。这就是单体架构典型的"互相拖累"问题。拆成微服务之后,OCR识别服务独立扩容,即便它扛不住也不会影响其他服务的可用性。
另外从团队协作角度来说,微服务拆分之后,不同模块可以由不同的小组独立开发、独立部署,互不阻塞。这对后续系统扩展——比如将来要接入更多健康设备的数据、增加AI营养师对话功能——都留了足够的弹性空间。
1.2 核心技术栈拆解与选型理由
这套系统的技术栈选型,每一个组件都是基于实际需求反复对比之后确定的。
后端主体用的是SpringBoot,这个没什么可争议的,SpringBoot在Java生态里的统治地位至今无法撼动。我们用的是SpringBoot 2.7.x版本,这里提醒一句:不要盲目追求最新的大版本。SpringBoot 3.x要求JDK 17以上,而且对SpringCloud的版本兼容性要求更严格,如果你用的是SpringCloud Alibaba组件,很多老版本的集成方案在3.x下会出问题。我们团队里有成员一开始用了SpringBoot 3.0,结果Nacos客户端和Sentinel的适配折腾了好几天,最后退回2.7.x才顺利跑通。
服务治理框架选的是SpringCloud Alibaba生态,核心组件包括:
- Nacos:同时承担服务注册与配置中心的功能,比Eureka+Config分开部署省事得多,而且Nacos自带控制台,查看服务健康状态、动态调整配置都很方便。
- Spring Cloud Gateway:统一API网关,负责路由转发、鉴权、限流。我们对比过Zuul,Gateway基于WebFlux响应式编程,性能更好,而且路由配置更灵活。
- OpenFeign:服务间声明式HTTP调用,配合Nacos做服务发现,写起来非常舒服,性能上虽然比Dubbo的RPC稍差一点,但对于我们的业务量完全够用。
- Sentinel:流量治理组件,做限流和熔断降级。选它没选Hystrix的原因很简单:Hystrix已经停止维护了,Sentinel还有实时监控面板,对排查问题帮助很大。
- Seata:分布式事务框架,只用到了AT模式处理比较简单的跨服务事务场景,后面会详细说。
前端后台管理用的是Vue,选Vue 2.7还是Vue 3取决于团队熟悉程度。我们用Vue 3 + Element Plus + Pinia。Vue 3的组合式API写业务逻辑比Vue 2的选项式API更顺手,尤其是管理后台这种表单多、交互逻辑复杂的场景,组合式API的代码复用能力能减少不少重复代码。
小程序端用的是原生微信小程序语法,搭配uni-app做了条件编译,保证同一套代码将来能扩展发布到支付宝小程序和抖音小程序。这里说明一下,如果你只做微信小程序,原生语法就够了,没必要引入uni-app增加一层抽象;但如果团队有跨端需求,尽早用uni-app能省下后面改造的大量时间。
2. 核心功能模块与业务设计拆解
2.1 用户端小程序的功能设计与业务逻辑
小程序端是用户直接接触的入口,功能设计需要覆盖"记录-分析-建议-追踪"完整闭环。
饮食记录模块是整个系统的数据基础。我们最初只做了手动输入食物名称和克数,用户嫌麻烦,留存率很低。后来改成两种方式:一是按餐次(早餐、午餐、晚餐、加餐)选择食物模板,系统内置了上千种常见食物的营养素数据库,用户直接搜索或从常用列表里勾选;二是拍照识别,调用OCR服务识别菜品,然后映射到食物库。第一种方式实现简单且准确率高,第二种方式体验好但在识别准确率上需要持续调优。
营养分析模块是核心价值所在。用户每次记录完饮食,服务端需要计算当餐和当日的热量、蛋白质、脂肪、碳水化合物、膳食纤维、钠等核心营养素摄入量,并与该用户的基础代谢率(BMR)和推荐摄入量做对比。这里有一个容易忽略的细节:不同用户的性别、年龄、身高、体重、活动系数不同,基础代谢率差异很大,不能用一个统一的推荐值。我们使用Mifflin-St Jeor公式计算BMR,再乘以活动系数得到每日总热量消耗(TDEE),然后根据用户的健康目标(减脂、增肌、保持)设置不同的热量缺口或盈余比例。
健康建议模块根据分析结果给出可执行的反馈。如果某餐蛋白质摄入不足,系统会推荐富含蛋白质的食物;如果钠摄入超标,会提醒减少腌制食品。这块我们用的是规则引擎,配置了一组可扩展的规则条件,比如"当蛋白质摄入量低于推荐值80%且连续2天出现时,触发蛋白质补充建议"。用规则而不是AI模型,是因为规则的结果可解释、可控,在MVP阶段性价比最高。
数据追踪模块用图表展示体重趋势、营养摄入趋势和饮食打卡记录。这里的数据不是实时算的,而是每天晚上由定时任务预聚合生成,前端查询时直接读聚合结果,避免每次都跑大数据量的计算查询。
2.2 管理后台的功能设计与权限控制
管理后台是运营和管理的工具,我们用Vue实现,功能分成四大块:
食材与食谱管理:维护食物营养数据库、菜品库、食谱库。这部分对数据质量要求很高,因为用户端的营养分析准确度完全依赖基础数据的准确性。我建议食物库的字段设计不要只存"热量"这一个数字,至少要有:每100克的热量、蛋白质、脂肪、碳水、膳食纤维、钠含量,以及食物分类和可食部比例。可食部比例这个字段特别容易被忽略——比如带壳鸡蛋,如果用户输入的是去壳后的重量,那不需要修正,但如果是带壳重量,就需要按可食部比例折算,否则热量会偏高。
用户管理:查看用户列表、用户详情、用户健康档案,支持禁用异常账号。这里要设计好用户数据的分权:运营人员只能查看脱敏数据,营养师角色可以查看详细的健康档案,管理员才能执行封禁操作。
内容管理:发布健康资讯、饮食科普文章、系统公告。内容发布后通过消息服务推送给用户端,这个业务场景正好用来实践消息队列。
数据看板:用ECharts展示用户增长趋势、活跃度、饮食记录数量、热门食材排行等指标。这里的统计数据来自一个独立的统计服务,从其他服务的数据库中定时同步数据到自己的库,再生成报表。
权限控制这块,我们用的方案是Spring Security + JWT,配合自定义的RBAC权限模型,菜单和按钮级别的权限都从前端路由动态生成。Vue端用动态路由匹配用户有权限的页面,没有权限的菜单不会出现在侧边栏,同时在路由守卫里再做一次校验,防止直接输入URL绕过菜单访问。这里有一个实践要点:前端路由拦截只是体验优化,真正的安全校验必须在后端完成。我们给每个管理接口都加了权限注解,比如@PreAuthorize("hasRole('ADMIN')"),确保就算有人绕过前端直接调接口也拿不到数据。
3. 微服务拆分与SpringCloud落地实践
3.1 服务拆分的原则与边界划分
微服务拆分是这门架构里最考验功力的环节,拆得太粗等于没拆,拆得太细又会被服务间通信的成本拖死。我们最终拆成了6个服务,拆分依据遵循了三层思想:高内聚低耦合、按业务能力拆分、按数据边界拆分。
- 用户服务(user-service):负责用户注册登录、健康档案管理、基础代谢率计算、用户偏好设置。
- 饮食记录服务(record-service):负责饮食记录的增删改查、食物搜索、餐次数据管理。
- 营养分析服务(analysis-service):负责营养素计算、摄入对比分析、健康报告生成。
- 推荐服务(recommend-service):负责食谱推荐、食物替换建议、基于规则的健康建议生成。
- 消息服务(message-service):负责站内信、微信订阅消息推送、系统公告。
- 系统管理服务(admin-service):负责后台用户管理、内容管理、数据统计看板。
每个服务都拥有独立的数据库,这是微服务架构数据隔离的铁律。你可能会觉得"明明同一块数据两个服务都要用,拆开之后查询变复杂了",确实会有这种情况,但数据独立是微服务的根基——如果两个服务共享一张表,那它们本质上还是一个整体,别说独立部署了,连数据库层面的耦合都解不开。
有跨服务的数据需求怎么办?答案是通过接口调用或数据冗余。举例来说,营养分析服务需要用户的年龄、性别、身高、体重来计算BMR,这些数据在用户服务里。分析服务不直接查用户库,而是通过OpenFeign调用用户服务提供的健康档案查询接口获取。这带来一个性能问题:一次营养分析请求需要调用用户服务拿档案数据。我们的优化方案是在分析服务里冗余一份"用户基础档案"表,记录分析所必需的字段,用户档案变更时通过消息通知异步更新冗余表。读走本地冗余表,写走消息同步,性能问题和一致性问题都解决了。
3.2 Nacos注册中心与配置中心实战
Nacos在这里承担两个职责:服务注册发现和配置管理。服务注册这块基本是开箱即用,只要在SpringBoot应用里引入spring-cloud-starter-alibaba-nacos-discovery依赖,配置好服务名和Nacos地址,应用启动后就会自动注册。真正需要注意的是命名空间和分组的概念。
我们按环境划分命名空间:dev、test、prod三个环境各一个命名空间,每个命名空间下服务的配置相互隔离。这样做的好处是本地开发连的Nacos里配置的是开发库地址,测试环境启动实例会自动拉到测试库配置,不用每个环境单独改配置文件。个人经验:如果项目要长期维护,环境隔离在第一天就做好,后期省心太多。
配置中心方面,我们把数据库连接、Redis地址、消息队列地址、业务阈值参数都放进了Nacos配置中心,用YAML格式维护。这里有一个典型的坑:配置热更新。默认情况下,Nacos配置发生变更,SpringBoot应用不会自动感知,需要给配置类加@RefreshScope注解才能实现动态刷新。我们一开始漏了这个,改了配置之后怎么都不生效,排查了半天才发现是@RefreshScope的问题。
还有一点,Nacos配置中心的dataId命名规则是服务名-环境名.yaml,比如record-service-dev.yaml。工具版本要注意:Nacos 2.x版本相比1.x在通信协议上变化很大,spring-cloud-starter-alibaba-nacos-discovery的2.2.x版本对应Nacos 1.x,要使用Nacos 2.x服务器端的话,客户端依赖版本需要升级到2021.x或2.2.1及以上。这里版本不匹配会报各种奇怪的连接异常,排查时优先怀疑版本兼容性。
3.3 Gateway网关的路由、鉴权与限流实现
Spring Cloud Gateway是整个微服务集群的门面,所有外部请求都先到网关,再由网关转发到对应的服务。
网关的三大职责:路由转发、统一鉴权、限流。路由配置有两种方式:配置文件硬编码和代码动态路由。我们最初用配置文件写死在application.yaml里,每个服务一个路由规则,路径前缀比如/api/user/**转发到用户服务,/api/record/**转发到饮食记录服务。后来服务多了之后,配置文件的维护成本上升,就改成了基于Nacos的动态路由实现。不过对于大部分中小项目,配置文件方式完全够用,不要为了"动态"而动态。
统一鉴权在网关做的是Token合法性校验。用户的JWT Token在网关层校验签名和过期时间,校验通过后把用户ID解析出来放在请求头的X-User-Id字段里,转发给下游服务。下游服务直接从请求头里拿用户ID,不再重复校验Token,这能减少一次Redis查询的开销。这里要强调一个安全细节:对外的网关必须把传递用户ID的私有请求头在入口处清理掉,防止用户伪造请求头冒充他人身份。我们的做法是在网关的GlobalFilter里先删除客户端传来的X-User-Id头,再重新设置解析出的真实用户ID。
限流用的是Sentinel的网关限流模块,按照用户维度和接口维度各配了一套规则。以用户维度为例,饮食记录提交接口的QPS阈值是每秒10次,超过阈值的请求直接返回"操作过于频繁"的提示。实际测试下来,正常用户的操作频率远低于这个值,所以阈值不会误伤,但能有效防止脚本批量刷数据。
4. 分布式场景下的关键技术实践
4.1 分布式事务:Seata AT模式的落地与局限
单体架构下的事务由数据库的ACID特性保证,改成微服务之后就麻烦了——一次业务操作可能跨多个服务、操作多个数据库,无法用单库事务解决。饮食健康系统里最典型的跨服务事务场景是:用户提交饮食记录时,系统要在饮食记录服务写记录数据,同时要在用户服务侧更新用户的"连续打卡天数"状态。
这个场景字面上看涉及两个服务、两个库的事务,实际上我们用Seata AT模式处理。AT模式的核心思想是:业务SQL执行前记录数据快照,如果全局事务回滚,根据快照反做补偿恢复数据。说直白点,它会自动帮你生成反向SQL来做回滚,不需要写额外的补偿代码,对业务代码的侵入性非常小。
但我要坦率地说,Seata AT模式在生产环境中不是银弹。开全局事务会带来额外的性能开销,每参加一个分支事务都要和TC通信,网络延迟会影响整体RT。而且一旦全局事务的隔离级别控制不好,会出现脏读问题——AT模式默认的全局隔离级别是读未提交,这意味着一个未提交的全局事务修改的数据,可能被其他事务读出来。所以我的建议是:能用消息队列最终一致性解决的问题,就不要上分布式事务。Seata只用来处理那些对强一致性要求极高的场景。
我们项目里最终把"打卡状态更新"改成了异步消息方案:饮食记录服务本地事务提交后,发送一条"饮食记录已创建"的MQ消息,用户服务消费消息后更新打卡天数。如果消费失败就重试,重试多次不成功就落进死信队列,人工处理。最终一致性完全够用,而且性能比Seata好很多。
4.2 Redis分布式锁:库存场景与防重复提交流程
微服务架构下,多个实例同时运行,本地锁synchronized已经失效了,必须用分布式锁来解决跨实例的资源竞争问题。我们在两个场景用到了分布式锁。
第一个场景是活动秒杀类功能。系统偶尔会做"限时免费领取营养师咨询资格"这类活动,名额有限,多个用户同时抢,服务又是多实例部署,这就是典型的分布式锁场景。实现方案基于Redis的SETNX命令:用活动ID和用户ID拼起来作为锁的key,只有第一个设置成功的请求能继续执行,后面的请求直接返回"已被领取"。这里有两个关键细节:加锁时要同时设置过期时间,防止拿到锁的实例突然宕机导致死锁;加锁的value要带上唯一的请求ID,释放锁时先判断是不是自己的锁,防止误删别人持有的锁。推荐用Redisson客户端,它封装好的RLock已经处理了看门狗自动续期的问题,不推荐自己用SETNX手写锁,容易出现超时问题或者忘删锁的Bug。
第二个场景是用户重复提交。前端做了按钮防抖,但网络慢或者用户快速连点时,后端还是可能收到两条相同的饮食记录。我们在提交接口上用用户ID加当天日期作为key加分布式锁,同一用户同一秒只能提交一次。这样做本质上是从接口幂等性的角度出发,比单纯的前端防抖可靠得多。
4.3 服务间通信与数据一致性方案
服务间通信,我们用的是OpenFeign。Feign的声明式API风格让调用远程接口像调用本地方法一样简单,开发效率很高。但Feign有一个坑:默认的超时时间很短,容易在慢接口上触发超时。我们当时调营养分析服务的报告生成接口,因为要做大量计算,响应时间超过2秒,Feign默认的1秒超时就报错了。解决方案是在配置里把超时时间调整到合适的值,同时给Feign加上重试机制。不过要注意:重试只适合GET之类幂等的请求,POST写请求重试要非常谨慎,搞不好会重复创建数据。
数据一致性是分布式系统永恒的话题。除了前面提到的用MQ保证最终一致性,还有一个实践要点是采取"本地消息表"方案实现可靠消息投递。具体来说:业务服务和消息服务不在一个数据库里,为了确认消息一定发出去了,在业务库里建一张本地消息表,把待发送的消息和业务数据放在同一个本地事务里写入,然后由定时任务把状态为"待发送"的消息扫描出来,发送到MQ,收到发送成功的确认后,把消息状态更新为"已发送"。这套方案实现不复杂,但能有效避免"业务成功但消息没发出去"和"消息重复发送"两个经典问题。消息重复发送的问题消费时要做幂等处理,我们给每条消息设置一个全局唯一的业务ID,消费端根据这个ID去重。
5. Vue管理后台与小程序端的实现要点
5.1 Vue3后台管理系统的工程化实践
后端管理用Vue 3 + Element Plus + Vite构建。工程初始化直接用的Vue官方的create-vue脚手架,选上TypeScript支持。这里建议项目一开始就用TypeScript,管理后台的接口返回数据往往结构复杂,有类型定义能省掉大量字段拼错导致的bug排查时间。
项目的目录结构按"功能模块 + 页面"组织:src/views/roomManagement、src/views/dataAnalysis等。每个功能模块下包含:列表页、表单页、详情页对应的Vue文件,以及该模块独立的API请求模块和TypeScript类型定义文件。这样做的好处是模块边界清晰,多人协作时不容易出现代码冲突。
路由设计用了动态路由方案:用户登录后,后端返回该用户的角色和权限码,前端根据权限码动态生成路由表,注册到Vue Router中。具体实现里要注意一个容易踩的坑:动态路由注册之后,用户在浏览器里刷新页面会导致路由表丢失,需要在路由守卫里判断路由表是否已加载,如果没加载就重新动态注册。我们当初漏了这一步,用户从列表页点到详情页再刷新就白屏,排查了很久才定位到问题。
接口封装方面,我们用axios实例统一处理请求:baseURL指向网关地址,请求拦截器里带上Token,响应拦截器里统一处理错误码。后端返回格式约定为{ code, message, data },code为0表示成功。如果code为401则跳转登录页,其他非0码在页面里用ElMessage提示后端返回的消息。这样前后端联调时贡献出了一个项目约定,有效避免了每个页面写一套错误处理逻辑的混乱局面。
5.2 微信小程序端的实现与前后端联调
小程序端我们用原生语法开发,基础架构分为:pages页面、components组件、utils工具函数、api请求模块、store状态管理。
技术要点上有几个值得展开的地方。请求封装上,小程序原生wx.request功能比较原始,我们封装了一层统一处理:每次请求前从storage里读取Token,放在Authorization请求头里,所有请求走相对路径,基础域名放到app.js里的全局配置中。开发环境下用本地局域网IP,因为小程序开发者工具不能直连localhost后端。真机预览时,域名必须是HTTPS并且在小程序后台配置合法域名,这是开发阶段最容易被卡住的问题。
页面间通信和数据共享,我们用了一个轻量级的全局状态管理方案:毕竟是原生小程序,不像Vue有完整的Pinia,我们直接在app.js里维护一个全局data对象,或者使用wx.emit和wx.on方法自己做事件总线。确保一个场景:用户在记录页提交了饮食数据,回到首页需要立即刷新今天的营养汇总——通过事件总线通知首页重新拉取数据。
小程序端的Token过期处理是一个实操中必须解决的问题。我们采用的方案是:后端返回401错误码时,小程序端不直接让用户重新登录,而是自动调用refreshToken的接口(一个专门发刷新Token的接口)尝试续期,续期成功就重放刚才失败的请求;续期失败才跳转登录页。这个体验优化非常重要,尤其是用户每天第一次打开小程序时往往已过Token有效期,处理不好会非常影响使用体验。
6. 部署实践与常见问题排查实录
6.1 基于Docker Compose的环境搭建与部署流程
部署方案我们用的是Docker Compose,因为服务器规模还没到必须上Kubernetes的程度,Compose足够管理这套微服务集群。
整个部署环境包含的容器有:MySQL(两个实例,分给不同服务)、Redis、Nacos、RabbitMQ、Seata Server,以及我们自己的6个微服务容器。统一用docker-compose.yaml编排,配置里指定镜像版本、端口映射、环境变量。有个经验:生产环境的容器一定要设置内存限制,比如Java服务限制-Xmx512m,防止某个服务内存泄露把整台服务器拖垮。
部署流程上,我们的CI/CD流程是:代码推送到Git仓库后,Jenkins从仓库拉取代码,执行Maven打包和前端构建,构建Docker镜像,推送到私有镜像仓库,然后在服务器上拉取最新镜像并更新容器。这套流程对中小规模项目投入产出比已经很划算,不需要上GitLab CI或者GitHub Actions那套更复杂的配置。
部署过程中最容易出问题的是Nacos和Seata,它们依赖MySQL存储配置数据,而且初始化表结构是自动执行的,如果MySQL的字符集设置不对,表创建不了,后续服务注册就都会失败。我们统一的字符集是utf8mb4,在MySQL容器启动时通过command参数指定。
6.2 常见问题速查表与独家避坑技巧
最后整理了这套系统开发过程中最常遇到的20个问题,按严重程度排个优先级,每个都是实际踩过的坑。
| 症状 | 根本原因 | 解决方案 |
|---|---|---|
| 服务启动后注册不到Nacos | Nacos命名空间不一致 | 检查服务application.yaml里的namespace字段和Nacos控制台创建的命名空间ID是否一致 |
| 网关转发请求超时 | 路由配置未指定lb://前缀 | 路由URI必须写成lb://service-name格式,不能直接写IP |
| 接口返回的数据是旧的 | 本地缓存+多实例缓存不一致 | 用Redis做统一缓存,本地缓存要设置短过期时间且只缓存不敏感数据 |
| 前端打包后访问白屏 | 静态资源路径配置错误 | Vite构建配置base: './',避免绝对路径导致资源加载失败 |
| 分布式锁总是不生效 | Redisson锁对象没有用唯一前缀 | 确认锁key的粒度设计,避免不同业务共用同一把锁 |
| 消息队列积压严重 | 消费者处理速度跟不上 | 优化消费逻辑,批量处理消息,提高prefetch count |
| 数据库慢查询导致接口卡顿 | 分页查询没有走索引 | 给查询条件涉及的字段建立联合索引,特别是时间字段 |
| SpringBoot启动报循环依赖 | 2.6版本默认禁止循环依赖 | 优先重构代码消除循环依赖,临时方案是设置allow-circular-references=true |
再分享两个独家经验。第一个是微服务排障的杀手锏:这几个服务的日志分散在不同容器里,出了问题只能一个个容器翻日志,效率极低。后来我们统一把日志输出到JSON格式,收集到同一个日志平台集中查询,通过traceId串联一次请求经过的所有服务日志。从动手搭建日志统一方案开始,排查问题的时间缩短到原来的三分之一,这个投入非常值得。
第二个是接口响应时间的监控实践。我们在网关层给每个请求记录耗时,把耗时超过1秒的接口单独拉出来定期分析。食用、饮水等方式逐步优化性能。系统上线之前一定要做一次全链路的压力测试,至少模拟平时三倍的流量,看看哪个服务最先到达瓶颈,提前扩容。
这个项目做到一半的时候,我最大的感受是微服务架构不是"设计出来"的,而是"演化出来"的。一开始不需要把服务拆到极致,而是从2到3个核心服务起步,随着业务增长逐步拆分。服务体系拆到6个的时候,团队还能维护得过来,大家的业务认知也最清晰。
最后给想复现这套系统的朋友一个务实的建议:不要从零开始造轮子。项目初始化直接用Spring Initializr生成骨架,微服务组件引入SpringCloud Alibaba的官方示例作为起点,前端用Vite脚手架初始化之后替换业务代码。把更多的精力花在业务设计和数据模型设计上,那才是这套系统真正的价值所在。踩坑的过程中我对分布式系统的敬畏又多了一分:架构不是越复杂越好,而是恰好能解决当前问题、能平滑演进才最好。