当前位置: 首页 > news >正文

Spring Boot 3.5 + MyBatis Plus + RabbitMQ:打造 AI 驱动的慢 SQL 监控与优化系统

一套面向高并发场景的智能性能诊断方案,自动捕获慢请求与慢 SQL,通过 RabbitMQ 削峰异步处理,调用大模型生成优化建议并持久化,实现“从发现到建议”全自动 SQL 治理闭环

1. 为什么需要这套系统?

  • 人工看慢日志太累:传统 MySQL 慢查询日志或 Druid 监控页面需要 DBA 逐条分析,时效性差。

  • 接口慢 ≠ 一定是 SQL 慢:可能包含了业务逻辑耗时,需同时监控接口总耗时单条 SQL 耗时才能精准定位。

  • AI 可直接给出改写方案:结合 SQL 模板、执行耗时、接口上下文,大模型能快速给出加索引、改写法等具体建议,降低人工门槛。

于是我们构建了一个无侵入、异步、可扩展的 AI 慢 SQL 分析系统,核心流程如下:

用户请求 → Filter 计时开始 → 业务 SQL 执行(Interceptor 记录 SQL 耗时)
→ Filter 计时结束 → 总耗时超过阈值?
→ 是 → 收集 SQL 耗时信息 → 封装事件 → 发送 RabbitMQ
→ 消费者消费事件 → 写入慢日志 + 调用 AI 分析每条 SQL → 入库待审核

2. 技术选型

组件作用
Spring Boot 3.5.12基础框架,提供 Web、AMQP、JDBC 自动配置
MyBatis Plus 3.5.5ORM 层,简化开发,提供插件机制
MySQL业务数据 + 监控结果存储
RabbitMQ异步解耦,削峰填谷
Jackson消息 JSON 序列化
RestTemplate调用 OpenAI/DeepSeek 等兼容接口
Druid连接池,可选作为 SQL 监控的兜底数据源

3. 核心实现细节

3.1 请求级计时:RequestTimingFilter

所有 API 请求都经过该 Filter,记录开始时间,生成 TraceId,并在请求结束后判断是否慢请求。

@Component public class RequestTimingFilter implements Filter { @Value("${slow.request-threshold:1000}") private long slowThreshold; // 总耗时阈值,配置化 @Autowired private SlowRequestProducer producer; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; long start = System.currentTimeMillis(); String traceId = UUID.randomUUID().toString().replace("-", "").substring(0, 16); httpRequest.setAttribute("startTime", start); httpRequest.setAttribute("traceId", traceId); try { chain.doFilter(request, response); } finally { long totalTime = System.currentTimeMillis() - start; if (totalTime > slowThreshold) { // 从线程变量中取出该请求内所有 SQL 的耗时 ConcurrentHashMap<String, Long> sqlTimes = SqlTimingInterceptor.getCurrentSqlTimes(); // 封装事件并发送 RabbitMQ(代码见下文) SlowRequestEvent event = buildEvent(httpRequest, totalTime, traceId, sqlTimes); producer.sendSlowRequestEvent(event); } SqlTimingInterceptor.clear(); // 防止内存泄漏 } } }

3.2 SQL 执行耗时拦截:SqlTimingInterceptor

利用 MyBatis 插件机制拦截StatementHandler.prepare()方法,记录每条 SQL 的执行耗时。

@Component @Intercepts(@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})) public class SqlTimingInterceptor implements Interceptor { private static final ThreadLocal<ConcurrentHashMap<String, Long>> SQL_TIMES = new ThreadLocal<>(); @Override public Object intercept(Invocation invocation) throws Throwable { long start = System.nanoTime(); Object result = invocation.proceed(); long execMs = (System.nanoTime() - start) / 1_000_000; StatementHandler handler = (StatementHandler) invocation.getTarget(); String rawSql = handler.getBoundSql().getSql().replaceAll("\\s+", " "); // 简单脱敏:将数字和字符串替换为 ? String template = rawSql.replaceAll("\\d+", "?").replaceAll("'[^']*'", "?"); ConcurrentHashMap<String, Long> map = SQL_TIMES.get(); if (map == null) { map = new ConcurrentHashMap<>(); SQL_TIMES.set(map); } map.merge(template, execMs, Math::max); // 同模板保留最大耗时 return result; } public static ConcurrentHashMap<String, Long> getCurrentSqlTimes() { return SQL_TIMES.get(); } public static void clear() { SQL_TIMES.remove(); } }

注册拦截器:为避免 Spring 自动装配时机问题,使用ConfigurationCustomizer确保拦截器一定会被添加到Configuration

@Configuration public class MyBatisPlusConfig { @Bean public ConfigurationCustomizer mybatisConfigurationCustomizer() { return configuration -> configuration.addInterceptor(new SqlTimingInterceptor()); } }

3.3 RabbitMQ 配置:统一 JSON 序列化

自定义RabbitTemplate和消费者容器工厂,全部使用Jackson2JsonMessageConverter,避免 Java 原生序列化带来的NotSerializableException

@Configuration public class RabbitMqConfig { public static final String EXCHANGE = "slow.request.exchange"; public static final String QUEUE = "slow.sql.queue"; public static final String ROUTING_KEY = "slow.sql"; // 声明交换机、队列、绑定 ... @Bean public Jackson2JsonMessageConverter converter() { return new Jackson2JsonMessageConverter(); } @Bean public RabbitTemplate rabbitTemplate(ConnectionFactory cf) { RabbitTemplate template = new RabbitTemplate(cf); template.setMessageConverter(converter()); return template; } @Bean public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory cf) { SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); factory.setConnectionFactory(cf); factory.setMessageConverter(converter()); return factory; } }

3.4 消费者:持久化 + AI 分析

@Component public class SlowRequestConsumer { @Value("${slow.sql-threshold:500}") private long sqlThreshold; // 单条 SQL 的最低分析阈值,配置化 @Autowired private SlowRequestLogMapper logMapper; @Autowired private OptimizationAnalysisMapper analysisMapper; @Autowired private AiAnalysisService aiAnalysisService; @RabbitListener(queues = RabbitMqConfig.QUEUE) public void handle(SlowRequestEvent event) { // 1. 保存慢请求日志 SlowRequestLog log = buildLog(event); logMapper.insert(log); // 2. 对每条 SQL 进行分析 if (event.getSqlList() != null) { for (SqlExecInfo sql : event.getSqlList()) { if (sql.getExecTimeMs() < sqlThreshold) continue; // 忽略耗时过短的单条 SQL String aiResult = aiAnalysisService.analyzeSql( sql.getTemplate(), sql.getExecTimeMs(), event.getUri() ); // 保存分析结果(含危险操作标记) OptimizationAnalysis analysis = buildAnalysis(log.getId(), sql, aiResult); analysisMapper.insert(analysis); } } } }

3.5 AI 调用服务

@Service public class AiAnalysisService { @Value("${ai.provider.url}") private String aiUrl; @Value("${ai.provider.api-key}") private String apiKey; @Value("${ai.provider.model}") private String model; private final RestTemplate restTemplate = new RestTemplate(); public String analyzeSql(String sql, long execTimeMs, String apiPath) { String prompt = String.format(""" 接口: %s SQL: %s 执行耗时: %dms 请以JSON格式分析原因并给出优化建议,包含 risk 字段。 """, apiPath, sql, execTimeMs); // 构建 OpenAI 兼容请求 Map<String, Object> body = Map.of( "model", model, "messages", List.of( Map.of("role", "system", "content", "你是MySQL优化专家,返回JSON。"), Map.of("role", "user", "content", prompt) ), "temperature", 0.2 ); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setBearerAuth(apiKey); ResponseEntity<String> resp = restTemplate.postForEntity( aiUrl, new HttpEntity<>(body, headers), String.class ); return resp.getBody(); // 实际需提取 choices[0].message.content } }

4. 测试与验证

4.1 数据库准备

执行init.sql创建studentteacherslow_request_logoptimization_analysis表。
测试时若student表只有几条数据,查询耗时极短,无法触发阈值。可采用以下方式模拟:

方案一:调低阈值(推荐快速测试)

application.yml中设置:

slow: request-threshold: 10 # 10ms,任意查询都会被视为慢请求 sql-threshold: 1
方案二:插入大量数据

通过存储过程插入 50 万条学生数据,使全表扫描超过 1 秒。

方案三:在 Controller 中手动延时
@GetMapping("/slow-students") public List<Student> slowStudents() throws InterruptedException { List<Student> list = studentMapper.selectList(...); Thread.sleep(1500); // 制造总耗时 > 1s return list; }

4.2 验证结果

  1. 访问http://localhost:8080/api/test/slow-students

  2. 查看 RabbitMQ 管理界面,队列中应有消息。

  3. 查询数据库:

    SELECT * FROM slow_request_log; SELECT * FROM optimization_analysis;
  4. optimization_analysis.ai_suggestion字段应包含 AI 返回的 JSON 建议。

6. 生产强化建议

  1. SQL 指纹去重:同一 SQL 指纹在 1 小时内只分析一次,引入 Redis 记录。

  2. AI 结果解析:提取risk字段,将高风险操作 (如 DROP) 自动标记为危险,需人工二次确认。

  3. 死信队列与重试:AI 调用失败的消息进入死信队列,后续定时补偿。

  4. 数据脱敏:消息中不携带真实参数值,全部替换为?

  5. 前端可视化:搭建管理页面展示待优化项,支持标记 “已应用”/“忽略”。

  6. 连接池与限流:对 AI 调用使用 Resilience4j 限制并发,避免超额。


7. 总结

本文从零实现了一套基于 Spring Boot + MyBatis Plus + RabbitMQ 的 AI 慢 SQL 监控系统。核心思路是:拦截请求与 SQL 耗时 → 异步发送事件 → 持久化并调用 AI 分析 → 入库待审。整个过程对业务代码零侵入,可大幅提升性能问题发现与解决的效率,尤其适合微服务架构下 SQL 治理难、缺乏专职 DBA 的团队。

完整代码可参考文中各片段组合,关键配置已全部给出,读者可直接复用至自己项目。


扩展思考:如果团队已引入 SkyWalking / Pinpoint 等 APM 工具,本系统可作为其增强模块,专注于自动化建议生成,形成“监控 → 诊断 → 建议”的完整链路。

http://www.jsqmd.com/news/732257/

相关文章:

  • C语言 宏嵌套的展开规则
  • 基于DINOv3、Swin Transformer、FastViT、ResNet的场景识别模型
  • 从`/proc/interrupts`输出看网络性能:以Realtek RTL8125网卡的中断风暴排查为例
  • 鑫豆娘豆腐店加盟——正规品牌护航,开一家火一家的刚需创业好项目 - 奔跑123
  • 把 SNC PSE 创建对,别让 STRUST 成为你上线前最后一个拦路虎
  • 雀魂牌谱屋完全指南:3步开启你的麻将数据分析之旅
  • 上海写字楼安保公司哪家好?2026正规商场/园区安保外包公司实力权威推荐 - 栗子测评
  • 从OBS插件到采集卡:聊聊那些伪装成‘正经软件’的AI自瞄,以及反作弊如何‘抓鬼’
  • 配置路径 + 数据路径架构
  • 2025届学术党必备的六大降重复率网站推荐
  • 【flutter for open harmony】第三方库Flutter 鸿蒙版 物流追踪 实战指南(适配 1.0.0)✨
  • 如何用3种方法让Mem Reduct显示中文界面?技术选型与实施指南
  • 2026江苏/南京安保服务哪家好?本地学校/商场安保服务商精选榜单 - 栗子测评
  • 企业如何利用Taotoken统一管理多个AI模型的API密钥与访问权限
  • 企业内如何构建安全可控的大模型API调用与管理体系
  • 在 Node.js 服务中集成多模型能力借助 Taotoken 统一 API 调用
  • GPT-5.5写文案、改稿、做大纲,写作全流程实测
  • 为什么85%的中文玩家都在寻找MASA模组汉化包?终极解决方案来了
  • 海外市场“可解释金融智能体”受关注,国内IT服务商如何参与竞争
  • CL9095 500mA输出可调线性稳压器
  • ComfyUI-Impact-Pack终极指南:解锁AI图像精细化处理的完整工作流
  • 把 ABAP 平台上的 SNC 真正配通,使用 SAP Cryptographic Library 完成 PSE、密钥对与应用服务器落地
  • 18年GitHub老用户因平台故障频发迁出项目,直言:若改进仍愿回归
  • 如何在10分钟内搭建高效的PlantUML Server?[特殊字符]
  • 安卓基础之《(29)—消息机制与异步任务》
  • 2026年5月最新宝珀官方售后网点核验报告(含迁址/新开)|亲测全流程记录 - 亨得利官方服务中心
  • 从零到上线:手把手教你用Vue3+OpenLayers搭建一个企业级GIS管理系统(兼容IE11)
  • Maccy:重新定义macOS剪贴板管理的工作流优化方案
  • 2025届毕业生推荐的十大降AI率网站横评
  • Windows 11任务栏拖放修复:终极免费解决方案完全指南