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

简易的慢SQL自定义告警实战经验(支持多数据源)

背景

对于慢SQL相信大家都不陌生了,一旦遇到后,相信大家会很快的提供出来对应的优化方法、索引优化建议工具使用等等,对于此我相信大家已经熟悉的不能再熟悉了,但是比较不尽人意的是:在此之前我们往往是花费了大量时间才发现造成系统出现问题的是慢SQL引起的,风险自然而然地也就慢慢升高了,基于此开发了一款简易的慢SQL自定义告警组件,为的就是提前预警,在影响扩大化之前进行快速止损,甚至是在一些新业务在上线前(测试、预发布)提前发现风险并规避

原理简介

通过mybatis拦截器进行sql语句执行过程的拦截,同步执行过程中计算sql执行的时间,当实际执行时间大于指定的配置阈值时发出告警信息并打印日志(日志中带有详细的调用链信息方便快速定位调用源头),同时将对应的sql放入异步队列disruptorQueue中,异步分析sql的执行计划,这里主要做3中场景预警

1.出现不走索引的全表扫描场景

2.没有走索引

3.扫描数据量超过配置阈值

关键代码

1、Mybatis拦截器实现执行时间超时预警以及放入异步队列

自定义一个类实现接口org.apache.ibatis.plugin.Interceptor,增加上官方提供的注解@Intercepts,这里主要介绍几个细节,具体关键代码如下

◦同步执行逻辑中根据sql的实际执行时间判断是否进行预警

◦预警日志中打印出具体的调用链堆栈信息

◦同一条sql在同一天最多只预警一次

◦具体sql的explain分析以及预警放在异步执行

◦开放子类可覆盖方法自行实现个性逻辑:比如mybatic-Plus的多数据源支持

/*** 数据库操作性能拦截器,记录耗时* @Intercepts定义Signature数组,因此可以拦截多个,但是只能拦截类型为:*         Executor*         ParameterHandler*         StatementHandler*         ResultSetHandler*/
@Slf4j
@Component
@Intercepts(value = {@Signature(type=Executor.class,method="query",args={MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class,CacheKey.class,BoundSql.class}),@Signature(type=Executor.class,method="query",args={MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class})})
public class SqlInterceptor implements Interceptor {/*** 判定sql执行超时的时间标准,单位毫秒*/private final int DEFAULST_TIMEOUT = 1000;/*** sql最大扫描行数*/private final int DEFAULT_MAX_SCANROWS = 50000;/*** 每秒sql入队的最大限制*/private final double SQL_PERMITS_PERSECOND = 10.0;/*** 同一个sql在redis中的过期时间*/private final Long DEFAULT_REDIS_TIME = 24 * 60 *60L;/***  分析sql阈值告警默认时间 单位:毫秒*/private final Long DEFAULT_EXPLAIN_ALERM_TIME = 0L;/*** 缓存时间 单位:秒*/private Long redisTime;/*** 分析sql阈值告警时间 单位:毫秒*/private Long explainAlermTime;/*** 限流器*/private RateLimiter rateLimiter = RateLimiter.create(SQL_PERMITS_PERSECOND,3*60, TimeUnit.SECONDS);private String appCode;private String appName;private String appStackBasePackage;private String dataSourceId;private String redisClientId;private Cluster redisClient;private DataSource dataSource;private String dbName;private JdbcTemplate jdbcTemplate;private Integer maxScanRows;private Integer sqlTimeout;private Boolean explainSwitch;protected final Map<String,JdbcTemplate> jdbcTemplateMap = new ConcurrentHashMap<>();/*** 初始jdbcTemplateMap,可由子类实现*/public void initjdbcTemplateMap(){}/*** 实现拦截的地方* @param invocation* @return* @throws Throwable*/@Overridepublic Object intercept(Invocation invocation) throws Throwable {Object target = invocation.getTarget();Method method = invocation.getMethod();Object result = null;if (target instanceof Executor) {long start = System.currentTimeMillis();/**执行方法*/try{result = invocation.proceed();long end = System.currentTimeMillis();long executeTime = end-start;log.debug("sql性能监控-execute-target:{}毫秒",executeTime);this.doTimeOutSql(invocation, executeTime);}catch (Throwable var1) {long end = System.currentTimeMillis();long executeTime = end-start;String logId = UUID.randomUUID().toString();this.businessAlarmError(invocation, executeTime, logId);throw new RuntimeException("sql性能监控-调用原始方法出错:logId=" + logId + ",方法:" + method, var1);}}return result;}/*** Plugin.wrap生成拦截代理对象* @param target* @return*/@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {}/*** 处理超时SQL*      1.超时自定义报警*      2.超时入redis慢SQL队列* @param invocation*/private void doTimeOutSql(Invocation invocation,long executeTime){long startTime = System.currentTimeMillis();String preSql = "";try{SqlEventInfo sqlEventInfo = this.getRealSqlInfo(invocation, executeTime);preSql = sqlEventInfo.getPreSql();//自定义告警List<StackTraceElement> pivotalStackTraces = getPivotalStackTraces();sqlEventInfo.setPivotalStackTraces(pivotalStackTraces);if(executeTime - getSqlTimeout() > 0){StringBuffer alermKeyBuf = new StringBuffer();alermKeyBuf.append(this.appCode).append(".").append(SqlAlermEnum.SQL_ALERM_KEY.getDesc());

相关文章:

简易的慢SQL自定义告警实战经验(支持多数据源)

背景 对于慢SQL相信大家都不陌生了,一旦遇到后,相信大家会很快的提供出来对应的优化方法、索引优化建议工具使用等等,对于此我相信大家已经熟悉的不能再熟悉了,但是比较不尽人意的是:在此之前我们往往是花费了大量时间才发现造成系统出现问题的是慢SQL引起的,风险自然而…...

【Springboot】Filter 过滤器的使用

一、基本介绍 过滤器 Filter 作为 Java 三大器之一&#xff0c;在 Java Web 的使用中有很高的地位。所谓过滤器&#xff0c;就是实现了 javax.servlet.Filter 接口的服务器端程序&#xff0c;就是对事物进行过滤的。在 Web 中的过滤器&#xff0c;当然就是对请求进行过滤&#…...

力扣-461.汉明距离

Method 1 直接比较x&#xff0c;y二进制中的每一位&#xff0c;如果不同则cnt加一&#xff0c;并且x&#xff0c;y每次右移一位 class Solution { public:int hammingDistance(int x, int y) {int cnt 0;while(x > 0 && y > 0) {if((x & 1) ! (y & 1)…...

GEE 18:基于GEE平台的土地荒漠化监测与分析【论文复现】

Desertification 1. 研究背景1.1 参考论文1.2 参数获取1.2.1 NDVI1.2.2 Albedo1.2.3 Normalizing indices1.2.4 Calculating the quantitative relationship1.2.5 Calculating DDI2. GEE2.1 数据2.2 GEE code2.2.1 Study region2.2.2 Reomove cloud for Landsat-82.2.3 Calcula…...

平台系统老板驾驶舱的重要性,我选云表

平台系统老板驾驶舱的重要性在于它是一个集成的管理和分析工具&#xff0c;能够提供对平台系统运行情况的全面和实时的监控、分析和管理功能。以下是平台系统老板驾驶舱的重要性&#xff1a; 老板驾驶舱 该表单可供老板实时把控企业运营情况&#xff0c;包括销售业绩、…...

【SpringMVC篇】探索请求映射路径,Get请求与Post请求

&#x1f38a;专栏【SpringMVC】 &#x1f354;喜欢的诗句&#xff1a;天行健&#xff0c;君子以自强不息。 &#x1f386;音乐分享【如愿】 &#x1f384;欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f33a;请求映射路径⭐报错原因⭐解决方法 &#x1f33a;…...

vqvae简单实战,利用vqvae来提升模型向量表达

最近CV领域各种大模型在图像生成领域大发异彩&#xff0c;比如这两年大火的dalle系列模型。在这些模型中用到一个基础模型vqvae&#xff0c;今天我们写个简单实现来了解一下vqvae的工作原理。vqvae原始论文连接https://arxiv.org/pdf/1711.00937.pdf 1&#xff0c;代码 首先我们…...

idea禁用双击ctrl

Run anything | IntelliJ IDEA Documentation Disable double modifier key shortcuts...

记使用docker部署项目出现问题

我的docker-compose.yml内容如下&#xff1a; version: "3" services:my_server:build: .restart: alwaysdepends_on:mysql:condition: service_startedports:- 9999:9999links:- mysqlmysql:image: mysql:latest # mysql:oraclerestart: alwayscontainer_name: mys…...

EDU挖掘

1.信息搜集2.漏洞挖掘 1.信息搜集 没事干&#xff0c;准备找个证书站挖挖看&#xff0c;没想到碰到一个小通用系统。 看样子还挺多功能可以测&#xff0c; 这里利用F12 查看前端源码js 或者css文件&#xff0c;直接用hunter或者fofa搜索到同一类型的网站。 Hunter语法&#…...

机器人制作开源方案 | 杠杆式6轮爬楼机器人

1. 功能描述 本文示例将实现R281b样机杠杆式6轮爬楼机器人爬楼梯的功能&#xff08;注意&#xff1a;演示视频中为了增加轮胎的抓地力&#xff0c;在轮胎上贴了双面胶&#xff0c;请大家留意&#xff09;。 2. 结构说明 杠杆式6轮爬楼机器人是一种专门用于爬升楼梯或不平坦地面…...

报错——warning: ignoring JAVA_HOME=/home/jdk/jdk1.8.0_281; using bundled JDK

我使用了es的8.3.0版本&#xff0c;但es从7.17版本以后不再支持jdk1.8了&#xff0c;需要进行JDK的版本升级&#xff0c;或者降低es的版本。 es和jdk对比版本...

【Java8】java.time 根据日期获取年初年末、月初月末、日初日末

目录 年初年末月初月末3. 日初日末 记录日常开发中的常用的日期转换代码&#xff0c;算是一篇Java 8时间API使用实操的简短总结文。 下文中&#xff0c;都以LocalDateTime为例&#xff0c;在不声明的情况下如下方法一般都适用于Java8中LocalDate、LocalDateTime、OffsetDateTi…...

【LeetCode: 137. 只出现一次的数字 II | 位运算 | 哈希表】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…...

「深入探究Web页面生命周期:DOMContentLoaded、load、beforeunload和unload事件」

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 引言 1. DOMContentLoaded 1.1 属性 1.2 A…...

SpringMVC源码分析(一)启动流程分析

a、SpringMVC 在启动过程中主要做了什么事情&#xff1f; SpringMVC在启动过程中是什么时候解析web.xml文件的&#xff0c;又是什么时候初始化9大内置对象的&#xff1f; <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns"http://xml…...

ARM 10.12

设置按键中断&#xff0c;按键1按下&#xff0c;LED亮&#xff0c;再按一次&#xff0c;灭 按键2按下&#xff0c;蜂鸣器响。再按一次&#xff0c;不响 按键3按下&#xff0c;风扇转&#xff0c;再按一次&#xff0c;风扇停 src/key.c #include"key.h"//按键3的配…...

vue-rouer 路由

安装/配置: //进入项目目录:(在搭建项目的时候安装了) cnpm install vue-router --save旧版路由 需要自己配置 //项目中载入,一般在main.js中载入:import VueRouter from vue-routerVue.use(VueRouter)let router new VueRouter({}) //其中配置路径和地址//在Vue中引入:n…...

元数据的前世今生

什么是元数据 元数据(Metadata)是描述数据的数据。它是一组信息,用于描述数据的特征、属性、结构和内容,以便更好地管理、理解、组织和使用数据。让人们能够清楚拥有什么数据、代表什么、源自何处、如何在系统中移动,以及哪些人可以使用源数据,如何使用。 元数据通常包…...

Python实现简易过滤删除数字的方法

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 如果想从一个含有数字&#xff0c;汉字&#xff0c;字母的列表中滤除仅含有数字的字符&#xff0c; 当然可以采取正则表达式来完成&#xff0c;但是有点太麻烦了…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

Robots.txt 文件

什么是robots.txt&#xff1f; robots.txt 是一个位于网站根目录下的文本文件&#xff08;如&#xff1a;https://example.com/robots.txt&#xff09;&#xff0c;它用于指导网络爬虫&#xff08;如搜索引擎的蜘蛛程序&#xff09;如何抓取该网站的内容。这个文件遵循 Robots…...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...

第八部分:阶段项目 6:构建 React 前端应用

现在&#xff0c;是时候将你学到的 React 基础知识付诸实践&#xff0c;构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段&#xff0c;你可以先使用模拟数据&#xff0c;或者如果你的后端 API&#xff08;阶段项目 5&#xff09;已经搭建好&#xff0c;可以直接连…...

jdbc查询mysql数据库时,出现id顺序错误的情况

我在repository中的查询语句如下所示&#xff0c;即传入一个List<intager>的数据&#xff0c;返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致&#xff0c;会导致返回的id是从小到大排列的&#xff0c;但我不希望这样。 Query("SELECT NEW com…...

负载均衡器》》LVS、Nginx、HAproxy 区别

虚拟主机 先4&#xff0c;后7...

用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法

用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法 大家好,我是Echo_Wish。最近刷短视频、看直播,有没有发现,越来越多的应用都开始“懂你”了——它们能感知你的情绪,推荐更合适的内容,甚至帮客服识别用户情绪,提升服务体验。这背后,神经网络在悄悄发力,撑起…...