当前位置: 首页 > 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;但是有点太麻烦了…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...