关键问题修复指南¶
文档版本: 1.7.0 最后更新: 2026-04-10 Git 提交: 2cba097 作者: Lincoln
概述¶
本文档记录了 JAiRouter 项目开发和运维过程中遇到的关键问题及其修复方案,帮助快速定位和解决类似问题。
高优先级问题¶
1. WebFlux 阻塞调用导致性能下降¶
问题描述: 系统并发能力不足,响应时间波动大
原因分析: - 部分代码使用阻塞的 JDBC 调用 - 文件 I/O 操作未异步化 - HTTP 调用使用 RestTemplate
修复方案:
// ❌ 错误:阻塞调用
public Mono<Response> getData() {
Data data = repository.findById(id); // 阻塞
return Mono.just(convert(data));
}
// ✅ 正确:响应式调用
public Mono<Response> getData() {
return repository.findById(id)
.map(this::convert);
}
验证方法: - 查看线程堆栈,确认无 BLOCKED 状态 - 压测对比 QPS 提升
相关版本: V1.4.0 修复
2. 熔断器状态管理混乱¶
问题描述: 熔断器状态转换不正确,偶发无法恢复
原因分析: - 状态判断逻辑分散在多处 - 圈复杂度过高(15+) - 并发状态下状态不一致
修复方案: 使用状态模式重构
public interface CircuitBreakerState {
void recordSuccess(CircuitBreakerContext context);
void recordFailure(CircuitBreakerContext context);
boolean allowRequest();
}
public class ClosedState implements CircuitBreakerState { ... }
public class OpenState implements CircuitBreakerState { ... }
public class HalfOpenState implements CircuitBreakerState { ... }
验证方法: - 单元测试覆盖所有状态转换 - 压测验证故障恢复
相关版本: V1.4.1 修复
3. R2DBC 查询方法命名失效¶
问题描述: Spring Data R2DBC 方法命名查询不生效
原因分析: - R2DBC 不支持复杂的方法命名派生查询 - 某些关键字组合无法正确解析
修复方案: 使用 @Query 注解
// ❌ 错误:方法命名可能失效
Mono<ServiceInstance> findByServiceKeyAndStatus(String key, String status);
// ✅ 正确:使用@Query
@Query("SELECT * FROM service_instance WHERE service_key = :key AND status = :status")
Mono<ServiceInstance> findByServiceKeyAndStatus(String key, String status);
验证方法: - 检查生成的 SQL 是否正确 - 日志输出实际执行的 SQL
4. 前端路由配置导致 404¶
问题描述: Vue 前端刷新页面出现 404
原因分析: - 前端使用 history 模式 - 后端未配置 fallback 路由
修复方案:
@Configuration
public class WebFluxConfig implements WebFluxConfigurer {
@Override
public void configureRouting(RouteBuilder routes) {
routes.GET("/admin/**", ctx -> {
return ctx.render("index.html"); // fallback
});
}
}
验证方法: - 访问前端路由直接刷新 - 检查是否返回 index.html
5. 浏览器缓存导致变更不生效¶
问题描述: 修改静态资源后,浏览器仍显示旧内容
原因分析: - 静态资源未添加版本参数 - 浏览器强缓存策略
修复方案: 1. 构建时添加文件 hash 2. HTML 引用添加版本号 3. 开发环境禁用缓存
验证方法: - 清空浏览器缓存 - 使用无痕模式测试
中优先级问题¶
6. 配置版本回滚失败¶
问题描述: 配置回滚到历史版本后未生效
原因分析: - 版本切换未触发配置刷新 - 缓存未清理
修复方案:
public void rollback(String version) {
Config config = versionRepository.findById(version);
configRepository.save(config);
cache.invalidate(config.getKey()); // 清理缓存
eventPublisher.publish(new ConfigChangedEvent(config)); // 发布事件
}
7. 限流器并发计数不准确¶
问题描述: 高并发下限流器放行请求超过设定值
原因分析: - 计数器非原子操作 - 分布式环境下不同步
修复方案:
// 使用原子类
private final AtomicLong count = new AtomicLong(0);
// 或使用 Redis 分布式锁
public Mono<Boolean> tryAcquire() {
return redisTemplate.execute(script, keys, args);
}
8. JWT 令牌验证性能瓶颈¶
问题描述: JWT 验证占用大量 CPU 时间
原因分析: - 每次请求都解析 JWT - 未使用缓存
修复方案:
// 缓存解析后的 Claims
private final Cache<String, Claims> cache = Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
public Claims parse(String token) {
return cache.get(token, t -> jwtParser.parse(t));
}
低优先级问题¶
9. 文档链接失效¶
问题描述: MkDocs 编译时报告链接失效
原因分析: - 文件移动未更新引用 - 锚点变更
修复方案: 1. 使用脚本检查链接 2. 使用相对路径 3. 添加缺失文件
10. 测试覆盖率不达标¶
问题描述: JaCoCo 报告覆盖率低于 60%
原因分析: - 新增代码未写测试 - 边界条件未覆盖
修复方案: 1. 配置 Maven 强制检查 2. 使用 IDE 测试覆盖率工具 3. 优先覆盖核心逻辑
问题排查流程¶
1. 问题定位¶
# 查看应用日志
tail -f logs/application.log
# 查看慢查询
curl http://localhost:8080/actuator/metrics/db.pool.wait
# 查看线程堆栈
jstack <pid> > thread_dump.txt
2. 复现问题¶
- 记录操作步骤
- 准备测试数据
- 编写复现脚本
3. 分析原因¶
- 查看相关代码
- 分析日志输出
- 使用调试工具
4. 制定方案¶
- 评估影响范围
- 设计修复方案
- 准备回滚计划
5. 验证修复¶
- 单元测试验证
- 集成测试验证
- 回归测试验证
预防措施¶
1. 代码审查¶
- 所有 PR 必须经过审查
- 使用 Checkstyle 检查规范
- 使用 SpotBugs 检查 bug
2. 自动化测试¶
- 单元测试覆盖率 > 80%
- 集成测试覆盖核心流程
- E2E 测试覆盖关键场景
3. 持续集成¶
- 提交触发自动构建
- 自动运行测试
- 自动质量检查
4. 监控告警¶
- 关键指标监控
- 异常自动告警
- 日志聚合分析
相关文档¶
更新日期: 2026-04-10 文档维护: JAiRouter Team