ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

若依微服务分离版启动全攻略:从环境准备到性能调优

若依微服务分离版启动全攻略:从环境准备到性能调优

1. 从单体到微服务:若依分离版到底拆了什么

第一次接触若依微服务分离版的人,最容易犯的错就是把它当成单体版来用。我见过不少朋友把压缩包解压完,看到一堆模块目录直接懵了——怎么这么多文件夹?到底先启动哪个?为什么启动完了前端还是报404?

先把这件事说清楚:若依微服务分离版不是简单地把单体版拆成前后端两个工程,而是把后端又按业务边界拆成了多个独立的服务进程。单体版里所有功能都跑在一个Java进程里,你启动一个jar包就完事了。微服务版不一样,它至少包含以下几个核心服务:

  • 网关服务:所有外部请求的统一入口,负责路由转发、鉴权过滤、限流熔断。前端发过来的请求先到这里,再由它决定转发给哪个后端服务。
  • 认证服务:专门处理登录、登出、令牌签发与校验。它不负责具体业务,只负责“你是谁”这件事。
  • 系统服务:承载用户管理、角色管理、菜单管理、部门管理等基础功能模块。
  • 业务服务:根据你的项目需要,可能有一个或多个,承载具体的业务逻辑。
  • 注册中心与配置中心:通常用Nacos来充当,所有服务启动后都要到这里报到,同时从它那里拉取配置。

这还没算上Redis、MySQL、RabbitMQ这些中间件。所以整个系统跑起来,你电脑上同时运行的Java进程可能有五六个,再加上数据库和缓存,资源占用比单体版高出一大截。我实测过,如果只给微服务版分配4GB内存,启动三四个服务之后就开始频繁GC,页面响应明显变慢。建议开发机至少16GB内存,给Java进程留出8GB以上的堆空间。

那为什么还要用微服务?答案在于独立部署与弹性伸缩。单体版里改一个用户查询的逻辑,整个应用都得重新打包部署。微服务版里系统服务挂了,网关和认证服务还在,你至少还能登录,只是用户管理页面打不开。业务量大的时候,可以单独给业务服务多开几个实例,其他服务不用动。这种灵活性是单体架构给不了的。

但代价也很明显:启动复杂度直线上升。单体版你只需要保证MySQL和Redis正常,然后java -jar就完事了。微服务版你得先确保Nacos起来了、MySQL初始化脚本执行了、Redis能连上,然后按特定顺序启动各个服务,最后才是前端。任何一个环节出问题,整个系统就跑不起来。

注意:若依微服务版对版本匹配非常敏感。Spring Cloud Alibaba、Spring Boot、Nacos客户端三者之间的版本必须严格对应,否则会出现服务注册不上、配置拉取失败、启动直接报错等各种问题。不要随意升级某个组件的版本,除非你清楚知道兼容性矩阵。

2. 启动前的环境准备:那些文档里不会细说的坑

2.1 Nacos的安装与配置陷阱

Nacos是整个微服务体系的“通讯录”加“配置仓库”,它起不来,后面所有服务都是白搭。官方文档会告诉你下载、解压、执行启动脚本,但有几个细节它不会强调。

第一,Nacos的启动模式。默认情况下Nacos是以集群模式启动的,但开发环境你只需要单机模式。启动命令必须加-m standalone参数,否则它会尝试去找集群配置文件,然后报错退出。Windows下是startup.cmd -m standalone,Linux下是sh startup.sh -m standalone。这个参数不加,你会看到它启动到一半就卡住或者直接闪退。

第二,Nacos的持久化配置。Nacos默认使用内嵌的Derby数据库存储配置信息,这在开发环境够用,但有个致命问题:每次重启Nacos,之前通过控制台添加的配置可能会丢失(取决于版本和配置)。更稳妥的做法是让Nacos使用MySQL作为持久化存储。具体操作是在Nacos的conf目录下找到application.properties文件,把数据库连接相关的配置打开并填上你自己的MySQL地址。然后执行conf目录下的mysql-schema.sql脚本创建必要的表。这样配置数据就持久化了,重启不会丢。

第三,Nacos的内存占用。Nacos默认启动参数给JVM分配的内存不小,如果开发机内存紧张,可以修改启动脚本里的JAVA_OPT参数,把-Xms和-Xmx调小一些,比如都设成512MB。但不要设得太小,否则Nacos自己会因为内存不足而频繁Full GC,导致服务注册和配置拉取超时。

2.2 MySQL与Redis的版本选择

MySQL方面,若依微服务版使用的SQL语法和函数在MySQL 5.7和8.0上都能跑,但要注意驱动包版本。如果你用MySQL 8.0,JDBC连接URL里必须加时区参数serverTimezone=Asia/Shanghai,否则启动时会报时区错误。另外MySQL 8.0默认的认证插件是caching_sha2_password,老版本的JDBC驱动可能不支持,需要把驱动升级到对应版本,或者把用户的认证插件改成mysql_native_password。

Redis方面,若依用到了Redis的发布订阅功能来实现服务间的缓存刷新通知。这意味着Redis不能是单机伪集群模式,必须是真正的单机或者集群。另外Redis的notify-keyspace-events配置项需要开启,否则某些基于键过期的事件监听会失效。在redis.conf里把这一项设成Ex或者KEA,具体取决于你的需求。

还有一个容易被忽略的点:Redis的密码。如果你给Redis设了密码,那么所有服务的配置文件里spring.redis.password都必须填对,包括网关、认证、系统、业务各个服务。漏掉任何一个,那个服务启动时就会报连接拒绝。

2.3 前端环境的Node版本问题

若依微服务版的前端通常基于Vue2或Vue3,对应的Node版本要求不同。Vue2项目用Node 14或16比较稳,Vue3项目建议Node 16以上。如果你本机装了多个Node版本,记得用nvm之类的工具切换。我遇到过用Node 18跑Vue2项目,node-sass编译直接报错的情况,换成Node 16就正常了。

前端依赖安装时,如果npm install卡住不动,大概率是网络问题。可以换成国内镜像源,或者用cnpm、pnpm来装。但要注意,pnpm的严格依赖隔离机制可能导致某些包找不到,如果遇到奇怪的模块缺失错误,换回npm或yarn试试。

3. 启动顺序与各服务的关键配置

3.1 正确的启动顺序

微服务版启动有严格的依赖顺序,搞错了就会看到各种连接超时。我总结的顺序是这样的:

  1. MySQL:先确保数据库跑起来,并且已经执行了若依提供的初始化SQL脚本。
  2. Redis:确保Redis服务正常,密码配置正确。
  3. Nacos:单机模式启动,确认控制台能正常访问。
  4. 在Nacos中导入配置:若依的压缩包里通常有一个nacos配置导出的zip文件,需要在Nacos控制台里导入。这一步很多人会漏掉,结果服务启动时拉不到配置直接报错。
  5. 启动系统服务:它是基础服务,其他服务可能依赖它的接口。
  6. 启动认证服务:处理登录逻辑。
  7. 启动网关服务:所有请求的入口。
  8. 启动业务服务:按需启动。
  9. 启动前端:最后启动,因为前端要调用后端接口。

这个顺序不是绝对的,但系统服务和认证服务最好在网关之前启动,否则网关启动时去拉取路由配置可能会失败。

3.2 各服务配置文件的关键项

每个服务都有自己的bootstrap.yml和application.yml(或者配置都放在Nacos里)。bootstrap.yml里最关键的是Nacos的地址和命名空间。命名空间用来隔离不同环境的配置,开发环境通常用dev或者一个自定义的命名空间ID。如果命名空间填错了,服务会去默认的public命名空间找配置,结果找不到,启动就失败。

application.yml里需要关注的是数据库连接、Redis连接、以及服务端口。微服务版里每个服务的端口都不能冲突,网关通常是8080,认证是9200,系统是9201,以此类推。如果你本机已经装了其他应用占用了这些端口,要么改端口,要么把占用的应用停掉。

还有一个隐藏的坑:服务间的调用地址。微服务之间通过Feign客户端调用,Feign会从Nacos获取目标服务的实例列表。但如果你的Nacos注册的IP地址不对(比如注册成了Docker内部IP或者127.0.0.1),那么服务间调用就会失败。解决办法是在服务的配置里指定spring.cloud.nacos.discovery.ip为你本机的真实局域网IP,或者确保Nacos客户端能正确探测到可用的IP。

3.3 前端代理配置的调整

前端开发时通常用vue.config.js里的devServer.proxy来代理API请求,解决跨域问题。若依微服务版的前端代理目标应该是网关的地址,而不是某个具体服务的地址。比如网关跑在localhost:8080,那么代理配置里target就写http://localhost:8080。所有请求先到网关,再由网关路由到具体服务。

这里有个细节:代理的路径重写规则。如果前端请求的路径是/dev-api/system/user/list,代理时需要把/dev-api前缀去掉,变成/system/user/list再发给网关。若依的前端配置里通常用pathRewrite来实现。如果重写规则写错了,网关收到的路径不对,就会返回404。

4. 常见启动报错与排查思路

4.1 服务注册不上Nacos

这是最常见的问题,表现是服务启动日志里一直刷“nacos registry failed”或者“connect to nacos server failed”。排查步骤:

  • 确认Nacos是否真的启动了,浏览器访问http://localhost:8848/nacos看能不能打开控制台。
  • 确认服务配置里的Nacos地址和端口是否正确,特别是如果你改了Nacos的默认端口。
  • 确认命名空间ID是否填对。命名空间ID是一串UUID,不是命名空间名称,很多人在这里填错。
  • 检查防火墙是否拦截了8848端口。Windows防火墙有时候会静默拦截。
  • 如果Nacos和微服务不在同一台机器上,确认网络是否互通。

4.2 配置拉取失败导致启动中断

服务启动时如果从Nacos拉不到配置,会直接抛异常退出。日志里通常会说“config not found”或者“dataId not exist”。这时候要去Nacos控制台的配置列表里检查:

  • 对应的dataId是否存在。若依的dataId命名规则通常是服务名-环境.yml,比如ruoyi-system-dev.yml。
  • 配置内容是否正确,特别是数据库和Redis的连接信息。
  • 配置的group是否匹配,默认是DEFAULT_GROUP,如果你改了分组,服务配置里也要同步改。

4.3 数据库连接超时或拒绝

如果日志里出现Communications link failure或者Access denied for user,说明数据库连接有问题。检查:

  • MySQL服务是否启动。
  • 数据库地址、端口、用户名、密码是否正确。
  • 数据库用户是否有远程访问权限。如果MySQL和微服务不在同一台机器,需要授权用户从微服务的IP访问。
  • 数据库连接池的配置是否合理。若依默认用Druid,连接池参数可以在配置里调整。

4.4 端口被占用

启动时报Port already in use,说明端口被别的进程占了。用netstat -ano | findstr 端口号(Windows)或lsof -i:端口号(Linux/Mac)找到占用进程,然后决定是杀掉它还是改微服务的端口。

4.5 前端启动后接口404

前端页面能打开,但所有接口请求都返回404。这通常是代理配置问题:

  • 检查vue.config.js里的proxy配置,确认target指向的是网关地址。
  • 检查pathRewrite是否正确去掉了前缀。
  • 确认网关是否正常启动,并且路由配置正确。
  • 打开浏览器开发者工具的Network面板,看请求的实际URL是什么,和预期的是否一致。

5. 性能调优与开发效率提升

5.1 JVM参数调整

微服务版每个服务都是一个独立的JVM进程,默认的堆内存可能不够用。可以在启动命令里加上-Xms512m -Xmx1024m来调整。如果开发机内存充足,可以给系统服务和业务服务多分配一些。但要注意,所有服务的堆内存总和不能超过物理内存,否则会频繁使用交换分区,反而更慢。

5.2 关闭不必要的服务

开发阶段如果只关注某个业务模块,可以只启动必要的服务。比如只调前端页面样式,可以只启动网关和系统服务,认证服务用Mock数据代替。这样能省下不少内存和启动时间。

5.3 使用Nacos的配置热更新

若依微服务版支持配置热更新。在Nacos控制台修改配置后,服务不需要重启就能生效。但要注意,不是所有配置都支持热更新。数据库连接池、Redis连接这些通常在启动时初始化,修改后需要重启服务。而一些业务开关、限流阈值之类的配置可以热更新。具体哪些支持,要看代码里有没有加@RefreshScope注解。

5.4 日志级别的调整

开发阶段可以把日志级别调成DEBUG,方便排查问题。但DEBUG级别会产生大量日志,影响性能。生产环境一定要调回INFO或WARN。若依的日志配置通常在Nacos的配置里,修改logging.level相关的项即可。

6. 一些零散但重要的经验

关于Nacos的命名空间:建议为每个开发者分配一个独立的命名空间,这样大家的配置互不干扰。但注册服务时要注意,不同命名空间的服务默认不能互相发现。如果团队协作,需要统一命名空间。

关于前端打包:开发完成后打包前端,要把代理配置去掉,改成直接请求后端网关地址。打包命令通常是npm run build:prod,具体看package.json里的脚本定义。

关于数据库脚本:若依的SQL脚本可能包含一些初始化数据,比如默认用户、菜单、角色。执行脚本时注意字符集,建议用utf8mb4,否则中文可能乱码。

关于版本升级:若依社区版会不定期更新,升级时不要直接覆盖配置文件,因为你的配置可能已经改过了。正确的做法是对比新旧版本的配置文件,把差异合并进去。

关于Docker部署:如果要用Docker跑微服务版,建议用docker-compose来编排,把MySQL、Redis、Nacos和各个微服务都定义在一个compose文件里。这样启动和停止都方便。但要注意容器间的网络配置,Nacos注册的IP要能被其他容器访问到。

关于IDE的Run Dashboard:如果用IntelliJ IDEA开发,可以把所有微服务的启动配置加到一个Run Dashboard里,一键启动所有服务。但要注意启动顺序,IDEA的Run Dashboard默认是并行启动的,可能导致依赖问题。可以配置成顺序启动,或者手动控制。

关于内存溢出:微服务版跑久了可能会遇到OutOfMemoryError,特别是系统服务和业务服务。除了调整堆内存,还要检查是否有内存泄漏。可以用JProfiler或者VisualVM来监控。常见的内存泄漏原因包括:Feign客户端没有正确关闭、线程池没有回收、缓存没有设置过期时间等。

关于跨域问题:微服务版里跨域通常在网关层处理,而不是在每个服务里处理。网关的跨域配置要允许前端开发服务器的地址,并且要处理OPTIONS预检请求。如果跨域配置不对,前端会报CORS policy错误。

关于令牌传递:认证服务签发的令牌需要在网关层校验,然后传递给下游服务。下游服务从请求头里获取用户信息。如果令牌传递链路断了,下游服务就获取不到当前用户,导致权限判断失败。排查时可以在网关的日志里看令牌是否被正确解析和转发。

关于服务降级:微服务版通常集成了Sentinel来做限流降级。开发阶段可以先把Sentinel的控制台地址配上,方便观察流量情况。但Sentinel的控制台本身也是一个服务,需要额外启动。

关于配置加密:如果配置里有敏感信息,比如数据库密码,可以用Nacos的加密功能或者Jasypt来加密。但加密后要确保服务能正确解密,否则启动会失败。

关于健康检查:每个微服务都暴露了健康检查端点,通常是/actuator/health。网关可以配置健康检查来剔除不健康的实例。开发阶段如果某个服务挂了,网关可能还会继续转发请求过去,导致前端报错。可以配置网关的重试机制,但要注意重试次数不要太多,否则会放大故障。

关于日志聚合:微服务版日志分散在各个服务里,排查问题很不方便。可以用ELK或者类似的日志聚合方案,把所有服务的日志收集到一个地方统一查看。但ELK本身也需要不少资源,开发机可能跑不动。折中方案是把日志输出到同一个文件,或者用tail -f同时监控多个日志文件。

关于接口文档:若依微服务版通常集成了Swagger或者Knife4j来生成接口文档。但微服务版里每个服务都有自己的文档地址,比较分散。可以在网关层做聚合,把所有服务的文档聚合到一个页面里。这样前端开发人员只需要看一个地址就够了。

关于数据库连接池监控:Druid提供了监控页面,可以看到SQL执行情况、连接池状态等。开发阶段可以打开这个页面,方便排查慢SQL。但生产环境要记得关闭或者加访问控制,否则有安全风险。

关于Nacos的持久化:前面提到Nacos可以用MySQL持久化。但要注意,Nacos的MySQL和业务数据库最好分开,不要用同一个库。因为Nacos的读写频率可能比较高,和业务库混在一起会影响性能。

关于服务间的超时设置:Feign客户端默认的超时时间可能比较短,如果某个服务响应慢,就会报超时错误。可以在配置里调整feign.client.config.default.connectTimeout和readTimeout。但超时时间也不要设得太长,否则故障时会拖垮调用方。

关于重试机制:Feign支持重试,但默认是关闭的。如果开启重试,要注意幂等性问题。非幂等的接口重试可能导致数据重复。建议只对查询类接口开启重试。

关于线程池隔离:如果用了Hystrix或者Sentinel做熔断,要注意线程池隔离策略。默认情况下,每个依赖服务会用一个独立的线程池,如果线程池满了,请求会被拒绝。开发阶段可以先把熔断关掉,避免调试时被熔断干扰。

关于配置的优先级:Nacos的配置、本地application.yml、命令行参数,这三者的优先级要搞清楚。通常命令行参数优先级最高,其次是Nacos配置,最后是本地配置。如果发现配置没生效,先检查是不是被更高优先级的配置覆盖了。

关于服务下线:停止服务时,最好先通过Nacos控制台把服务下线,等一会儿再停进程。这样网关能及时感知到服务不可用,把请求转发到其他实例。直接杀进程可能导致网关还在往已经挂掉的实例转发请求,造成短暂的请求失败。

关于时区问题:如果服务器时区和数据库时区不一致,可能会出现时间相差8小时的问题。建议统一用Asia/Shanghai时区,并且在JDBC连接URL里明确指定时区。

关于字符编码:前端、后端、数据库的字符编码要统一成UTF-8。否则中文可能出现乱码。特别是数据库连接URL里要加useUnicode=true&characterEncoding=utf8。

关于静态资源:微服务版里静态资源通常由前端服务器(Nginx)处理,不经过网关。如果静态资源访问404,检查Nginx的配置是否正确指向了前端打包后的dist目录。

关于HTTPS:开发阶段用HTTP就够了,生产环境建议上HTTPS。HTTPS通常在Nginx层配置,网关和后端服务继续用HTTP。这样证书只需要在Nginx上配一次。

关于备份:Nacos的配置、数据库的数据、Redis的持久化文件,这些都要定期备份。特别是Nacos的配置,一旦丢失,恢复起来很麻烦。

关于文档:团队协作时,建议把启动步骤、常见问题、配置说明整理成文档,放在项目仓库里。这样新成员加入时能快速上手,不用每次都问老人。

关于版本控制:Nacos的配置也可以纳入版本控制。可以把配置导出成文件,提交到Git仓库。修改配置时先改文件,再导入Nacos。这样配置的变更历史就清晰了。

关于环境隔离:开发、测试、生产环境要用不同的Nacos命名空间和不同的数据库。不要混用,否则容易出事故。

关于监控:微服务版建议集成Spring Boot Admin或者Prometheus来监控服务状态。但监控系统本身也需要资源,开发阶段可以先用Nacos控制台看服务列表,简单判断服务是否在线。

关于日志级别动态调整:Spring Boot Actuator提供了动态调整日志级别的端点。可以在不重启服务的情况下临时把某个包的日志级别调成DEBUG,排查完再调回去。这个功能在排查线上问题时特别有用。

关于线程堆栈分析:如果服务卡死,可以用jstack命令导出线程堆栈,看看是不是有死锁或者线程阻塞。微服务版里线程比较多,分析起来要有耐心。

关于内存分析:如果怀疑内存泄漏,可以用jmap导出堆转储文件,然后用MAT或者VisualVM分析。重点看哪些对象占用了大量内存,以及它们的引用链。

关于网络抓包:如果怀疑服务间通信有问题,可以用Wireshark或者tcpdump抓包分析。但微服务版通信比较多,抓包文件会很大,建议先过滤特定端口或IP。

关于配置中心的高可用:生产环境的Nacos必须做集群,否则Nacos挂了整个系统就瘫痪了。开发环境单机就够了,但要知道生产环境需要集群部署。

关于服务网格:如果微服务数量很多,可以考虑引入Service Mesh来管理服务间通信。但那是另一个层面的复杂度了,开发阶段用不上。

关于API网关的选择:若依默认用Spring Cloud Gateway,也支持其他网关。如果团队对Nginx比较熟,也可以用Nginx做网关。但Spring Cloud Gateway和Spring Cloud生态集成更好,推荐用默认的。

关于注册中心的选择:若依默认用Nacos,也支持Eureka、Consul等。Nacos同时提供了注册中心和配置中心的功能,比较方便。如果只用注册中心,Eureka更轻量。但Nacos的配置中心功能确实好用,建议用Nacos。

关于配置的灰度发布:Nacos支持配置的灰度发布,可以先把新配置推给一部分实例,观察没问题再全量推。这个功能在修改关键配置时很有用。

关于服务的优雅停机:Spring Boot支持优雅停机,可以在配置里开启。这样停止服务时,会先拒绝新请求,等正在处理的请求完成后再退出。避免直接杀进程导致请求失败。

关于健康检查的细节:健康检查端点可以自定义,比如检查数据库连接、Redis连接是否正常。如果某个依赖挂了,健康检查返回不健康,网关就会把该实例剔除。

关于请求链路追踪:微服务版建议集成Sleuth或者SkyWalking来做链路追踪。这样排查问题时能看到一个请求经过了哪些服务,每个服务耗时多少。但链路追踪系统本身也需要部署和维护。

关于分布式事务:如果业务涉及多个服务的数据修改,要考虑分布式事务。若依本身没有集成分布式事务解决方案,需要自己引入Seata等框架。但分布式事务会带来额外的复杂度,能不用尽量不用。

关于缓存一致性:微服务版里多个服务可能共享同一个Redis缓存。修改数据时要注意缓存的一致性。若依提供了一些缓存刷新的机制,但需要正确配置。

关于接口幂等性:微服务版里接口可能被重试或者重复调用,要考虑幂等性。可以用令牌、唯一ID等方式来保证。

关于限流:网关层可以做限流,保护后端服务。Sentinel或者Redis+Lua都可以实现。开发阶段可以先不开启,但要知道生产环境需要。

关于熔断:如果某个服务频繁失败,熔断器会打开,后续请求直接返回失败,不再调用该服务。这样可以防止故障扩散。但熔断器的阈值要合理设置,否则可能误熔断。

关于降级:熔断后可以走降级逻辑,返回一个默认值或者缓存数据。降级逻辑要提前设计好,不能临时抱佛脚。

关于线程池的监控:如果用了线程池,要监控线程池的活跃线程数、队列大小等指标。线程池满了会导致请求被拒绝。

关于数据库连接池的监控:Druid提供了详细的监控指标,要定期查看。连接池满了会导致获取连接超时。

关于慢SQL:慢SQL会拖垮数据库,进而影响整个系统。要开启慢SQL日志,定期分析优化。

关于索引:数据库表要有合适的索引,否则查询会全表扫描。但索引也不是越多越好,会影响写入性能。

关于分库分表:如果数据量很大,要考虑分库分表。但那是架构层面的决策,开发阶段一般用不上。

关于读写分离:如果读多写少,可以考虑读写分离。但会带来主从延迟的问题,需要业务上能容忍。

关于缓存穿透:查询一个不存在的数据,缓存和数据库都没有,导致每次请求都打到数据库。可以用布隆过滤器或者缓存空值来解决。

关于缓存雪崩:大量缓存同时过期,导致请求全部打到数据库。可以给缓存过期时间加随机值来避免。

关于缓存击穿:热点key过期瞬间,大量请求打到数据库。可以用互斥锁或者永不过期来解决。

关于热key:某个key访问量特别大,可能导致Redis单节点压力过大。可以用本地缓存或者key拆分来缓解。

关于大key:某个key的value特别大,可能导致Redis阻塞。要避免存储过大的value,可以拆分。

关于Redis持久化:Redis的RDB和AOF各有优缺点。开发阶段可以只用RDB,生产环境建议RDB+AOF。

关于Redis集群:如果数据量大或者并发高,要考虑Redis集群。但集群会带来一些限制,比如不支持多key操作。

关于消息队列:如果服务间需要异步通信,可以引入消息队列。若依默认用RabbitMQ,也支持Kafka、RocketMQ等。

关于消息丢失:消息队列要保证消息不丢失,需要生产者确认、持久化、消费者手动确认等机制。

关于消息重复:消息可能重复投递,消费者要保证幂等性。

关于消息顺序:如果需要保证消息顺序,要用单分区或者单消费者。

关于定时任务:微服务版里定时任务要避免多个实例同时执行。可以用分布式锁或者把定时任务单独部署。

关于分布式锁:微服务版里多个实例可能同时操作同一资源,需要分布式锁。可以用Redis或者Zookeeper实现。

关于分布式ID:微服务版里需要全局唯一的ID,可以用雪花算法或者数据库自增。

关于文件存储:微服务版里文件上传可能涉及多个服务,要考虑文件存储的方案。可以用本地存储、FastDFS、MinIO等。

关于跨服务查询:微服务版里一个页面可能需要多个服务的数据,可以用API组合或者GraphQL。但会增加复杂度。

关于服务编排:如果业务流程涉及多个服务,要考虑服务编排。可以用状态机或者工作流引擎。

关于服务版本管理:微服务版里服务可能有多个版本,要考虑版本兼容性。可以用灰度发布或者版本路由。

关于服务依赖:微服务之间可能有循环依赖,要尽量避免。如果无法避免,要考虑重构。

关于服务粒度:微服务的粒度要合适,太细会导致服务太多,太粗又失去了微服务的优势。要根据业务边界来划分。

关于团队协作:微服务版需要团队协作,每个人负责不同的服务。要制定好接口规范、代码规范、部署规范。

关于文档:每个服务都要有文档,说明接口、配置、依赖等。文档要随代码更新。

关于测试:微服务版测试比单体版复杂,需要集成测试、契约测试等。要保证每个服务都能独立测试。

关于部署:微服务版部署比单体版复杂,需要CI/CD流水线。可以用Jenkins、GitLab CI等。

关于回滚:微服务版回滚要考虑版本兼容性。如果新版本改了接口,回滚可能导致旧版本调用失败。

关于监控告警:微服务版需要完善的监控告警,及时发现故障。可以用Prometheus+Grafana+Alertmanager。

关于日志:微服务版日志分散,需要集中管理。可以用ELK或者Loki。

关于链路追踪:微服务版需要链路追踪,定位性能瓶颈。可以用SkyWalking或者Zipkin。

关于安全:微服务版的安全要考虑认证、授权、加密、防重放等。网关层可以做统一的安全过滤。

关于限流:网关层可以做限流,保护后端服务。可以用令牌桶或者漏桶算法。

关于熔断:如果某个服务频繁失败,熔断器会打开,后续请求直接返回失败,不再调用该服务。这样可以防止故障扩散。

关于降级:熔断后可以走降级逻辑,返回一个默认值或者缓存数据。降级逻辑要提前设计好,不能临时抱佛脚。

关于线程池的监控:如果用了线程池,要监控线程池的活跃线程数、队列大小等指标。线程池满了会导致请求被拒绝。

关于数据库连接池的监控:Druid提供了详细的监控指标,要定期查看。连接池满了会导致获取连接超时。

关于慢SQL:慢SQL会拖垮数据库,进而影响整个系统。要开启慢SQL日志,定期分析优化。

关于索引:数据库表要有合适的索引,否则查询会全表扫描。但索引也不是越多越好,会影响写入性能。

关于分库分表:如果数据量很大,要考虑分库分表。但那是架构层面的决策,开发阶段一般用不上。

关于读写分离:如果读多写少,可以考虑读写分离。但会带来主从延迟的问题,需要业务上能容忍。

关于缓存穿透:查询一个不存在的数据,缓存和数据库都没有,导致每次请求都打到数据库。可以用布隆过滤器或者缓存空值来解决。

关于缓存雪崩:大量缓存同时过期,导致请求全部打到数据库。可以给缓存过期时间加随机值来避免。

关于缓存击穿:热点key过期瞬间,大量请求打到数据库。可以用互斥锁或者永不过期来解决。

关于热key:某个key访问量特别大,可能导致Redis单节点压力过大。可以用本地缓存或者key拆分来缓解。

关于大key:某个key的value特别大,可能导致Redis阻塞。要避免存储过大的value,可以拆分。

关于Redis持久化:Redis的RDB和AOF各有优缺点。开发阶段可以只用RDB,生产环境建议RDB+AOF。

关于Redis集群:如果数据量大或者并发高,要考虑Redis集群。但集群会带来一些限制,比如不支持多key操作。

关于消息队列:如果服务间需要异步通信,可以引入消息队列。若依默认用RabbitMQ,也支持Kafka、RocketMQ等。

关于消息丢失:消息队列要保证消息不丢失,需要生产者确认、持久化、消费者手动确认等机制。

关于消息重复:消息可能重复投递,消费者要保证幂等性。

关于消息顺序:如果需要保证消息顺序,要用单分区或者单消费者。

关于定时任务:微服务版里定时任务要避免多个实例同时执行。可以用分布式锁或者把定时任务单独部署。

关于分布式锁:微服务版里多个实例可能同时操作同一资源,需要分布式锁。可以用Redis或者Zookeeper实现。

关于分布式ID:微服务版里需要全局唯一的ID,可以用雪花算法或者数据库自增。

关于文件存储:微服务版里文件上传可能涉及多个服务,要考虑文件存储的方案。可以用本地存储、FastDFS、MinIO等。

关于跨服务查询:微服务版里一个页面可能需要多个服务的数据,可以用API组合或者GraphQL。但会增加复杂度。

关于服务编排:如果业务流程涉及多个服务,要考虑服务编排。可以用状态机或者工作流引擎。

关于服务版本管理:微服务版里服务可能有多个版本,要考虑版本兼容性。可以用灰度发布或者版本路由。

关于服务依赖:微服务之间可能有循环依赖,要尽量避免。如果无法避免,要考虑重构。

关于服务粒度:微服务的粒度要合适,太细会导致服务太多,太粗又失去了微服务的优势。要根据业务边界来划分。

关于团队协作:微服务版需要团队协作,每个人负责不同的服务。要制定好接口规范、代码规范、部署规范。

关于文档:每个服务都要有文档,说明接口、配置、依赖等。文档要随代码更新。

关于测试:微服务版测试比单体版复杂,需要集成测试、契约测试等。要保证每个服务都能独立测试。

关于部署:微服务版部署比单体版复杂,需要CI/CD流水线。可以用Jenkins、GitLab CI等。

关于回滚:微服务版回滚要考虑版本兼容性。如果新版本改了接口,回滚可能导致旧版本调用失败。

关于监控告警:微服务版需要完善的监控告警,及时发现故障。可以用Prometheus+Grafana+Alertmanager。

关于日志:微服务版日志分散,需要集中管理。可以用ELK或者Loki。

关于链路追踪:微服务版需要链路追踪,定位性能瓶颈。可以用SkyWalking或者Zipkin。

关于安全:微服务版的安全要考虑认证、授权、加密、防重放等。网关层可以做统一的安全过滤。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进