ARTICLE DETAIL

资讯详情

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

饮食健康管理系统微服务架构设计与SpringCloud落地实践

饮食健康管理系统微服务架构设计与SpringCloud落地实践 去年接手了一个饮食健康管理系统的开发项目需求方要求同时输出微信小程序端和PC管理后台支持用户日常饮食记录、营养摄入分析、健康打卡、食谱推荐等核心功能。我一开始图省事直接用单体SpringBoot把服务端一股脑做完了结果业务越加越多减肥人群、慢病人群、普通用户的推荐逻辑全耦合在一个工程里每次改需求都要重新打包部署数据库表也越堆越乱。后来痛定思痛把整个后端重构成了微服务分布式架构技术栈定为SpringBoot SpringCloud Vue 小程序多端联动。这篇文章就完整复盘一下这套系统的架构设计与落地过程包括微服务怎么拆、SpringCloud组件怎么选、分布式事务和分布式锁怎么落地、前端双端怎么对接以及我在真实部署过程中踩过的那些坑。适合正在做微服务毕业设计、或者想把单体项目升级成分布式架构的Java开发同学参考。1. 为什么一个饮食健康管理小程序需要微服务1.1 从单体吃紧到微服务改造的转折点先交代一下背景。这个项目刚起步时只是做一个记录每天吃了什么、算算卡路里的小工具用户量不大功能也不复杂单体应用绝对是性价比最高的选择。但我做需求分析的时候发现这套系统的业务面其实很宽基础的用户注册登录、饮食记录上传、食物数据库检索、营养元素计算、健康评估报告、食谱推荐、积分打卡、消息推送还要接一个管理后台来做食物库和文章内容的维护。如果全塞进一个SpringBoot工程初期开发确实快但到了中期就非常难受。举个例子营养分析服务需要对食物图片做OCR识别和营养成分换算计算逻辑比较重而打卡积分服务只是简单的Redis计数加数据库更新。这两个东西的访问频率、资源消耗、迭代节奏完全不同硬放一起每次上线都得互相牵制。更麻烦的是小程序端高频请求饮食记录接口偶尔一次大促式运营活动会把打卡积分接口流量顶得很高单体架构下流量分不开一个小接口抖动就可能拖垮所有用户。所以说微服务不是赶时髦而是当系统存在三个以上异步迭代的业务模块、且模块间的资源消耗和访问模式差异明显时一种比较自然的拆分选择。1.2 这套系统到底要管哪些事为了把架构设计讲清楚先列一下这套饮食健康管理系统的核心功能清单用户端小程序微信授权登录、个人健康档案维护、饮食拍照/手动记录、每日营养摄入统计、健康打卡、食谱浏览与收藏、积分与等级。管理后台Vue端用户管理、食物数据库管理、食谱管理、健康资讯文章管理、打卡规则配置、数据统计看板、轮播图等CMS配置。公共能力图片文件上传、短信/订阅消息推送、统一认证鉴权、日志链路追踪、配置管理。功能一梳理完服务边界就比较清楚了。我在动手之前画了一张服务划分表虽然微服务架构图最后会被各种组件连线塞得密密麻麻但最核心的还是那几个业务服务的边界这张表我放在下面。2. 服务边界怎么切从单体到六个微服务的拆分思路2.1 按领域边界而不是按功能模块切很多初学者拆微服务习惯按用户管理、食谱管理、打卡管理这种页面功能去切听起来好像也行但本质上还是把一个Controller一个Service搬出去没有解决耦合问题。我更推荐按领域边界拆也就是围绕业务能力而不是页面入口来划服务。以这个饮食健康管理系统为例用户注册登录和用户健康档案其实是可以放一个服务的因为它们都围绕用户这个核心实体饮食记录和营养分析必须放一起因为一条饮食记录背后要联动食物数据库查询、营养元素计算拆开了就得频繁做分布式事务而打卡积分虽然是用户行为但它依赖的是积分规则引擎和用户资料几乎无关适合独立部署、独立扩容。最终我拆成六个微服务每个服务可以独立开发测试、独立部署互不阻塞。2.2 六个微服务的职责说明与调用关系服务名核心职责关键依赖user-service登录认证、用户档案、健康指标MySQL、Redisdiet-service饮食记录、食物库管理、OCR识别MySQL、Redis、MinIO文件health-service营养分析、健康评估报告、数据统计MySQL、Redis、消息队列content-service食谱管理、健康资讯文章、CMS配置MySQL、Redispoints-service打卡签到、积分流水、等级计算MySQL、Redisgateway-service统一入口、路由转发、JWT鉴权、限流Nacos、Redis服务间调用关系大致是这样的小程序端请求先进gateway-service网关做完JWT鉴权和路由转发后把请求分发到具体的业务服务user-service负责登录和换取Tokendiet-service接收饮食记录后会调用health-service做营养分析同时把打卡事件发到消息队列points-service订阅消息队列中的打卡事件完成积分累计content-service比较独立主要给小程序和管理后台提供内容查询接口。这里有个很关键的落地细节健康分析是同步调用还是异步解耦我一开始用的是OpenFeign同步调用diet-service去调health-service结果饮食记录高峰期经常因为健康分析响应慢拖累记录保存接口。后来优化成先落库、后分析的异步模式记录保存后立即返回用户营养分析结果延迟几秒更新到记录上。用户在体验上几乎感知不到系统吞吐量却上了一个量级。2.3 单体转微服务后的公共模块抽取服务一拆分公共代码就成了第一个坑。实体类、DTO、工具类、统一返回结果如果每个服务各写一份后面改一个字段得同步改六个工程。我的做法是抽取了一个common模块用Maven多模块管理把通用实体、常量、异常处理、统一响应结构、Redis工具类、JWT工具类全部下沉到common里业务服务通过依赖引入。不过公共模块不能塞太多东西否则就成了隐形的耦合中心。我只把稳定的、几乎不变的东西放进去每个业务服务自己的核心逻辑还是各写各的。这个度要把握好一个常见的反面案例是有人把Feign客户端也集中放到common里结果common一改动所有服务都要重新编译部署等于把单体依赖又搬了回来。3. 注册中心、网关、配置中心SpringCloud核心组件的选型与落地3.1 SpringCloud官方还是SpringCloud Alibaba这是做技术选型时第一个要拍板的问题。SpringCloud官方全家桶和SpringCloud Alibaba全家桶目前都比较成熟但我个人建议直接上SpringCloud Alibaba生态核心原因是Nacos可以同时搞定注册中心和配置中心省去部署Eureka加SpringCloud Config两套组件的麻烦。如果你还是学生或者第一次接触SpringCloud担心Alibaba生态和SpringCloud不兼容其实不用担心。SpringCloud Alibaba本质上就是SpringCloud的扩展实现只是在注册发现、配置管理、分布式事务这些组件上换了具体的落地产品。只要SpringBoot版本和SpringCloud Alibaba版本对齐使用体验非常顺。我这次用的是SpringBoot 2.7.x搭配SpringCloud Alibaba 2021.0.x这套版本组合比较稳定网上教程也多出了问题好查。有一点必须提醒SpringBoot版本太高不一定是好事比如SpringBoot 3.x之后要求JDK17起步很多老教程和开源组件都没跟上踩坑成本成倍增加。3.2 Nacos注册中心与配置中心的一体化落地Nacos部署并不复杂我用Docker方式跑单机版开发阶段完全够用。服务的注册代码只需要在pom里引入依赖然后在配置文件里指定Nacos地址即可。核心配置代码大致如下spring: application: name: user-service cloud: nacos: discovery: server-addr: 127.0.0.1:8848 config: server-addr: 127.0.0.1:8848 file-extension: yaml namespace: dev这里有个很容易忽略的点每个微服务的配置文件我都没有把数据库地址、Redis地址直接写在服务本地的application.yml里而是统一放到Nacos配置中心用spring.cloud.nacos.config去拉取。这样改配置不用重新打包Nacos里改完刷新即可。但开发阶段配置中心偶尔会拉取失败所以我保留了一个spring.profiles.active的开关本地联调可以直接切回本地配置方便排查问题。服务启动后在Nacos控制台的服务列表里能看到user-service、diet-service这些实例都上线了。Nacos的临时实例采用心跳上报机制非临时实例用服务端主动探测我用的是默认临时实例服务异常时能快速摘除。3.3 SpringCloud Gateway网关统一入口与统一鉴权网关是整个微服务架构流量的第一道关卡我用的SpringCloud Gateway纯响应式网关性能和稳定性都够用。网关做了三件事路由转发、JWT统一鉴权、接口限流。路由配置简化后大概是这样的spring: cloud: gateway: routes: - id: user-service uri: lb://user-service predicates: - Path/api/user/** - id: diet-service uri: lb://diet-service predicates: - Path/api/diet/** filters: - StripPrefix1注意lb://前缀一定要写这是让网关走LoadBalancer去Nacos拉取服务实例的关键。如果写成了http://127.0.0.1:8081那网关就退化成了静态转发完全失去了微服务动态发现的意义。JWT鉴权我封装了一个全局过滤器白名单路径直接放行比如登录接口其余接口都要校验请求头里的Token。Token验证通过后把用户ID解析出来放进请求头转发给下游服务下游就直接信网关透传的userId不用自己再解析一次Token。这样设计的好处是鉴权逻辑收敛在网关一层业务服务不用关心谁在调、有没有权限代码干净很多。限流我用的RequestRateLimiter过滤器基于Redis做分布式限流按接口维度限制每秒请求数。实际压测下来单机网关每秒能扛住千级请求配合限流规则足够防御突发流量。3.4 服务间调用OpenFeign的超时与重试服务间调用我用的OpenFeign配置了连接超时、读取超时和重试机制。做健康分析异步化之前我试过同步调用的方案健康分析涉及多表查询和多规则计算平均耗时300毫秒遇到高峰经常超时。所以分布式系统里凡是调用链路过长、耗时波动大的场景超时时间不能拍脑袋给死要结合压测数据来定。Feign配置如下feign: client: config: default: connectTimeout: 5000 readTimeout: 10000 httpclient: enabled: true这里有个重试的坑后面单独说先提示一点Feign默认集成的是Ribbon重试只适合幂等接口。写操作如果没做幂等设计重试可能会导致重复扣积分或重复生成报告一定要谨慎。4. 分布式事务与分布式锁健康打卡和会员订单的一致性难题4.1 什么场景真的需要分布式事务微服务拆分后一个用户操作经常跨越多个服务。比如用户在小程序端完成一次每日健康打卡并领取积分这个操作同时涉及points-service的积分账户调整和user-service的连续打卡天数更新。如果不用分布式事务可能积分加成功了但打卡天数没更新用户直接来找客服。但分布式事务是有代价的不是所有跨服务操作都得用。我的原则是能异步就异步能最终一致就最终一致只有强一致要求极高的业务才上Seata。打卡换积分这种场景按道理也能用消息队列做最终一致但考虑到积分变更直接牵涉用户权益我最后选择了Seata的AT模式开发成本低侵入性小。4.2 Seata AT模式接入流程Seata AT模式的核心思路是业务SQL执行前记录undo_log快照事务完成后删除快照一旦出现异常就根据快照反向补偿。我只需要在业务方法上加一个GlobalTransactional注解本地SQL该怎么写还是怎么写不需要手工写补偿逻辑。关键代码如下GlobalTransactional(name daily-checkin, rollbackFor Exception.class) public void checkinAndAwardPoints(CheckinRequest request) { userService.updateCheckinDays(request.getUserId()); pointsService.addPoints(request.getUserId(), request.getPoints()); }接入Seata有几个容易踩的坑。第一个是每个业务库都要建undo_log表我见过有人只在其中一个库建了表事务一执行报错半天找不出原因。第二个是Seata的file.conf和registry.conf配置里的分组名要跟Nacos对上尤其是tx-service-group的配置错了会一直报no available service。第三个是AT模式对SQL有要求比如不能用SELECT ... FOR UPDATE长时间锁行否则事务冲突概率会明显上升。4.3 Redis分布式锁解决重复打卡和积分并发分布式事务解决的是跨服务数据一致性但同服务内的并发问题还得靠分布式锁。比如用户在小程序端手速过快零点瞬间连点两次打卡按钮如果没有锁积分可能被加两次。单机时代用synchronized就行微服务架构下多个实例部署就得用Redis分布式锁。我这里用的是Redisson它比你手动用SETNX实现锁要省心太多封装了看门狗自动续期和可重入特性。核心代码如下RLock lock redissonClient.getLock(checkin:user: userId); boolean locked lock.tryLock(3, 10, TimeUnit.SECONDS); if (!locked) { throw new BizException(操作过于频繁请稍后再试); } try { pointsService.doCheckin(userId); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } }注意tryLock的三个参数等待时间、锁自动释放时间、时间单位。我不建议把锁的自动释放时间设置得特别长默认走了看门狗逻辑后占锁超过30秒会自动续期业务没执行完锁不会丢业务执行完了finally里主动释放双保险。还有一个业务上的细节checkin和pointsService其实都在points-service内部为什么又要用分布式锁又要用分布式事务因为如果打卡和积分加在同一服务里普通的本地数据库事务就够了分布式事务是针对跨服务调用说的。我当时为了避免过度设计把连续打卡天数和积分账户放在同一个points-service数据库里这样内部操作用本地事务加分布式锁就能搞定根本不需要Seata。所以前面说的Seata事务是我在需求方坚持要把用户天数和积分分开维护的情况下才用的实际项目中服务边界一定要结合事务代价来权衡。4.4 分布式锁面试题里最常问的续期问题说起Redis分布式锁热词搜索里也高频出现分布式锁面试题这里给大家补充一个很经典的问题如果业务执行时间超过了锁的过期时间怎么办网上很多人会背加长过期时间或者不用Redis换成Zookeeper但真正合理的做法是用Redisson的看门狗机制。Redisson加锁时默认锁超时时间是30秒同时启动一个后台定时任务每10秒检查一次锁是否还在如果还在就续期到30秒。这样即使业务执行了50秒锁也不会在30秒时自动释放只有服务进程宕机了看门狗停了锁才会因为过期自动释放避免死锁。我在实现打卡接口时依赖的正是这个机制实测跑了几轮并发脚本没有出现锁丢失或者重复加积分的问题。5. Vue管理后台与小程序端的双端联动认证、路由与接口对接5.1 管理后台技术栈Vue3还是Vue2管理后台我用的Vue3。如果你现在还在用Vue2起步新项目我建议直接学Vue3生态已经很成熟了Element Plus配合Vue3的组合式API开发效率很高。Vue端的技术栈是Vue3 Vite Element Plus Pinia Axios。开发环境通过Vite配置代理解决跨域问题。生产环境我直接把构建后的dist目录交给Nginx托管Nginx再把/api开头的请求反向代理到网关地址。nginx关键配置location /api/ { proxy_pass http://127.0.0.1:8888/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }这里有一个细节很容易搞错proxy_pass http://127.0.0.1:8888/;结尾的斜杠很重要它表示把/api/前缀替换成/再转发。如果漏掉斜杠网关那边匹配路由就会带上一层/api前缀导致路由转发失败。我身边不止一个人在这里调了一整天才发现是反斜杠的问题。5.2 动态路由不同角色看到不同的菜单管理后台用户分超级管理员、运营人员、营养师等角色不同角色能看的菜单和操作权限不一样。我用的是动态路由方案登录时后端返回当前用户的角色权限码前端根据权限码动态添加路由和渲染菜单。核心思路是这样前端把所有的页面路由都定义好给每个路由配置meta.roles字段登录后拿到用户的角色用router.addRoute动态挂载有权限的路由。没有权限的路由即使手动输入URL也会被路由守卫拦截。// 路由守卫中动态添加路由 if (!hasAddedRoutes) { const accessible filterRoutes(permissionRoutes, user.roles) accessible.forEach(route router.addRoute(route)) hasAddedRoutes true next({ ...to, replace: true }) }这个方案比写死菜单灵活很多运营需求经常变新增页面或者调权限时不用改代码重新部署。5.3 小程序的认证对接流程小程序端用的是原生微信小程序加uni-app框架主要是看重它的跨端复用能力以后要出支付宝小程序或者App能少写不少代码。小程序和Vue后端联调时最核心的是登录认证流程。微信小程序调用wx.login获取code把code传到后端user-service的/api/user/login接口后端拿code去微信服务器换openid再生成我们自己的JWT Token返回给小程序。小程序拿到Token后存到本地storage之后每次请求都带上这个Token。封装请求时我习惯在header里加Authorization字段const request (url, method, data) { return new Promise((resolve, reject) { wx.request({ url: baseUrl url, method: method, data: data, header: { Authorization: Bearer wx.getStorageSync(token) }, success: (res) { if (res.statusCode 401) { wx.navigateTo({ url: /pages/login/index }) } else { resolve(res.data) } } }) }) }401统一处理很重要Token过期时小程序能自动跳回登录页重新授权否则用户会看到一堆看不懂的报错。小程序端的图片上传走的是MinIO对象存储后端通过网关开放**文件上传接口小程序选择图片后直接上传返回URL再提交业务表单这样饮食记录里的图片路径都是完整可访问的链接。5.4 关于Vue打包放进SpringBoot的特殊需求热搜词里有vue打包放进springboot中确实有一些项目为了部署方便、不想单独维护Nginx会把前端打包产物放进SpringBoot的static目录让一个Java进程同时服务前后端。这个做法的好处是部署简单缺点是静态资源由Java容器提供并发能力不如Nginx而且失去Nginx的静态缓存能力。我的建议是如果部署环境允许还是优先前端独立部署。如果确实要打包进SpringBoot只需把Vue构建后的dist目录内容拷贝到src/main/resources/static/然后后端网关添加一个放行规则让非/api开头的请求都跳转到index.html注意刷新页面时前端路由不能404。这个问题前后端分离场景下经常出现本质原因是SpringBoot默认的静态资源映射找不到Vue Router的前端路径。6. 容器化部署与性能压测本地跑通到线上稳定的最后一公里6.1 Docker Compose编排六个服务和中间件本地开发环境我用的是Docker Compose一键启停MySQL、Redis、Nacos、Seata、MinIO全部编排在一个docker-compose.yml里。下面是简化的编排示意services: mysql: image: mysql:8.0 ports: - 3306:3306 environment: MYSQL_ROOT_PASSWORD: root123456 redis: image: redis:7.0-alpine ports: - 6379:6379 nacos: image: nacos/nacos-server:v2.3.0 ports: - 8848:8848 - 9848:9848 environment: MODE: standalone注意Nacos除了8848端口还开放了9848端口这个9848是Nacos 2.x新增的gRPC端口服务发现时要用。我见过有人只映射了8848服务死活注册不上去查日志才看到连接9848被拒。业务服务的Dockerfile也比较简单基于openjdk:8-jre或openjdk:11-jre镜像把构建好的SpringBoot jar包打进去然后指定启动命令。每个服务用--spring.profiles.activeprod切换到生产环境配置数据库地址、Redis地址都指向Docker网络内的服务名。6.2 链路由SkyWalking和日志关键词搜索把住微服务排查问题的核心痛点是调用链断裂。一个请求先到网关网关调user-serviceuser-service又调points-service中间任何一个环节出问题单看某一台服务的日志根本定位不了。我接入了SkyWalking做链路追踪。每个服务的agent挂载方式很简单启动时加上-javaagent参数即可。链路追踪能看到一次完整请求经过哪些服务、每个服务耗时多少、有没有异常。实际排查中帮了大忙的是一次美食报告生成超时的问题看链路发现耗时主要卡在健康分析服务查询慢SQL上一眼就锁定了方向。日志这块没有刻意引入ELK全家桶先用最朴素的方案落地日志统一格式包含traceId排查问题时直接按网关下发的traceId去检索所有服务日志因为网关在过滤器里会把traceId放进MDC下游服务从请求头取到traceId后也塞进MDC日志打印时自动带上。6.3 JMeter压测三个核心接口的实测数据上线前我压测了三个核心接口小程序登录、饮食记录保存、健康分析报告查询。压测工具用的JMeter线程组模拟200个并发用户循环跑5分钟。实测结果如下接口平均响应时间吞吐量错误率/api/user/login86ms738 req/s0.0%/api/diet/record245ms412 req/s0.2%/api/health/report680ms156 req/s1.1%login接口性能最好因为大部分逻辑是Redis查Token和简单的数据库查询。diet记录接口有点慢主要是保存记录时要写MySQL、再异步发消息、还要调文件服务处理图片压测时错误率0.2%来自个别Feign超时。health/analysis报告查询最重涉及多张表join和营养公式计算我后来给聚合查询加了Redis缓存客户端先从缓存拿结果没命中再查数据库回填缓存。加了缓存后平均响应时间压到了320ms左右效果立竿见影。6.4 高并发场景下的限流和降级预案压测虽然通过了但线上业务总有超出预期的时候。我在gateway-service里给关键接口配了限流规则比如打卡接口单用户每秒最多2次请求超出直接返回操作太频繁管理后台导入食材数据这种低频高耗操作单IP限制每分钟10次。降级方面健康分析服务如果超时或者异常Feign的兜底逻辑返回一个友好的提示用户先看到分析结果正在生成中等异步任务完成后刷新页面就能看到结果。这种体验比直接报错好很多也保护了核心服务不被拖垮。7. 实践中的坑版本兼容、跨域与网关转发的连锁问题7.1 SpringBoot版本太高引发的兼容链问题前面我提了一句SpringBoot版本太高不一定是好事这里展开说说。项目初期我图新直接用了SpringBoot 3.1结果手里的老项目脚手架、MyBatis-Plus版本、Knife4j接口文档工具全都跟不上要么启动报错要么打出来的jar包类型不兼容。SpringBoot 3.x从javax.servlet包迁移到了jakarta.servlet很多第三方库要专门适配新版本才行。如果业务场景没有必须用Virtual Threads或者GraalVM原生镜像我建议还是稳字当头选SpringBoot 2.7.x加JDK8或JDK11。网上绝大部分SpringCloud和微服务教程都能直接跑通遇到问题也好搜答案。搜索引擎里搜springboot版本太高相关的问题非常多大多都是版本错配导致的提前规避比事后排查舒服得多。7.2 Vue开发环境的跨域代理和Cookie Session丢失Vue开发环境联调时浏览器直接请求http://localhost:8888/api/**会跨域。我的解法是Vite配置proxy代理把请求转发到网关同端口浏览器看到的始终是同源请求就不存在CORS问题了。// vite.config.js server: { proxy: { /api: { target: http://localhost:8888, changeOrigin: true } } }另一个很容易踩的坑是网关转发后的Session丢失。有个管理后台接口用的登录验证码验证码存Session里网关转发了两次请求后端取不到前一次存下的验证码。排查后发现SpringCloud Gateway默认不会传递Cookie和Session信息跨服务路由后Session ID就找不到了。解决方案是不要在微服务里依赖HttpSession把验证码等临时数据全部放到Redis里用唯一Key关联。这样网关再怎么转发都不影响因为状态不在本地Session而在分布式缓存中。7.3 Feign重试导致的重复下单与幂等设计Feign默认自带重试机制网络抖动时会自动重试。这在查询接口上无伤大雅但在写操作上就是大坑。比如管理后台在做会员套餐下单的时候订单服务调用积分服务扣减积分第一次请求超时了但服务端其实已经处理成功Feign重试后积分被扣了两次。我的解决思路分两层服务提供方做接口幂等接收方拿到同一个业务流水号时直接返回已处理结果。我在points-service的扣减接口上加了幂等判断根据请求里的orderNo去查流水表存在就直接返回成功。同时对于下单主流程这种不需要自动重试的写操作关闭重试错误交给上层业务逻辑处理。这里提一句像订单、支付、积分这类涉及资金或者权益的写接口接口幂等是必须养的。如果没有精力把所有接口都做幂等至少把积分流水、打卡记录这类高频写操作做上否则压测一跑就露馅。7.4 Nacos配置变更不生效的排查思路有段时间运营改积分规则我在Nacos里更新了points-service的配置结果测试环境服务怎么都不生效重启也没用。查了一圈发现Nacos配置文件里的namespace写的是public但服务本地指定的namespace是dev配置和数据都对不上。这个问题其实很常见Nacos的namespace隔离没搞清楚注册中心和配置中心混用同一个namespace时服务注册的namespace和服务拉取配置的namespace必须一致。建议从一开始就规范命名每个环境一个namespacedev/test/prod配置文件里统一指定。最后再分享一点我做这套系统的个人体会整个项目从单体重构成微服务前前后后花了三个月的时间。如果只看功能单体架构可能早就做完了但如果从可维护性、扩展性和团队协作的角度看微服务带来的收益是长期的。我个人的建议是如果你也准备做类似的SpringBoot Vue SpringCloud项目一定要想清楚两个问题第一你的业务复杂度是否真的需要微服务如果只是课堂作业级别的CRUD单体完全够用微服务反而是负担第二如果确实要上微服务先用Docker Compose把Nacos、Redis、MySQL这些基础设施跑通再逐个接入业务服务不要想着一步到位。这套饮食健康管理系统后期我还在继续迭代比如在健康分析里接入了大模型做个性化饮食推荐把消息推送改成基于RabbitMQ的异步通知。架构是底子业务才是灵魂底子打好了后面加功能就真的只剩写代码这一件事了。
返回列表