本仓库是针对数据库并发查询开销进行预测的,包含了数据库负载生成,数据库压力测试,数据库资源开销预测等等多个部分。目前针对的数据库是postgresql
,截止到目前为止仅仅做了有限的工作。
本系统针对的预测场景是单点关系型数据库在并发访问工况下各种资源的消耗预测,因此在负载上选取面向事务的tpcc
测试。由于Percona-lab
仅有针对Mysql
的tpcc测试,因此针对Postgresql
的测试就需要自己编写,之所以不使用现有的benchmark工具是因为在测试过程中需要收集事务执行的诸多信息,只有在具体的代码中才能更好地,更灵活地收集这些信息。本系统针对Postgresql
的tpcc
测试遵守tpcc
测试规范,具体的测试代码采用c++编写,代码详见/load
目录。
使用者可以通过克隆仓库到本地获取源代码,本仓库的c++部分可以使用cmake
进行编译,且win
和Linux
平台通用,具体的编译方式如下:
root@lab4:/home/yanghang/test# cmake .
-- The C compiler identification is GNU 5.4.0
...
-- Build files have been written to: /home/yanghang/test
root@lab4:/home/yanghang/test# make
Scanning dependencies of target load
[ 4%] Building CXX object CMakeFiles/load.dir/main.cpp.obj
[ 8%] Building CXX object CMakeFiles/load.dir/lib/pg_lib/pg_connection.cpp.obj
...
[100%] Linking CXX executable load
[100%] Built target load
编译而成的load
程序可以在线数据导入,也可以生成数据文件然后通过COPY
命令批量导入。导入数据后使用者可以利用load
程序进行tpcc
测试并且可以设定并发度等参数。程序在进行并发访问数据库的同时还会生成并发事务执行的log
信息保存在指定的目录下。
这一步是建立在事务执行的log
信息上的,预测代码保存在/model
目录下,关于具体的依赖请直接在requirement.txt
中查看。预测模型首先对事务执行的log
进行解析,得到能够输入到模型中的输入。这个输入是九个二元组组成的一个十八维向量,每个元组对应一个tpcc
表,元组中的第一位代表该事务对该表的读次数,第二位代表对该表进的写次数,每一个向量的label
则是该事务的执行时间(毫秒)。通过解析事务执行的log
可以大概看出事务执行的时间分布是非常零散的,从200毫秒到8000毫秒都有。为了避免模型的输出太过分散,对所有的执行时间都取e
的对数。接下来开始对执行时间进行直接回归预测,Fig 1
是非并发条件下事务执行时间预测的损失和准确率:
可以看出若直接对执行时间进行回归预测效果是不好的,损失和准确率都一直在一个水平上震荡,没有表现出收敛的趋势,这可能是由于模型太过简单造成的。为了解决这个问题,我们可以考虑更粗粒度的预测,也就是说将事务执行时间的自然底数对数进行区间划分,模型只预测事务执行时间自然底数对数可能落入的区间,这样就把一个回归问题转化成了分类问题。在这里,考虑到模型的泛化能力和事务执行时间的散布,选取了180个区间。Fig 2
是非并发条件下执行时间区间的预测的准确率和损失,可以看到模型收敛是比较好的,最终准确率达到0.53左右。
接下来,使用测试集测试模型并且输出预测的事务执行时间。预测值和测试集的实际值对比如下,其中Fig 3
是未排序状态下事务执行时间的真实分布与模型预测分布的对比,Fig 4
是排序状态下二者的对比,可以看出模型的预测能力还是非常不错的。
最后,评价一下该模型:
Label accuracy: 0.534
Digtial accuracy: 0.1->67.029% | 0.2->73.643% | 0.3->79.023% | 0.35->80.997%
该模型的执行时间的区间预测准确率达到了0.534,在映射到真实的执行时间上却好很多,可以看到有67%的样本预测误差在0.1以内,80%的样本预测误差在0.35以内。当然,以上模型仅仅是针对非并发条件下的事务执行时间预测。如果是并发条件下呢?为此,我们使用多线程模拟并发工况,模型对并发状态下的事务执行时间预测效果如下:
并发条件下模型表现要差很多,非常不稳定。这也说明了事务的执行时间不仅仅与事务本身的性质相关,在并发条件下事务与事务之间的耦合关系也是一个重大因素。
由于事务的执行延迟大体上可以分为事务本身特性导致的执行延迟以及事务与事务之间耦合关系导致的执行延迟。前者主要是事务本身的IO,磁盘读写等等导致的延迟,与事务本身的特性有关,上一节使用BP网络就能够达到一个比较好的预测效果(80%以上的样本预测误差在0.35以内)。但是针对并发事务BP模型的拟合结果就很差了,这主要是因为模型不能分析样本与样本之间的耦合关系,也就是说传统的模型将训练数据视为一个个独立同分布的样本,这样的假设在非并发条件下适用,但在并发条件下样本与样本之间不是独立的(可能存在写锁竞争等)。笔者在这种更为一般的情况下选择LSTM进行预测,这样做的原因在于以LSTM为代表的众多循环神经网络能够在时序上将样本串联起来,建立起信号传输通道,这样会有助于解决事务并发执行耦合的问题。
上图所示的损失以及预测准确率曲线表明模型收敛是可以接受的。可以看到:最终模型的预测准确率稳定在0.9以上。但是这个模型的训练过程有一个较为致命的问题:训练样本存在类别不平衡问题。造成这个问题的原因在于一个事务往往是由多个sql查询组成的,这些查询往往执行速度非常快。笔者所在的环境下有86.7%的样本的执行时间都不到1毫秒(被记录成0毫秒),这导致训练样本中过多的label值为0:
tpcc=# explain analyse SELECT SUM(ol_amount) FROM order_line WHERE ol_o_id = 4 AND ol_d_id = 2 AND ol_w_id = 5;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=24.57..24.58 rows=1 width=4) (actual time=0.092..0.092 rows=1 loops=1)
-> Index Scan using order_line_pkey on order_line (cost=0.57..24.55 rows=10 width=4) (actual time=0.047..0.053 rows=5 loops=1)
Index Cond: ((ol_w_id = 5) AND (ol_d_id = 2) AND (ol_o_id = 4))
Planning time: 0.199 ms
Execution time: 0.175 ms
(5 rows)
通常情况下,如果样本出现类别不平衡问题可以通过过采样或者负采样来解决。但是在这个问题下样本与样本之间的偏序关系是非常重要的,采用任意一样采样方式都会不同程度上破坏这样的偏序关系,因此训练数据类别不平衡问题目前还没有解决,一个可行的思路就是增大并发量,让单个sql可能应为写锁竞争而加大执行时间。在极端条件下:过于严重的类别不平衡问题可能会导致过拟合,在本小节中,预测器可以什么都不做直接输出0就能达到86%以上的准确率,但是实验表明最终的预测准确率在90%以上,说明该预测期似乎没有出现很严重的过拟合现象,下面的实验也说明了这一点:
Fig 5
是未排序状态下sql执行时间的真实值和预测值对比图,Fig 6
是经过执行时间排序后二者的对比。可以看到预测器给出的预测值(橙色曲线代表的部分)并没有将所有的分类结果给定为0,这说明过拟合现象还不是很严重,然而,也可以发现,预测器给出的预测值大多集中在两个条带上,而在一些峰值上则完全没有给出正确的预测,虽然这些峰值上的数据量较小可能对整体的预测准确率影响不大,但是这也说明了类别不平衡问题会导致预测器忽略掉很多数据的细节,这在某种程度上也是过拟合的表现。最后,我们可以评价一下该模型:
Label accuracy: 0.908
Digtial accuracy: 0.1->91.520% | 0.2->93.655% | 0.3->93.657% | 0.35->93.661%
以上是对sql语句的执行时间预测,可以看到总的类别预测准确率在90%以上,其中有91.52%的测试样本预测执行时间和实际执行时间的差异在0.1以内。