VortMall 微服务故障排查手册

VortMall 微服务故障排查手册

适用范围:VortMall-Api 全部 15 个业务微服务、网关、认证服务及公共组件。
技术栈:Java 21 / Spring Boot 4.0 / Spring Cloud 2025.1 / Spring Cloud Alibaba 2025.1 / MyBatis-Plus 3.5 / RocketMQ / Nacos / Seata / Redis / Elasticsearch / XXL-JOB


目录


一、服务启动失败

1.1 端口占用

现象:启动报 Address already in use: bind

排查

# Windows
netstat -ano | findstr :<端口号>
taskkill /PID <进程ID> /F

# Linux
lsof -i :<端口号>
kill -9 <PID>

各服务默认端口对照

服务端口
vortmall-gateway8000
vortmall-auth8001
vortmall-biz-product19901
vortmall-biz-payment19902
vortmall-biz-system19903
vortmall-biz-marketing19904
vortmall-biz-order19905
vortmall-biz-content19906
vortmall-biz-organize19907
vortmall-biz-logistics19908
vortmall-biz-aftersales19909
vortmall-biz-distribution19910
vortmall-biz-decoration19911
vortmall-biz-message19912
vortmall-biz-user19913
vortmall-biz-file19914
vortmall-biz-pos19915

1.2 Bean 创建失败

现象BeanCreationExceptionUnsatisfiedDependencyException

常见原因与解决

原因解决方案
缺少依赖包检查 pom.xml 是否引入对应 starter,执行 mvn dependency:tree 排查冲突
@Mapper 未扫描到确认 Mapper 接口在 com.vortmall.*.infrastructure 包下,或检查 @MapperScan 配置
条件装配不满足检查 @ConditionalOnProperty 对应的配置项(如 vortmall.outbox.enabled)是否设置
循环依赖Spring Boot 4.x 默认禁止循环依赖,使用 @Lazy 或重构解耦

1.3 配置文件加载失败

现象ConfigDataLocationNotFoundExceptionCould not resolve placeholder

排查步骤

  1. 确认 bootstrap.ymlspring.config.import 路径正确:
spring:
  config:
    import:
      - classpath:config.yml      # Nacos 公共配置(必须)
      - classpath:datasource.yml  # 数据源
      - classpath:cache.yml       # Redis 缓存
      - classpath:mq.yml          # RocketMQ(按需)
      - classpath:seata.yml       # Seata(按需)
      - classpath:job.yml         # XXL-JOB(按需)
  1. 确认 env.ymlvortmall.host 地址可达
  2. 检查 Nacos 配置中心中对应的 dataId 是否存在,namespace 是否与部署环境一致

1.4 Java 版本不匹配

现象UnsupportedClassVersionError--enable-preview 相关报错

解决:项目要求 Java 21,确认 JAVA_HOME 指向 JDK 21,且 IDE 编译级别设置为 21。


二、Nacos 注册与配置异常

2.1 服务注册失败

现象NacosException: failed to req API、服务列表中看不到实例

排查

  1. 确认 Nacos Server 已启动:curl http://<vortmall.host>:8848/nacos/
  2. 检查 config.yml 中配置:
    • server-addr 地址与实际 Nacos 服务地址一致
    • namespace 与 Nacos 控制台中使用的命名空间一致
  3. 检查网络连通性(防火墙、VPN)
  4. 确认服务没有被 spring.cloud.nacos.discovery.enabled: false 禁用

2.2 配置拉取失败

现象:启动时配置值为空或使用了默认值

排查

  1. 登录 Nacos 控制台 → 配置管理 → 确认当前命名空间正确
  2. 检查 dataIdgroup 是否匹配
  3. 共享配置(如 datasource-multiple.yml)是否已创建
  4. 检查 Nacos 客户端日志:logs/nacos/config.log

2.3 配置热更新不生效

现象:修改了 Nacos 配置但服务未感知

排查

  1. 确认使用了 @RefreshScope@ConfigurationProperties
  2. 检查是否是在 static 或构造函数中读取的配置(不支持动态刷新)
  3. 确认 Nacos 配置发布后 MD5 已变更

三、数据库连接异常

3.1 连接池初始化失败

现象DruidDataSource init errorCommunications link failure

排查

  1. 确认 MySQL 服务已启动且端口可达(默认 3306)
  2. 检查数据源配置(datasource.yml 或 Nacos 中的配置):
    • url 格式:jdbc:mysql://<host>:3306/<db-name>?...
    • 用户名/密码正确
  3. 检查数据库是否存在(各服务对应的库名见下表)

各服务数据库名对照

服务数据库名
vortmall-biz-productvortmall-product
vortmall-biz-ordervortmall-order
vortmall-biz-uservortmall-user
vortmall-biz-paymentvortmall-payment
vortmall-biz-systemvortmall-system
vortmall-biz-marketingvortmall-marketing
vortmall-biz-contentvortmall-content
vortmall-biz-messagevortmall-message
vortmall-biz-aftersalesvortmall-aftersales
vortmall-biz-decorationvortmall-decoration
vortmall-biz-distributionvortmall-distribution
vortmall-biz-organizevortmall-organize
vortmall-biz-logisticsvortmall-logistics
vortmall-biz-filevortmall-file
vortmall-biz-posvortmall-pos

3.2 连接池耗尽

现象GetConnectionTimeoutExceptionCannot get a connection, pool error Timeout waiting for idle object

排查

  1. 检查 Druid 监控(如已开启):/druid/datasource.html
  2. 排查慢 SQL:开启 Druid 的 stat 过滤器
  3. 排查连接泄漏:检查是否有未关闭的手动 Connection
  4. 临时方案:增大 maxActive(默认 20),但需同步排查根因
spring:
  datasource:
    druid:
      max-active: 50
      max-wait: 60000

3.3 慢 SQL 导致超时

现象:接口响应慢、QueryTimeoutException

排查

  1. 开启 MyBatis-Plus SQL 日志:
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  1. 检查是否缺少索引:EXPLAIN SELECT ...
  2. 检查是否存在全表扫描、N+1 查询
  3. 使用 Druid 的 wallstat 过滤器监控

3.4 MyBatis-Plus 常见问题

问题解决方案
Invalid bound statement检查 XML 文件路径与 Mapper 接口包路径一致,确认 mapper-locations 配置
Table 'xxx' doesn't exist检查实体类 @TableName 注解与实际表名是否一致
字段映射异常检查 @TableField 注解、驼峰转换配置 map-underscore-to-camel-case

四、Redis 缓存异常

4.1 连接失败

现象RedisConnectionFailureExceptionUnable to connect to Redis

排查

  1. 确认 Redis 已启动:redis-cli -h <host> -p 6379 ping
  2. 检查 cache.yml 中的连接配置
  3. 检查密码是否正确
  4. 检查 Redis 最大连接数:redis-cli info clients

4.2 缓存穿透 / 击穿 / 雪崩

问题现象解决
缓存穿透大量查询不存在的数据,请求打到数据库缓存空值、布隆过滤器
缓存击穿热点 key 过期瞬间大量请求涌入使用 vortmall-common-lock 分布式锁保护加载逻辑
缓存雪崩大量 key 同时过期TTL 添加随机偏移量

4.3 Redisson 分布式锁问题

现象vortmall-common-lock 获取锁超时或死锁

排查

  1. 检查 Redis 连接是否正常
  2. 检查锁的 leaseTime 是否过短(业务未执行完锁已释放)
  3. 检查是否有异常导致锁未正确释放
  4. 通过 redis-cli 查看锁 key 状态:GET <lock-key>

4.4 Sa-Token 会话 Redis 异常

现象:登录后立即失效、NotLoginException

排查

  1. 确认网关和业务服务使用的 Redis 是同一实例
  2. 检查 sa-token.token-name 配置一致性
  3. 检查 Redis key 前缀是否冲突

五、消息队列(RocketMQ)异常

5.1 Producer 发送失败

现象RemotingTooMuchRequestExceptionMQBrokerException: No route info of this topic

排查

  1. 确认 RocketMQ NameServer 已启动:${vortmall.host}:9876
  2. 确认 Broker 已注册到 NameServer
  3. 检查 Topic 是否已创建(生产环境建议关闭自动创建):
# 查看 Topic 列表
mqadmin topicList -n <nameserver>:9876
# 创建 Topic
mqadmin updateTopic -n <nameserver>:9876 -b <broker>:10911 -t <TOPIC_NAME>
  1. 检查 mq.ymlname-server 地址是否正确

5.2 Consumer 消费失败

现象:消息重复消费、消费延迟

排查

  1. 检查消费者 Consumer<T> Function Bean 是否正确注册
  2. 检查 group 配置(同一 group 下的实例会负载均衡)
  3. 检查消费逻辑是否抛出异常导致重试:
    • RocketMQ 默认重试 16 次
    • 确保消费逻辑幂等(利用 MessageBody.identifier
  4. 查看消费积压:
mqadmin consumerProgress -n <nameserver>:9876 -g <消费者组>

5.3 消息积压

现象:消费者消费速度跟不上生产者

排查与处理

  1. 确认积压量:通过 RocketMQ Dashboard 或命令查看各 Queue 的消费偏移量
  2. 扩容消费者:增加消费者实例数(不能超过 Queue 数量)
  3. 排查消费瓶颈
    • 单条消息处理耗时过长 → 优化业务逻辑或异步化
    • 数据库/外部 API 慢 → 排查下游瓶颈
    • 消费异常重试 → 检查错误日志
  4. 临时方案:调整消费线程数
spring:
  cloud:
    stream:
      rocketmq:
        bindings:
          <binding-name>:
            consumer:
              maxConcurrency: 20

六、Outbox 可靠消息发送异常

6.1 消息滞留在 Outbox 表中

现象outbox_message 表中大量 PENDING 状态记录

排查

  1. 检查 XXL-JOB 中对应的 Outbox 扫描任务是否在运行
  2. 检查 AbstractOutBoxJobHandler 的日志输出
  3. 确认 StreamProducervortmall-common-mq)可用
  4. 检查 vortmall.outbox.enabled 是否为 true

6.2 Outbox 消息发送后状态异常

现象:消息已发到 MQ 但 Outbox 表状态仍为 PENDING

排查

  1. 检查 OutBoxServiceImpl.processAndSend 的事务提交是否正常
  2. 检查数据库连接是否在发送 MQ 后断开
  3. 查看 maxRetry 配置(vortmall.outbox.defaultMaxRetry

6.3 Outbox 表数据清理

正常情况下,成功发送的 Outbox 记录会被定时清理(retentionDays 控制保留天数)。如果表数据膨胀:

  1. 确认清理任务在 XXL-JOB 中已配置并正常运行
  2. 手动清理:
DELETE FROM outbox_message
WHERE status = 'SUCCESS'
  AND update_time < DATE_SUB(NOW(), INTERVAL 7 DAY);

七、网关路由异常

7.1 503 Service Unavailable

现象:网关返回 503,LoadBalancerNotFoundException

排查

  1. 确认目标服务已注册到 Nacos(Nacos 控制台 → 服务列表)
  2. 确认网关 application.yml 中路由配置的 uri 与服务注册名一致:lb://vortmall-biz-product
  3. 检查网关和业务服务是否注册在同一 Nacos 命名空间中

7.2 CORS 跨域问题

现象:前端报 Access-Control-Allow-Origin 错误

排查

  1. 检查网关 CorsConfig 配置
  2. 确认没有重复设置 CORS 头(网关已配 DedupeResponseHeader 过滤器)
  3. 如果业务服务也设置了 CORS,会导致响应头重复 → 业务服务不应单独配置 CORS

7.3 请求超时

现象:网关返回 504 Gateway Timeout

排查

  1. 确认下游服务响应时间
  2. 调整网关超时配置:
spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 10000
        response-timeout: 30s

7.4 请求体过大

现象:上传文件时报 DataBufferLimitException: Exceeded limit on max bytes to buffer

解决:网关已配置 max-in-memory-size: 20MB,如需更大:

spring:
  codec:
    max-in-memory-size: 50MB

八、Feign 服务间调用异常

8.1 调用超时

现象ReadTimeoutExceptionfeign.RetryableException

排查

  1. 确认被调用服务是否健康
  2. 调整 Feign 超时配置:
spring:
  cloud:
    openfeign:
      client:
        config:
          default:
            connectTimeout: 10000
            readTimeout: 30000

8.2 Fallback 未触发

现象:Feign 调用失败直接抛异常,未执行 Fallback

排查

  1. 确认 spring.cloud.openfeign.circuitbreaker.enabled: true
  2. 确认 Resilience4j 相关依赖已引入(spring-cloud-starter-circuitbreaker-resilience4j
  3. 确认 FeignClient 正确设置了 fallbackfallbackFactory

8.3 服务发现找不到实例

现象Load balancer does not contain an instance for the service

排查

  1. 确认被调用服务的 spring.application.name 与 FeignClient 中 name / value 一致
  2. 确认调用方和被调用方注册在同一 Nacos 命名空间和 group 下
  3. 确认被调用服务实例健康(Nacos → 服务详情 → 查看实例状态)

8.4 序列化/反序列化异常

现象HttpMessageConversionException、字段丢失

排查

  1. 确认请求和响应 DTO 字段一致(注意 Feign 模块中定义的 DTO 与业务模块中可能不同步)
  2. 本项目使用 fastjson2,检查是否有 Jackson 注解混用导致的行为差异
  3. 日期格式、枚举序列化方式是否一致

九、Seata 分布式事务异常

9.1 Seata Server 连接失败

现象RegistryExceptioncan not connect to seata-server

排查

  1. 确认 Seata Server 已启动
  2. 检查 seata.yml 配置:
    • registry.type: nacos
    • Nacos 地址:${vortmall.host}:8848
    • namespace:seata_server
  3. 在 Nacos 控制台确认 Seata Server 已注册(切换到 seata_server namespace)

9.2 全局事务回滚失败

现象:部分分支事务未回滚、数据不一致

排查

  1. 检查 Seata Server 日志
  2. 确认 undo_log 表存在于各业务数据库中
  3. 确认 enable-auto-data-source-proxy: true 生效
  4. 排查分支事务是否有修改了全局锁范围外的数据

9.3 事务超时

现象GlobalTransactionException: Could not found global transaction

排查

  1. 排查事务执行时间是否过长
  2. 调整 Seata 超时配置
  3. 考虑将长耗时操作拆出事务(如发送 MQ、调用外部 API)

9.4 使用注意

  • @GlobalTransactional 标注在 Application Service 层
  • 避免在事务中做耗时 I/O(HTTP 调用、文件上传)
  • tx-service-group 必须各服务一致(当前统一为 default_tx_group

十、XXL-JOB 定时任务异常

10.1 执行器注册失败

现象:XXL-JOB Admin 中看不到执行器

排查

  1. 确认 XXL-JOB Admin 已启动:http://<vortmall.host>:8082/xxl-job-admin
  2. 检查 job.yml 配置:
    • adminAddresses 地址正确
    • accessToken 与 Admin 端一致
    • appName 格式:${spring.application.name}-executor
  3. 检查执行器端口(默认随机 9900-9999)是否被占用或被防火墙拦截

10.2 任务执行失败

现象:XXL-JOB Admin 中任务状态为失败

排查

  1. 在 Admin 中查看任务执行日志(调度日志 → 执行日志)
  2. 检查服务端日志(logs/xxl-job/jobhandler/ 目录)
  3. 确认 @XxlJob("handlerName") 中的名称与 Admin 端任务配置一致

十一、Elasticsearch 搜索异常

11.1 连接失败

现象ElasticsearchExceptionConnection refused

排查

  1. 确认 ES 集群已启动(默认端口 9200)
  2. 检查 es.yml 中的连接配置
  3. 确认 ES 版本兼容性(项目使用 8.17.2 客户端)

11.2 索引不存在

现象index_not_found_exception

排查

  1. 确认索引是否已创建:curl <es-host>:9200/_cat/indices?v
  2. 检查索引名是否与业务代码中定义的一致
  3. 手动创建索引或等待数据同步任务创建

11.3 数据同步延迟

现象:数据库已更新但搜索结果未变

排查

  1. 检查 Canal binlog 消费是否正常(vortmall-biz-product 使用 Stream 消费 Canal 事件)
  2. ES 默认 refresh 间隔 1s,可手动刷新:POST /<index>/_refresh
  3. 排查同步消费者日志

11.4 通过 Elasticsearch 查看系统日志

系统运行日志通过 Logstash 采集后写入 Elasticsearch,可通过以下方式查看和检索。

查看集群健康状态

curl <es-host>:9200/_cluster/health?pretty

查看所有日志索引

curl <es-host>:9200/_cat/indices?v&s=index

日志索引通常按日期命名,格式如 vortmall-log-YYYY.MM.DD

按关键字搜索日志

# 搜索包含 "Exception" 的日志(最近 100 条)
curl -X GET "<es-host>:9200/vortmall-log-*/_search?pretty" \
  -H "Content-Type: application/json" \
  -d '{
    "size": 100,
    "sort": [{"@timestamp": "desc"}],
    "query": {
      "match": {
        "message": "Exception"
      }
    }
  }'

按服务名过滤日志

# 查看指定服务的错误日志
curl -X GET "<es-host>:9200/vortmall-log-*/_search?pretty" \
  -H "Content-Type: application/json" \
  -d '{
    "size": 50,
    "sort": [{"@timestamp": "desc"}],
    "query": {
      "bool": {
        "must": [
          {"match": {"app_name": "vortmall-biz-order"}},
          {"match": {"level": "ERROR"}}
        ]
      }
    }
  }'

按时间范围查询日志

# 查询最近 1 小时内的错误日志
curl -X GET "<es-host>:9200/vortmall-log-*/_search?pretty" \
  -H "Content-Type: application/json" \
  -d '{
    "size": 50,
    "sort": [{"@timestamp": "desc"}],
    "query": {
      "bool": {
        "must": [
          {"match": {"level": "ERROR"}}
        ],
        "filter": [
          {"range": {"@timestamp": {"gte": "now-1h", "lte": "now"}}}
        ]
      }
    }
  }'

通过 Kibana 查看日志(如果已部署):

  1. 访问 Kibana:http://<kibana-host>:5601
  2. 进入 Discover 页面
  3. 选择日志索引模式(如 vortmall-log-*
  4. 使用 KQL 语法搜索,示例:
    • 搜索错误日志:level: "ERROR"
    • 按服务过滤:app_name: "vortmall-biz-order" AND level: "ERROR"
    • 搜索特定异常:message: "NullPointerException"
    • 组合条件:app_name: "vortmall-biz-payment" AND message: "timeout" AND @timestamp >= "2026-03-27"

日志清理(磁盘空间不足时):

# 删除 30 天前的日志索引
curl -X DELETE "<es-host>:9200/vortmall-log-2026.02.*"

# 查看索引占用磁盘空间
curl "<es-host>:9200/_cat/indices/vortmall-log-*?v&s=store.size:desc&h=index,store.size"

十二、Sa-Token 认证授权异常

12.1 Token 无效或过期

现象NotLoginException: Token无效

排查

  1. 检查 Token 是否已过期(sa-token.timeout 配置)
  2. 确认 Token 是否通过正确的 Header 传递(检查 sa-token.token-name
  3. 确认 Redis 中 Token 对应的会话数据存在

12.2 网关与服务 Token 不互通

现象:网关校验通过但服务端拿不到登录信息

排查

  1. 确认网关使用 sa-token-reactor-spring-boot3-starter(响应式)
  2. 确认业务服务使用 sa-token-spring-boot3-starter(Servlet)
  3. 确认两端连接同一 Redis、使用相同 Token 配置
  4. 检查网关 AuthContextFilter 是否正确传递了用户上下文

12.3 权限不足

现象NotPermissionExceptionNotRoleException

排查

  1. 检查用户角色权限数据是否正确
  2. 确认接口上的权限注解(@SaCheckPermission)与权限数据匹配
  3. 检查权限缓存是否过期需要刷新

附录:故障处理流程

发现异常
  │
  ├─ 服务不可用? ──→ 检查 Nacos 注册状态 → 检查服务进程 → 查看启动日志
  │
  ├─ 接口报错? ──→ 查看网关日志 → 定位目标服务 → 查看服务错误日志
  │
  ├─ 数据异常? ──→ 检查数据库直连 → 检查缓存一致性 → 检查 MQ 消费状态
  │
  ├─ 性能问题? ──→ 慢 SQL 排查 → 连接池状态 → MQ 积压 → ES 日志检索
  │
  └─ 分布式事务? ──→ Seata Server 日志 → undo_log 表 → 各分支事务状态
VortMall 微服务故障排查手册
请输入搜索内容
大纲
VortMall 微服务故障排查手册
目录
一、服务启动失败
1.1 端口占用
1.2 Bean 创建失败
1.3 配置文件加载失败
1.4 Java 版本不匹配
二、Nacos 注册与配置异常
2.1 服务注册失败
2.2 配置拉取失败
2.3 配置热更新不生效
三、数据库连接异常
3.1 连接池初始化失败
3.2 连接池耗尽
3.3 慢 SQL 导致超时
3.4 MyBatis-Plus 常见问题
四、Redis 缓存异常
4.1 连接失败
4.2 缓存穿透 / 击穿 / 雪崩
4.3 Redisson 分布式锁问题
4.4 Sa-Token 会话 Redis 异常
五、消息队列(RocketMQ)异常
5.1 Producer 发送失败
5.2 Consumer 消费失败
5.3 消息积压
六、Outbox 可靠消息发送异常
6.1 消息滞留在 Outbox 表中
6.2 Outbox 消息发送后状态异常
6.3 Outbox 表数据清理
七、网关路由异常
7.1 503 Service Unavailable
7.2 CORS 跨域问题
7.3 请求超时
7.4 请求体过大
八、Feign 服务间调用异常
8.1 调用超时
8.2 Fallback 未触发
8.3 服务发现找不到实例
8.4 序列化/反序列化异常
九、Seata 分布式事务异常
9.1 Seata Server 连接失败
9.2 全局事务回滚失败
9.3 事务超时
9.4 使用注意
十、XXL-JOB 定时任务异常
10.1 执行器注册失败
10.2 任务执行失败
十一、Elasticsearch 搜索异常
11.1 连接失败
11.2 索引不存在
11.3 数据同步延迟
11.4 通过 Elasticsearch 查看系统日志
十二、Sa-Token 认证授权异常
12.1 Token 无效或过期
12.2 网关与服务 Token 不互通
12.3 权限不足
附录:故障处理流程