
一套面向高并发场景的智能性能诊断方案自动捕获慢请求与慢 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 的耗时 ConcurrentHashMapString, 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 ThreadLocalConcurrentHashMapString, 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([^]*, ?); ConcurrentHashMapString, 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 ConcurrentHashMapString, 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 兼容请求 MapString, 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); ResponseEntityString resp restTemplate.postForEntity( aiUrl, new HttpEntity(body, headers), String.class ); return resp.getBody(); // 实际需提取 choices[0].message.content } }4. 测试与验证4.1 数据库准备执行init.sql创建student、teacher、slow_request_log、optimization_analysis表。测试时若student表只有几条数据查询耗时极短无法触发阈值。可采用以下方式模拟方案一调低阈值推荐快速测试application.yml中设置slow: request-threshold: 10 # 10ms任意查询都会被视为慢请求 sql-threshold: 1方案二插入大量数据通过存储过程插入 50 万条学生数据使全表扫描超过 1 秒。方案三在 Controller 中手动延时GetMapping(/slow-students) public ListStudent slowStudents() throws InterruptedException { ListStudent list studentMapper.selectList(...); Thread.sleep(1500); // 制造总耗时 1s return list; }4.2 验证结果访问http://localhost:8080/api/test/slow-students。查看 RabbitMQ 管理界面队列中应有消息。查询数据库SELECT * FROM slow_request_log; SELECT * FROM optimization_analysis;optimization_analysis.ai_suggestion字段应包含 AI 返回的 JSON 建议。6. 生产强化建议SQL 指纹去重同一 SQL 指纹在 1 小时内只分析一次引入 Redis 记录。AI 结果解析提取risk字段将高风险操作 (如 DROP) 自动标记为危险需人工二次确认。死信队列与重试AI 调用失败的消息进入死信队列后续定时补偿。数据脱敏消息中不携带真实参数值全部替换为?。前端可视化搭建管理页面展示待优化项支持标记 “已应用”/“忽略”。连接池与限流对 AI 调用使用 Resilience4j 限制并发避免超额。7. 总结本文从零实现了一套基于 Spring Boot MyBatis Plus RabbitMQ 的 AI 慢 SQL 监控系统。核心思路是拦截请求与 SQL 耗时 → 异步发送事件 → 持久化并调用 AI 分析 → 入库待审。整个过程对业务代码零侵入可大幅提升性能问题发现与解决的效率尤其适合微服务架构下 SQL 治理难、缺乏专职 DBA 的团队。完整代码可参考文中各片段组合关键配置已全部给出读者可直接复用至自己项目。扩展思考如果团队已引入 SkyWalking / Pinpoint 等 APM 工具本系统可作为其增强模块专注于自动化建议生成形成“监控 → 诊断 → 建议”的完整链路。