背景
大促备战,最大的隐患项之一就是慢 sql,带来的破坏性最大,也是日常工作中常常带来整个利用抖动的最大隐患,而且对 sql 好坏的评估有肯定的技术要求,有一些缺乏经验或者因为不够认真造成一个坏的 sql 胜利走到了线上,等发现的时候要么是造成了线上影响、报警、或者后置的慢 sql 采集发现,这时候个别无奈疾速止损,须要批改代码上线、或者调整数据库索引。
外围痛点:
1、无奈提前发现慢 sql,可能好转为慢 sql 的语句
2、线上呈现慢 sql 后,无奈疾速止损
解决思路
1、把问题解决在上线之前,最好的方法就是在测试阶段,甚至在开发阶段就发现一个 sql 的好坏
2、线上发现慢 sql 后除了改代码上线、调整数据库表索引的形式外,反对热更新的形式替换 sql 语句 。
部门外部,目前大部分数据库框架采纳的 mybatis,而后基于 mybatis 自身的实现机制中,开发一个 mybatis 组件,能够主动对运行的 sql 进行提取和剖析,定制一套默认的剖析规定,让 sql 在开发环境和测试环境执行的时候,就可能做初步的评估,把有问题的慢 sql 在这个阶段裸露进去;同时具备 sql 替换性能,在线上呈现问题 sql 的时候,能够通过 ducc 配置疾速实现对一个 sql 的在线替换,大大降低线上问题的止损工夫。
开源计划调研
目前,支流的 sql 剖析组件,外围性能次要放在了两个方向:1、慢 sql 的剖析和优化倡议 2、sql 的优化重写性能,而且次要偏运维的辅助性能无奈做到无侵入的和利用代码进行集成。也就无奈实现咱们的外围痛点,慢 sql 提前剖析预警和动静 sql 替换。
[]()
设计方案
外围性能:SQL 剖析预警能力、SQL 替换能力
[]()
具体设计
次要分为 8 个功能模块
模块一:core 次要负责组件的接入到 mybatis,以及其它模块的编排调用
模块二:config 次要负责组件配置信息的初始化
模块三:extrat 次要通过解析 mybatis 相干对象,提取残缺的待执行 sql
模块四:analysis 次要拼接剖析语句,执行 explain 剖析语句并获取剖析后果
模块五:rule sql 剖析规定的加载和初始化,反对自定义规定
目前默认规定(继续扩大):
1、查问未匹配索引
2、匹配索引过滤成果较差
3、返回行数过多
4、应用了文件排序
模块六:score 基于剖析后果和配置的评分规定进行匹配打分,优化倡议组装
模块七:out 输出模块,对于输入后果进行输入,目前已 error 日志、MQ 两种输入形式
模块八:replace 替换模块,能够对 sql 语句基于 ducc 配置进行动静替换
应用办法
1、引入依赖 jar 包
<dependency>
<groupId>com.jd.sql.analysis</groupId>
<artifactId>sql-analysis</artifactId>
<version>1.2-SNAPSHOT</version>
</dependency>
2、配置组件 xml
<configuration>
<plugins>
<plugin interceptor="com.jd.sql.analysis.core.SqlAnalysisAspect" >
<!-- 开启 sql 剖析性能最简配置 -->
<property name="analysisSwitch" value="true"/>
<!-- 开启 sql 替换性能最简配置 -->
<property name="sqlReplaceModelSwitch" value="true"/>
<property name="duccAppName" value="workbench-backend"/>
<property name="duccUri" value="ucc://workbench-backend:2d6991cb865f4e6bac6c3e1cf7794cdf@test.ducc.jd.local/v1/namespace/workbench_backend/config/default/profiles/test?longPolling=60000&necessary=false"/>
<property name="duccMonitorKey" value="refundBugFlag"/>
</plugin>
</plugins>
</configuration>
3、外围配置项
属性 | 用处 | 是否必填 | 默认值 | 备注 |
---|---|---|---|---|
analysisSwitch | 是否开启剖析性能 | 是 | false | |
onlyCheckOnce | 是否对一个 sqlid 只剖析一次 | 非 | true | |
checkInterval | 每个 sqlid 剖析距离 | 非 | 300000 毫秒 | onlyCheckOnce 为 false 才失效 |
exceptSqlIds | 须要过滤不剖析的 sqlid | 非 | | |
sqlType | 剖析的 sql 类型 | 非 | 默认 select、update | 反对 |
scoreRuleLoadClass | 评分规定加载器,用于扩大自定义规定 | 非 | | |
outModel | 默认输入形式 | 非 | 默认值:LOG | 反对 LOG、MQ 两种形式 |
outputClass | 评分后果输入类,用于扩大自定义后果输入形式 | 非 | | |
sqlReplaceModelSwitch | sql 替换模块是否开启 | 非 | 默认 false | |
duccAppName | ducc 配置的利用名称(jdos) | 非 | | |
duccUri | ducc uri 配置 | 非 | | |
duccMonitorKey | sql 替换配置文件对应的 key | 非 | | |
4、默认剖析成果展现
4.1、慢 sql 剖析成果
[]()
4.2、sql 动静替换成果
5、实际应用计划
5.1、慢 sql 剖析 - 日志输入 + 关键词告警
<configuration>
<plugins>
<plugin interceptor="com.jd.sql.analysis.core.SqlAnalysisAspect" >
<property name="analysisSwitch" value="true"/>
</plugin>
</plugins>
</configuration>
5.2、慢 sql 剖析 - 日志输入 +mq 输入 +es 存储 +Kibana 剖析
<configuration>
<plugins>
<plugin interceptor="com.jd.sql.analysis.core.SqlAnalysisAspect" >
<property name="appName" value="workbench-backend"/>
<property name="analysisSwitch" value="true"/>
<property name="outputModel" value="mq"/>
<property name="mqApp" value="qlstation"/>
<property name="mqUser" value="qlstation"/>
<property name="mqPassword" value="D1BCC547"/>
<property name="mqAddress" value="jmq-testcluster.jd.local:50088"/>
<property name="mqTopic" value="jdl_kds_key_node_log"/>
</plugin>
</plugins>
</configuration>
最终成果
[]()
5.3、慢 sql 替换 -ducc 配置动静更新 sql 语句
<configuration>
<plugins>
<plugin interceptor="com.jd.sql.analysis.core.SqlAnalysisAspect" >
<property name="sqlReplaceModelSwitch" value="true"/>
<property name="duccAppName" value="workbench-backend"/>
<property name="duccUri" value="ucc://workbench-backend:2d6991cb865f4e6bac6c3e1cf7794cdf@test.ducc.jd.local/v1/namespace/workbench_backend/config/default/profiles/test?longPolling=60000&necessary=false"/>
<property name="duccMonitorKey" value="sqlReplaceConfig"/>
</plugin>
</plugins>
</configuration>
发现慢 sql
[]()
ducc 配置
[]()
线上 sql 被动静替换
[]()
留神:性能正式修复后,需去掉该配置,该性能仅供给急解决线上问题,不倡议作为性能长期应用
性能测试
测试环境千次一般 sql 查问,每种场景进行了 5 次测试
未启用插件耗时:11108ms,10237ms,9482ms,7938ms,8196ms
开启 sql 剖析耗时:16619ms,17333ms,16321ms,19057ms,18164ms
理论配置,只有首次执行或者间隔时间执行,单次影响 10ms 左右)
开启 sql 替换耗时:10642ms,8803ms,8353ms,8830ms,9170ms
根本无影响
实用场景
1、慢 sql 预防
2、线上问题止损
劣势
1、外围劣势:执行时剖析 sql,区别于传统的依赖 sql 执行耗时来评估慢 sql,间接基于语法和索引进行前置剖析,不仅能预防某些坏 sql 在上线后发现是慢 sql,还能给出 sql 优化倡议,能够大限度的防止线上产生慢 sql。反对动静对线上 sql 进行替换,能够对线上问题疾速止损。
2、性能:基于性能和不同的应用场景思考,反对定制化配置,每个 sql 是否仅进行一次查看、或者按某个工夫距离进行配置。sql 替换简直无损耗。
3、扩大:基于后续 sql 评分规定的扩大、以及剖析后果以不同的形式输入的思考,反对评分规定、输入形式的自定义扩大。
4、老本:接入成本低,无代码侵入。
作者:京东物流 扈海涛
起源:京东云开发者社区