背景
为了去抓取应用端发来的负载信息,比如sql,timestamp,sql中的para,和select语句的result集合,通过分析这些负载,来模拟负载,主要用于抓取应用端的负载,相当于数据挖掘中获取数据的来源把~~
这篇主要是总结我在适配skywalking获取mysql应用端的负载遇到的问题和感受。
先行
利用skywalking在以mysql为数据库的应用程序中抓取负载,在实验中,以oltpbench为应用端。大致的配置是,在https://github.com/apache/skywalking拉去skywalking源代码,利用说明文档进行编译
1
2
3
4
5git clone https://github.com/apache/skywalking.git
cd skywalking/
git submodule init
git submodule update
./mvnw clean package -DskipTests编译好的在dist目录下,如果没有别的需求,可直接在启动应用端的脚本或命令行中加入-javaagent /skywalking/agent/skywalking-agent.jar。
- 由于项目中需要按照一定的形式将抓取到的日志输入固定的文件中,因此主要对skywalking的三个包进行修改,分别是mysql-common,mysql-5.x,jdbc-commons,这三个都在./apm-sniffer/apm-sdk-plugins中。
操作
mysql-commons
- 里面都是一些截流器,有针对预编译sql的PreparadStatementExeucute,还有PreparadStatementBatchExeucute,和普通的StateExecute。这些截流器都被注册了,与mysql-5.x中的注册器对应,注册器指明mysql中哪里函数利用那些截流器去捕获。如”add batch”函数就利用PreparadStatementBatchExeucute去抓取。”executeUpdate”利用PreparadStatementExeucute和StateExecute去抓取(根据不同的sql类型)
mysql-5.x
- 一些注册器,与拦截器对应即可
jdbc-commons
- 主要是加了connId,还有与commit,rollback有关的拦截器,在这个包中,也进行了修改。
问题
mysql 的 jdbc重复调用问题
查看Mysql的jdbc的包(可利用反编译软件进行查看),发现add batch又调用了executeUpdate函数,导致skywalking抓包的时候重复捕获一条语句,导致重复。此外,还有executeUpdate自调用三次,导致一条日志被打印出三次。这类问题的处理方式,利用查看调用栈,分析它的调用过程,来忽略一些日志的输出。
1
2
3
4
5
6
7
8
9Exception ex = new Exception();
StackTraceElement[] ste = ex.getStackTrace();
boolean fromExecuteBatch = false;
for (int i = 0; i < ste.length; ++i) {
if(ste[i].getMethodName().contains("executeBatch")||ste[i].getMethodName().contains("executeUpdate$Original")){
fromExecuteBatch = true;
break;
}
}
mysql中以一个host为一个connId
- 由于项目的需要,我们需要得到connId,在jdbc-commons的相应位置加上与connId相关的代码。
- 但是发现createstatement有个问题,就是无论多少个线程,以及无论多少个连接,但输出总是一个相同的。但从mysql端捕获到的connectionInfo都是不同的,后来发现是skywalking中是根据host和Port来存储connectionInfo的,若从相同的host和port发送数据库请求,那skywalking(mysql部分,oracle应该不是这样的)就认为是用一条connectionInfo信息,导致出错。
- 这个问题的解决方法:就不用host和port进行存储..换了另一种方式。
总结
- skywalking适配mysql耗时达1周左右,发现自己还是畏惧源码的阅读,无论是skywalking还是mysql-jdbc还是不能有效的进行阅读,希望下次能改进。
- 自己对于问题的解决不能深入,抱着懒散的心态~,要加油呀!