首页> 中国专利> 大规模事务负载生成与数据库隔离级别正确性验证系统及方法

大规模事务负载生成与数据库隔离级别正确性验证系统及方法

摘要

本发明提供了一种大规模事务负载生成与数据库隔离级别正确性验证系统,包括:随机数据库模式生成器、测试数据库生成器、随机事务负载生成器、测试负载执行器、日志分析器;其中,所述随机数据库模式生成器和所述测试数据库生成器服务于随机测试数据库的生成;所述随机测试数据库生成包括:数据库模式的生成和数据库实例的生成;所述随机事务负载生成器和所述测试负载执行器负责随机测试负载的生成和加载;所述日志分析器通过针对异象和异常的检测以及读结果集的正确性验证,给出正确性分析报告;所述正确性验证包括:异象和异常检测、读结果集正确性验证。基于以上系统,本发明还提出了一种大规模事务负载生成与数据库隔离级别正确性验证方法。

著录项

  • 公开/公告号CN112632105A

    专利类型发明专利

  • 公开/公告日2021-04-09

    原文格式PDF

  • 申请/专利权人 华东师范大学;

    申请/专利号CN202011595904.5

  • 发明设计人 张蓉;李可强;李宇明;

    申请日2020-12-29

  • 分类号G06F16/242(20190101);G06F11/36(20060101);

  • 代理机构31319 上海德禾翰通律师事务所;

  • 代理人夏思秋

  • 地址 200241 上海市闵行区东川路500号

  • 入库时间 2023-06-19 10:32:14

说明书

技术领域

本发明属于计算机技术领域,涉及一种大规模事务负载生成与数据库隔离级别正确性验证系统及方法。

背景技术

数据库管理系统作为重要的基础软件,广泛应用于金融、通讯、电商等领域的关键应用中。近年来,互联网的快速发展催生了大量的新型应用。在新应用的驱动下,数据库系统得到了快速的发展。本世纪初兴起了NoSQL数据库,如今NewSQL数据库扮演着越来越重要的角色,目前知名的数据库系统已超过300个[1]。此外,伴随着新硬件的发展,数据库系统的设计有了更多的选择,系统架构也在不断地重构。快速迭代的新系统对数据库系统的质量管理带来了新的挑战。

各种类型的测试是数据库系统质量的重要保证。例如,功能测试可以验证系统功能是否与设计文档一致;性能测试可以验证系统性能是否满足实际应用需求;分布式系统测试可以验证系统在分布式环境下的高可用特性是否符合预期。但由于数据库系统的复杂性和人工测试的高昂代价,目前数据库系统的测试案例是严重不足的,尤其是针对复杂事务负载的测试案例。为解决该问题,测试SQL随机生成器是一个重要尝试。

RAGS[2]是已知最早的测试SQL随机生成器,主要服务于Microsoft SQL Server的测试工作。RAGS可以根据已有测试数据库的Schema信息,生成大量满足SQL语法的随机测试负载,包含Select语句和Update语句。然后RAGS在多个数据库系统中执行测试负载,并通过逐行比对多个数据库系统的返回结果集来判断执行结果的正确性。RAGS中的更新负载不支持高并发下的正确性验证,生成的更新负载也仅是一些单行更新操作。QGEN[3]可以根据一组查询模板快速生成大量可供多客户端性能测试的查询负载,TPC-DS[4]的查询负载便由其生成。用户可以指定查询参数的随机生成策略,比如生成参数值的数据分布。QGEN生成的测试SQL都是基于输入的查询模板,本身不能自动产生新的查询模板,因此难以服务于测试案例的大规模自动化生成。

GARan[5]在生成随机测试案例的过程中,根据测试案例在数据库上的执行反馈,利用遗传算法生成更符合预期的测试案例,提高针对特定数据库模块的测试覆盖率。GARan主要聚焦于数据库的功能测试。TGTSG[6]是为DB 2查询优化器的测试而设计的随机SQL生成器。通过对查询优化器执行轨迹的分析,TGTSG可获得测试SQL的执行反馈,然后利用遗传算法不断迭代以生成触发特定优化规则的测试SQL。

ADUSA[7]在生成随机测试案例的同时,也生成相应的验证结果集,无需利用人工或者已有数据库系统给出验证结果集。ADUSA的数据生成和负载生成都依赖于Alloy[8]工具,但是Alloy的复杂度过高,目前仅能支持小数据表上的测试负载生成。同时ADUSA支持的查询负载类型也无法满足实际测试的需求,比如分组、排序、外连接、like运算符、日期数据类型都不支持。工作[9][10]对ADUSA作了进一步的优化,并将测试SQL的生成、测试数据的生成和验证结果集的生成整合到一个自动化的测试框架之中,然而这两个工作依然存在负载类型支持不足,无法支持大数据集测试的问题。

测试SQL随机生成器[2][3][5][6][7][9][10]可以生成大量符合SQL语法的查询语句,并以此构建大量随机测试案例,对数据库系统进行更充分的测试。然而,对于事务型负载来说,目前还没有相关的测试案例自动化生成技术。通过人工构建事务负载或者利用OLTP评测基准负载是当前的主要测试手段,而这些负载是相对有限的,因此数据库系统对于事务型负载的测试是不充分的,尤其是针对高并发、高冲突的事务负载。事务负载的自动化生成技术以及高压、高冲突事务负载下数据库系统的隔离级别正确性验证是数据库质量管理体系的重要一环,然而目前还没有相关的支撑技术。

现有技术中问题:数据库系统的质量管理是一个系统性的软件工程问题,包括产品的需求分析、技术框架选择、迭代模型和测试等。做好需求分析,把握好产品定位是一个成功软件系统必要的前提,数据库系统也是如此;合适的技术框架选择不仅可以大幅提高产品的开发效率,对于产品的质量、用户友好度以及生态都有重要的影响,数据库系统作为基础软件系统,更是如此;开发模型可以有效管控软件的开发过程,常见的软件开发模型有瀑布模型、增量模型、迭代模型和敏捷开发等。对于数据库系统的开发往往是多种开发模型并存,大的版本控制上采用的可能是迭代模型,每次版本迭代过程中可能又是瀑布模型,而某个功能模块的开发,小组内部可能又是敏捷开发;测试是软件系统质量保证至关重要的手段,数据库系统因为工程庞大、功能复杂、性能要求高,同时与众多生产系统又紧密关联,因此其质量管理具有极高的要求。

在软件系统开发的不同阶段,往往涉及不同类型的测试。对于一个功能单元,甚至是一个类、一个方法,单元测试是保证其实现正确性的重要手段;对于系统多个功能模块的集成,集成测试又是必不可少;而对于整个系统来说,系统测试是质量保障最后的防线。无论是单元测试还是集成测试,数据库系统与其他软件系统并无太大差异,但数据库系统的系统测试却具有很强的独特性。数据库系统的系统测试主要包含功能测试和性能测试;随着分布式数据库的发展,分布式系统测试也得到学术界和工业界的不断重视;数据库系统作为重要的基础支撑系统,其稳定性是用户重要的关注点,因此鲁棒性测试也是不可或缺。但是,上述的功能测试、性能测试、分布式系统测试和鲁棒性测试之间并无明确的界限,鲁棒性测试和性能测试可能都会采用压力测试的手段,分布式系统测试可能就是在分布式环境下验证某个数据库功能正确性的一次功能测试。如何实现高效的数据库系统测试是数据库系统质量管理的重要问题,目前主要的解决方式有自动化测试框架、持续集成以及测试案例的自动化生成,当然这些方式并不是完全并列的,比如持续集成一般也会应用到自动化测试框架。当前,在学术界和工业界对于自动化测试框架和持续集成都有相应的成果和产品[11][12][13][14],但对于测试案例自动化生成的研究还相对匮乏,无法满足生产上的需求。

测试案例的自动化生成技术是为了解决人工构建测试案例代价高昂、测试不充分的问题。人工构建测试案例往往需要先了解待测试系统的实现原理,然后撰写测试观点,再然后构建测试数据、测试负载和理想结果集,最后执行测试负载并验证执行结果的正确性。整个流程需要测试者对数据库系统具有良好的背景知识,甚至还需要测试者具有良好的工程能力,尤其是针对事务型负载的性能测试,因为需要测试者能够提供高并发、高吞吐和一定冲突控制的测试负载。对测试者的高要求以及测试工作的繁琐性导致人工构建测试案例代价高昂,从而进一步导致了测试案例数不足,造成数据库系统测试不充分的问题。

根据负载类型的不同,可以将测试案例的自动化生成分为两大类工作:分析型负载测试案例的自动化生成和事务型负载测试案例的自动化生成。对于第一类工作,已有很多相关的工作。从最早的RAGS[2]可根据已有数据库模式生成随机SQL语句,到GARan[5]可根据测试案例的执行反馈生成更符合预期的测试SQL语句,再到ADUSA[7]利用Alloy[8]工具生成测试SQL语句的理想结果集而无需利用人工或者已有数据库系统来给出理想结果集。分析型负载测试案例的自动化生成已有良好的学术研究工作和工程实践,但事务型负载测试案例的自动化生成因为其高难度而鲜有工作。

事务型负载测试案例的自动化生成主要涉及三个方面的内容,分别是随机测试数据库的生成、随机测试负载的生成和测试执行中的性能指标统计以及执行过程的正确性验证。随机测试数据库的生成主要分为两步,首先生成随机数据库模式,然后根据生成的数据库模式生成测试数据库实例;随机测试负载的生成也主要分为两步,首先基于生成的数据库模式生成随机事务负载,然后向目标数据库系统加载生成的事务负载,并根据测试需求控制请求并发度和数据访问分布;最终关于该测试案例的期望输出是测试执行过程中的性能指标统计以及整个测试执行过程的正确性。

发明内容

本发明将从测试角度来分析如何实现高效的数据库系统质量管理;将对该问题进行剖析并给出解决方案。本发明的目的可概括为:生成大规模事务负载测试案例,对数据库系统的功能和性能进行更充分的测试。关键问题主要有:如何生成全面且可控的随机事务负载;如何验证高压、高冲突事务负载下数据库系统隔离级别的正确性。

自动化测试案例生成技术是数据库系统质量管理的重要手段。目前仅有针对查询负载的测试SQL随机生成器,还没有针对事务型负载测试案例的自动化生成技术,从而导致数据库系统没有经过大规模随机事务负载的充分测试,高速版本迭代下的数据库系统性能与隔离级别正确性都难以得到保证。

本发明设计并实现了一种大规模事务负载生成与数据库隔离级别正确性验证系统(Thor系统),以解决大规模事务负载自动化生成与数据库隔离级别正确性验证问题。Thor系统可以生成海量随机事务负载测试案例,并可对高压、高冲突事务负载下数据库系统的隔离级别正确性进行验证。

为生成全面且可控的模拟事务负载,本发明定义了一组基础数据库操作,然后基于用户配置的随机范围生成大规模随机事务负载。对于生成的事务负载,本发明根据负载中所含事务的复杂程度定义了6种负载类型。为生成高并发、高冲突的模拟负载,Thor在负载加载时提供了3种数据访问分布,分别为均匀分布、高斯分布和Zipfian分布,同时数据访问的候选数据集大小以及访问分布的倾斜程度可以基于用户配置信息进行随机选择。

为实现高并发、高冲突事务负载下数据库隔离级别的正确性验证,本发明提出了基于事务执行历史验证的思路。针对事务负载下数据库系统的正确性验证,一个主要挑战便是验证事务执行历史有无达到指定的隔离级别。在负载执行过程中,Thor会记录整个负载轨迹,对于每一个操作会记录前后两条日志,其执行时间由一个时间区间表示。基于记录的事务执行历史,Thor会进行脏写、脏读、模糊读和幻读4个异象以及写偏异常的检测。对于不同并发控制协议,检测机制会作针对性的调整。最后本发明给出了读结果集的正确性验证算法,可以验证每一个读操作读到的数据版本是否合理。

本发明通过大量实验验证了Thor系统的有效性,并利用Thor系统发现:最近10年来,MySQL的性能在总体上呈下降趋势,下降幅度达到了30%左右,而PostgreSQL数据库的性能在总体上呈上升趋势,性能提升约50%左右;6年前(2013年),PostgreSQL的性能相较MySQL没有任何优势,而如今(2019年)PostgreSQL已在简单事务负载和读负载上具有明显优势,但是MySQL一直在复杂读写事务负载上具有显著的性能优势;Thor系统发现了PostgreSQL在冲突可串行化下存在写偏异常;Thor系统中各组件具有良好的性能,能够快速生成随机事务负载和对数据库隔离级别进行验证。

本发明提出了一种大规模事务负载生成与数据库隔离级别正确性验证系统,包括:随机数据库模式生成器、测试数据库生成器、随机事务负载生成器、测试负载执行器、日志分析器;其中,所述随机数据库模式生成器和所述测试数据库生成器服务于随机测试数据库的生成;所述随机测试数据库生成包括:数据库模式的生成和数据库实例的生成;所述随机事务负载生成器和所述测试负载执行器负责随机测试负载的生成和加载;所述日志分析器通过针对异象和异常的检测以及读结果集的正确性验证,给出正确性分析报告;所述正确性验证包括:异象和异常检测、读结果集正确性验证。

本发明中,所述随机数据库模式生成器的配置项包括:数据库Schema数目、数据表数目、数据表大小、主键中属性数目、复合主键前缀属性组为外键的概率、外键数目、非键值属性数目、属性的可选数据类型以及出现的概率。

本发明中,所述随机数据库模式生成器的配置项进一步包括:decimal数据类型的精度范围设置、字符串属性的长度范围设置。

本发明中,所述数据库实例的生成:数据库Schema含有多张数据表,将数据表主键值域划分成多个不相交的区间,每个区间指派给集群上的一个数据生成线程;数据表中一条记录的生成包括:首先,数据生成线程根据被指派的主键区间,按序递增获取一个主键值;然后,数据生成线程依次调用非主键属性的属性生成器并传入当前记录的主键值,每个属性生成器的输出即为该条记录相应属性的生成值;最后数据生成线程将主键值以及非主键属性的生成值组装成一条记录并异步写入文本发明件。

本发明中,负载生成的机制配置项包括:针对每个Schema生成的负载数、负载中事务数直方图、事务中事务块数直方图、事务块具体化概率表、主动回滚点概率。

本发明中,所述负载生成的机制的配置项进一步包括:分支和循环结构中操作数以及循环执行次数的设置,范围读和范围写的主键范围大小设置,读操作为Select forupdate形式的概率设置。

本发明还提出了一种大规模事务负载生成与数据库隔离级别正确性验证方法,所述方法包括:

通过抽象基础数据库操作,然后利用基础数据库操作的随机组合生成测试负载,并在加载测试负载时控制请求并发度和数据访问分布以模拟不同规模和不同冲突强度的应用负载;在负载的加载过程中,监控器会对性能指标进行统计并输出,包括吞吐、时延、死锁情况;测试负载在加载过程中会记录执行日志,然后日志分析器通过针对异象和异常检测以及读结果集正确性验证,最终给出正确性分析报告。

本发明中,所述基础数据库操作包括:包括9个单SQL语句基础操作和2个多SQL语句基础操作;所述单SQL语句基础操作包括基于主键的单点读、基于主键的单点写、基于主键的范围读、基于主键的范围写、基于外键的单点读、基于外键的单点写、基于外键的复杂读、基于非键值属性的单点读、基于非键值属性的复杂读。

本发明中,所述异象和异常检测:在测试线程中通过打印日志的方式来记录整个负载轨迹;对操作日志进行增量排序;将日志根据测试线程ID进行分组,舍弃执行失败的事务日志;每个测试线程ID都对应一个链表,基于该数据结构,异象检测包括以下步骤:

步骤1:在所有测试线程的链表中挑选一个开始时间最小的操作;如果挑选出的操作为事务提交操作,那么进入步骤3,否则进入步骤2;

步骤2:针对挑选的操作,遍历在其前完成的操作,依次进行异象检测,检测完后返回第一步继续挑选下一个操作

步骤3:当处理到一个事务的提交操作时,表明该事务对于后续操作都不再是正在执行的事务,因此无需对其操作进行异象检测,故该事务的操作日志都可从链表中删除;针对已处理事务日志的删除,可有效控制内存的使用。

本发明中,进一步包括:利用模糊读的检测信息来进一步检测写偏;在异象检测过程中,会维护当前正在运行事务的模糊读异象信息,当在检测过程中发现模糊读异象时,便触发一次写偏异常的检测。

本发明中,所述读结果集正确性验证包括:

第一步:挑选出开始时间最小的操作后,将BTime设置为该操作的开始时间;

第二步:如果当前操作是一个读操作,将其保存到待验证列表RList中;

第三步:在删除提交事务日志的同时,将所有写操作更新的记录维护到增量数据中;

第四步:遍历待验证列表RList中的所有读操作,如果一个读操作的结束时间小于BTime,则对其结果集进行验证并将其从RList中移出;只有当读操作的结束时间小于BTime才能保证该操作在验证中能够看到所有可能的数据版本。

针对大规模事务负载生成与执行正确性验证问题,本发明设计并实现了Thor系统。在Thor系统中,为生成全面且可控的随机事务负载,定义了一组基础数据库操作和多种数据访问分布,然后在用户指定的随机空间生成大规模事务负载测试案例。为实现高压、高冲突事务负载下数据库系统的正确性验证,Thor在负载加载过程中记录了整个事务执行历史,然后基于事务执行历史提出了高效的异象和异常检测算法以及读结果集的正确性验证算法,实现了数据库隔离级别的有效验证。实验结果表明Thor能够对数据库系统的性能和隔离级别正确性进行更充分的测试。

附图说明

图1是本发明Thor系统架构图。

图2是本发明确定性随机属性生成器示意图。

图3是本发明负载轨迹示例。

图4是本发明异象和异常检测示例(R和W分别代表读和写)。

图5是本发明增量数据示例。

图6是本发明MySQL吞吐量变化趋势示意图。

图7是本发明MySQL时延变化趋势示意图。

图8是本发明PostgreSQL吞吐量变化趋势示意图。

图9是本发明PostgreSQL时延变化趋势示意图。

图10是本发明2013年的性能对比情况示意图。

图11是本发明2019年的性能对比情况示意图。

图12是本发明数据库模式生成时间示意图。

图13是本发明事务负载生成时间示意图。

图14是本发明隔离级别日志分析时间示意图。

图15是本发明日志分析时的内存消耗示意图。

具体实施方式

结合以下具体实施例和附图,对发明作进一步的详细说明。实施本发明的过程、条件、实验方法等,除以下专门提及的内容之外,均为本领域的普遍知识和公知常识,本发明没有特别限制内容。

本发明的基本架构:为了有效解决事务型负载测试案例的自动化生成问题,本发明设计并实现了Thor系统,图1为其系统架构图。从图中可知,Thor主要包含五个功能模块,其中随机数据库模式生成器和测试数据库生成器服务于随机测试数据库的生成;随机事务负载生成器和测试负载执行器负责随机测试负载的生成和加载。本发明通过抽象基础数据库操作,然后利用基础数据库操作的随机组合生成大量测试负载,并在加载测试负载时控制请求并发度和数据访问分布以模拟不同规模和不同冲突强度的应用负载;在负载的加载过程中,监控器会对吞吐、时延、死锁情况等性能指标进行统计并输出。测试负载在加载过程中会记录执行日志,然后日志分析器通过针对异象和异常的检测以及读结果集的正确性验证,最终给出正确性分析报告。

Thor生成的随机数据库模式以及相应的事务负载可以保存在测试案例库中以作回归测试和对比测试之用。这里选择只保存数据库模式而非保存测试数据库实例是因为测试数据库可能需要占用巨大的存储空间,使得测试案例库的维护和管理困难。比如,当需要拷贝测试案例库到另一个数据中心测试时,占用巨大存储空间的测试数据库会使整个传输过程异常漫长。此外,为了实现测试过程的可重复性以及执行结果的可验证性,Thor中基于数据库模式的测试数据生成是确定的,即同一个测试案例多次执行中生成的测试数据库是完全相同的。本发明中,随机测试数据库生成是测试案例自动化生成的基础,同时其生成机制与后续的随机事务负载生成以及执行结果正确性验证具有紧密的关联关系。

其中,数据库模式的生成:数据库模式,即数据库Schema,是数据库中所有数据逻辑结构和特征的描述,往往由一组数据表(也称为关系)组成。测试数据库的Schema在一定程度上决定了该测试数据库上可能出现的事务负载类型,因此为了能够生成更加全面的随机事务负载,以实现更充分的数据库系统测试,Thor生成的数据库Schema要求类型丰富,能够覆盖主流的数据库应用。数据库Schema常见的特征有数据表个数、数据表属性的个数以及数据类型、主键是单属性主键还是多属性复合主键、外键个数、字符串属性的长度等等。因为这样的特征很多、范围太广,漫无目的随机生成的数据库Schema可能并没有实际意义,或者说并不是常见的,而且可能因为生成的Schema过多而导致测试周期难以接受。因此,需要列出关键的数据库Schema特征,以及设置这些特征的随机空间,以生成能够代表主流应用的随机数据库Schema。需要注意的是本发明生成的随机测试负载旨在测试数据库系统在主流事务负载下的性能以及正确性,这里的正确性主要是指并发控制的正确性,边界测试、表达式计算正确性测试等不是本发明的关注点。

为了实现上述目的,Thor中随机数据库模式生成器的主要配置项列出如下,同时还给了示例配置以及相关说明。

数据库Schema数目:100。生成100个随机数据库Schema。

数据表数目直方图:1,5,0.3;4,20,0.6;21,50,0.1。一个数据库Schema具有1至5个数据表的概率为0.3,具有4至20个数据表的概率为0.6,具有21至50个数据表的概率为0.1。

数据表大小直方图:10

主键中属性数目直方图:1,1,0.7;2,4,0.3。主键为单属性主键的概率为0.7,主键为2至4个属性构成的复合主键的概率为0.3。

复合主键前缀属性组为外键的概率:0.9。假设复合主键属性组为[pk_col1,pk_col2,pk_col3],其前缀属性组[pk_col1,pk_col2]为外键的概率为0.9。

外键数目直方图:0,1,0.4;2,4,0.6。一个数据表具有0至1个外键的概率为0.4,具有2至4个外键的概率为0.6。

非键值属性数目直方图:1,5,0.3;6,20,0.5;21,50,0.2。非键值属性指的是非主键和外键中的属性。该配置项用来随机确定非键值属性的数目。

属性的可选数据类型以及出现的概率:int,0.2;long,0.2;varchar,0.2;decimal,0.2;float,0.05;double,0.05;datetime,0.05;bool,0.05。该配置项用来随机确定非键值属性的数据类型,主键和外键属性的数据类型目前都为整型。

除了上述配置项,还有decimal数据类型的精度范围设置,字符串属性的长度范围设置等。根据配置项信息可以生成一组随机数据库Schema,但这样的数据库Schema还无法满足测试需求。为了保证测试过程的可重复性以及执行结果的可验证性,要求基于Schema的测试数据库实例生成是确定的。因为当数据库实例的生成是非确定的,每次基于相同Schema生成的测试数据库可能存在较大差异,从而难以保证多次测试结果的一致性;同时如果测试数据库的数据是非确定的,测试负载的执行结果难以验证其正确性,因为理想执行结果无从得知。针对每个数据表而言,主键可以按序生成,而其他非主键属性可以依据主键值确定性生成,但同时需要保证数据的随机性。因此,Thor为非主键属性构建了确定性随机属性生成器,其中确定性指的是针对一个特定的主键值,其生成的属性值是确定的,随机指该属性生成器生成出来的所有属性数据具有随机性。图2为确定性随机属性生成器的示意图。需要注意的是传统意义上的数据库Schema是不包含数据表大小以及属性生成器信息的,本发明这里对数据库Schema的含义作了拓展。

从图2中可知,属性生成器中含有一组属性生成函数,这些生成函数目前都是一次或者二次的多项式,多项式系数的选择会综合考虑数据表的大小和属性的阈值。单个属性采用多个属性生成函数是为了保证生成数据的随机性。由于主键可能是由多个属性构成的复合主键,属性生成器首先会将输入的主键值转化成单个数值,即pk_value。然后根据pk_value的值选择一个属性生成函数,并以pk_value作为生成函数的输入参数,通过计算可得数值nume_value。数值转化器会根据当前属性的数据类型,将数值nume_value转化成最终的属性值。如果当前属性就是数值类型,如int、double和decimal,只需将数值nume_value稍作处理即可作为属性值。比如属性是整形,只需对nume_value取整即可;若为decimal,仅需根据属性精度对小数位进行截取。当属性为字符串类型时,数值转化器中含有预先生成好的N个种子字符串,此时数值转化器会先根据nume_value的值选择一个种子字符串,比如第(nume_value%N)个种子字符串,然后将nume_value与选择的种子字符串连接后作为属性生成值。该方法既可保证数据生成的确定性,又不会消耗大量的存储资源。此外,针对外键属性,最终生成的属性值需要对参照主键相应属性阈值进行取模。

至此,数据库Schema已生成完成。可知数据库Schema是测试数据库的逻辑表示,存储空间占用小,易于测试案例库的存储与管理。同时,Thor引入了确定性随机属性生成器,可有效支持测试数据库的确定性生成。

本发明数据库实例的生成:由于测试需求,往往指定测试数据库具有庞大的数据量,因此测试数据库实例的并行生成是对Thor的基本要求。在数据库Schema生成之后,会依据Schema生成相应的测试数据库实例。基于不同数据库Schema的数据生成是相互独立的,因此首先可以实现Schema级别的并行数据生成。在一个数据库Schema中,一般会含有多张数据表,虽然数据表之间可能存在主外键参照关系,但是外键的生成机制并不依赖参照主键的生成,所以不同数据表的生成是可以完全并行的。对于同一个数据表,因为每条记录的生成是独立的,所以可以将数据表主键值域划分成多个不相交的区间,每个区间指派给集群上的一个数据生成线程,从而实现单个数据表的并行数据生成。

数据表中一条记录的生成主要分为三步:首先,数据生成线程根据被指派的主键区间,按序递增获取一个主键值;然后,数据生成线程依次调用非主键属性的属性生成器并传入当前记录的主键值,每个属性生成器的输出即为该条记录相应属性的生成值;最后数据生成线程将主键值以及非主键属性的生成值组装成一条记录并异步写入文本发明件。可以看出,记录的生成是流式的,生成一条记录就可以写出一条记录,不需要维护中间状态,内存占用小。同时,为了避免多线程在写文件上的冲突,Thor中每个数据生成线程都会有独立的输出文件。待测试数据库实例完全生成之后,Thor可利用目标数据库系统的数据导入功能(如MySQL的LOAD命令、PostgreSQL的COPY命令、Derby的SYSCS_IMPORT_DATA命令等)按照数据表的参照拓扑序依次将数据表导入。总而言之,测试数据库实例可以实现多节点多线程完全并行的数据生成,以及利用流式的记录生成机制实现了数据生成过程的低内存消耗。

本发明随机事务负载生成:基于已有数据库Schema的随机事务负载生成机制。首先,通过对主流OLTP评测基准负载的调研与抽象,给出了事务负载中常见的基础数据库操作。然后,提出了一个基于基础数据库操作随机组合的随机事务负载生成机制。

其中,基础数据库操作:事务负载一般由多个事务构成,一个事务往往由多条SQL语句(数据库操作)构成,同时可能还包含分支和循环控制结构。为了能够生成大量类型多样的随机事务负载,本发明对主流OLTP评测基准(如TPC-C[15]、Smallbank[16]和TATP[17])的负载进行了调研和抽象,总结了常见基础数据库操作,通过基于基础数据库操作的随机组合以生成随机事务负载。表1列出了所有单SQL语句的基础数据库操作。

表1:单SQL语句基础数据库操作

表1总结的9个基础数据库操作都是单条SQL语句,在实际应用以及评测基准的负载中还发现有些SQL语句经常一起出现,语句之间还有一定的关联关系,该类型的基础数据库操作总结如下:

基于单条记录的先读后写:该操作序列包含两条SQL语句,一条为基于主键的单点读,一条为基于主键的单点写。两条语句针对的是同一条记录,即选择谓词中的主键值相同。

基于两条参照记录的写:该操作序列包含两条SQL语句,都是基于主键的单点写。两条语句针对的记录来自两个不同的数据表,这两个数据表之间存在主外键参照关系,并且两条语句更新的记录也存在主外键参照关系。

至此,已经列出了所有的基础数据库操作,包括9个单SQL语句基础操作和2个多SQL语句基础操作。用户可自定义基础数据库操作添加到Thor系统中。随机事务将由这些基础数据库操作以及分支和循环控制结构组合而成。

本发明负载生成机制:通过合理地设置配置项信息,可令Thor在一个期望的负载空间中生成随机事务负载,使得生成的测试负载能够表示主流应用负载,避免与主流应用负载迥然相异。下面将列出主要配置项以及给出示例说明。

针对每个Schema生成的负载数:10。针对一个数据库Schema生成10个测试负载。因为测试数据库实例的生成与导入是比较耗时的,在同一个库上进行多次测试(每次测试的负载是不同的)可以有效提高测试效率。

负载中事务数直方图:1,5,0.5;6,10,0.3;11,30,0.2。负载中含有1至5个事务的概率为0.5,含有6至10个事务的概率为0.3,含有11至30个事务的概率为0.2。

事务中事务块数直方图:1,3,0.6;4,10,0.3;11,20,0.1。事务块可以是基础数据库操作也可以是分支和循环逻辑结构体。根据示例配置,一个事务中含有的事务块数为1至3个的概率为0.6,为4至10个的概率为0.3,为11至20个的概率为0.1。事务中的事务块数不等于SQL数,因为一个基础数据库操作可能是两条SQL语句,同时分支和循环结构中往往也包含多条SQL语句。

事务块具体化概率表:11个基础数据库操作出现的概率以及分支和循环结构出现的概率。依据该概率表可以随机确定事务中每个事务块具体为哪个基础数据库操作或者为某个结构体(分支或循环)。

主动回滚点概率:0.1,回滚概率直方图:0.001,0.01,0.8;0.01,0.1,0.2。在实际应用负载的事务中,存在因为条件判断不满足而主动回滚事务的情况,将这样的条件判断位置称为主动回滚点。根据示例配置,一个事务块执行后为主动回滚点的概率为0.1,同时其主动回滚事务的概率80%在0.001至0.01之间,20%在0.01至0.1之间。

除了上述配置项,还有分支和循环结构中操作数以及循环执行次数的设置,范围读和范围写的主键范围大小设置,读操作为Select for update形式的概率设置等。根据配置项信息,Thor通过随机组合便可生成指定数目的随机事务负载。

在生成随机事务负载之后,可以根据事务和负载的复杂程度对其进行分类。对于一个只读事务,若其SQL数小于等于5且读影响行数小于等于50,那么称之为简单只读事务,否则为长只读事务;对于一个读写事务,若其写影响行数大于10,或写影响行数大于5且读影响行数大于50,或写影响行数大于2且读影响行数大于100都称之为长读写事务,否则为简单读写事务。一个负载中往往包含多个事务,依据负载中事务的复杂程度对负载进行分类。对于一个仅包含只读事务的负载,若负载中所有事务都为简单只读事务,那么该负载为简单只读负载;若负载中长只读事务的比例小于50%,那么该负载为较复杂只读负载;否则为复杂只读负载。对于一个读写负载,若负载中所有事务都为简单只读事务和简单读写事务,那么该负载为简单读写负载;若负载中长只读事务和长读写事务的比例和小于50%,那么该负载为较复杂读写负载;否则为复杂读写负载。当前的事务分类和负载分类是基于经验设定的,Thor的使用者可以根据需要进行调整。对事务和负载进行分类,目的是为了使评测结果包含更丰富的信息,比如可以知道系统在哪类负载上性能有提升,在哪类负载上性能有下降,而不仅只有一个总体上的性能数据。

Thor在负载加载时提供了3种数据访问分布,即均匀分布、高斯分布和Zipfian分布,可由用户配置选择。同时对于高斯分布和Zipfian分布用户可以设置相应的倾斜程度。针对每种数据访问分布,用户都可以设定候选数据集的大小,以控制访问数据的范围。这个设定是针对数据表的,例如当设定为105时,即表示每个数据表上最多有105个记录会被访问。该设置的目的是为了控制更新数据量的大小,服务于读结果集的验证机制。此外,在负载加载时,用户还可以设置是否预编译执行、测试并发度、客户端隔离级别、每个测试案例的预热时间等。

本发明隔离级别正确性验证:现有工作[2][7][10]都只能针对分析型负载的执行正确性进行验证。查询负载执行的正确性就是指返回的结果集是否正确,常见的验证方式是利用另一个正确的数据库系统来生成理想结果集。但对于事务型负载,尤其是高并发、高冲突的事务负载,数据库中冲突事务的执行顺序是无法预知的,现有工作还没有可行的正确性验证方案。目前,事务负载的正确性验证都只能在简单负载下或者低并发下由人工开展,高压、高冲突的复杂事务负载无法得到有效验证。事务负载的执行正确性主要指事务在执行过程中,数据库系统的ACID有无得到保证。而其中的难点便是验证高压、高冲突事务负载下数据库系统的隔离级别有没有达到。根据相关理论[18][19],隔离级别的语义为数据库通过并发控制杜绝冲突负载下出现各类异象和异常。基于此,本发明隔离级别正确性验证主要思路为:首先,在数据库执行随机事务负载的过程中记录整个负载轨迹;然后,基于负载轨迹(事务执行历史)分析有无出现各类异象和异常,并据此判断当前数据库系统有无达到指定的隔离级别。但是对于多版本数据库来说,根据模糊读和幻读的语义,基于事务执行历史是难以对其进行检测的,因此进一步对事务中所有读操作的结果集正确性进行了验证,以弥补上述方式的不足。下面详细说明异象和异常检测以及读结果集正确性验证。

本发明异象和异常检测:在工作[18]中,Berenson等人详细阐述了各个数据库隔离级别允许出现的异象和异常。目前主流数据库系统的隔离级别主要有读未提交、读已提交、可重复读、快照隔离和冲突可串行化。通过观察是否具有脏写、脏读、模糊读和幻读异象以及写偏异常便可明确区分上述5个隔离级别,因此本发明在当前Thor系统中实现了上述4个异象和1个异常的检测。其他异象和异常的检测机制类似。

为实现异象和异常的检测,本发明在测试线程中通过打印日志的方式来记录整个负载轨迹,即事务执行历史。Thor系统中随机负载是通过JDBC接口加载的,并且每个测试线程都建立有独立的数据库连接。本发明在执行每一条SQL操作的前后都会打印一条日志,在提交事务前后也会各打印一条日志。每一条日志中都会包含当前测试线程的ID、日志打印时的系统时间、日志类型的标识符,日志中还会标识这是在操作执行前打印的还是在操作执行完成后打印的。图3展示了一段真实负载轨迹,图中标出的第一条日志是191测试线程在执行一个基于外键的单点读操作前打印的,图中标出的后两条日志由194测试线程分别打印于提交事务的前后。日志中除了上述基本信息还包含过滤条件、返回结果集等必要信息以用于异象和异常检测以及读结果集的正确性验证。虽然在测试客户端无法知道每个SQL操作在数据库系统中的精确执行时间,但是可以明确的是真实执行时间必然在该操作前后两条日志的打印时间之间,将利用该执行时间区间来进行后面的异象和异常检测。

由于日志是由多个测试线程并行输出到日志文件中(利用的是log4j日志组件),所以输出的日志可能并不是完全时间有序的,为使后面的检测更加高效,首先需要对操作日志进行排序。日志文件有这样两个特征:日志量可能很大,如果对所有日志进行完全排序,代价难以接受;日志文件虽然可能有乱序,但是乱序幅度一般很小。基于这样的前提,提出了日志增量排序的方案,具体为:每次仅对当前N条日志进行排序,排完序后,将前N-M条日志作为有序日志输出,剩下的M条日志与从文件中接着读上来的N-M条日志继续一起排序,直至将文件中的所有日志排序完成。N和M的大小取决于日志乱序容忍程度和排序性能的权衡。注意,在输出有序日志时,需要与上一次输出日志做有序性验证,若当前输出中最小日志时间不大于等于上一次输出中最大日志时间(越往前的日志时间越小),则需调整M为更大的数值。

在拿到有序日志后,将日志根据测试线程ID进行分组,具体如图4所示。针对执行失败的事务日志,无需对其进行异象和异常检测,故这些日志将从负载轨迹中舍弃。在图4中,每个测试线程ID都对应一个链表,链表中每个节点存储了一个操作的前后两条日志。日志是分批加载到链表中的,以确保不会占用过多内存,当链表中的日志被处理掉一部分时,再继续加载日志到链表中。基于图4中的数据结构,异象检测算法主要分为下面三个步骤:

第一步:在所有测试线程的链表中挑选一个开始时间最小的操作。例如在图4中,开始时间最小的操作应为R(9),这是一个针对数据项9的读操作。如果挑选出的操作为事务提交操作,那么进入第三步处理,否则进入第二步处理。

第二步:针对第一步挑选的操作,遍历在其前完成的操作(结束时间小于其开始时间),依次进行异象检测,检测完后返回第一步继续挑选下一个操作。假设当前操作为R(9),其前面没有其他操作,故无需处理;然后当前操作更新为R(5),依然无需处理;接着当前操作更新为W(7),此时R(9)的结束时间先于W(7)的开始时间,但由于两个操作读写的数据集不冲突,故未出现异象;然后当前操作更新为W(9),此时发现W(9)使R(9)成为模糊读;处理到R(7)时,发现其前面有一个W(7),故R(7)是一个脏读。

第三步:当处理到一个事务的提交操作时,表明该事务对于后续操作都不再是正在执行的事务,因此无需对其操作进行异象检测,故该事务的操作日志都可从链表中删除。针对已处理事务日志的删除,可有效控制内存的使用。

在图4中,当处理到R(6)时,发现其前面有W(6),但此时不能判定R(6)为脏读,因为R(6)与W(6)所属事务的提交操作在时间区间上有重叠,W(6)所属事务可能在R(6)之前就已完成提交。因此,在第二步中还需判断待检测操作的事务提交开始时间是否在当前操作结束时间之后,如果不满足则无需检测异象(因为该操作所属事务可能已完成提交)。此外,图4中的R(6to 8)、W(8)序列为幻读异象,W(2)、W(2)’序列为脏写异象。

上面已经完成了脏写、脏读、模糊读和幻读4个异象的检测,但还没有实现写偏异常的检测。写偏异常是指数据库在执行事务时出现了这样的执行序列:R1(x)…R2(y)…W1(y)…W2(x)…(C1 and C2 occur),其中两个读的相互顺序无所谓,两个写的相互顺序也无所谓,事务的提交顺序也不影响,但必须要求两个读在两个写之前。通过观察这个序列可以知道,写偏其实就是两个事务中的写相互导致对方事务中的读成为模糊读,并且涉及的读操作都在写操作之前。因此,可以利用模糊读的检测信息来进一步检测写偏。在上述异象检测过程中,会维护当前正在运行事务的模糊读异象信息,当在检测过程中发现模糊读异象时,便会触发一次写偏异常的检测。在图4中,R(3)、R(1)、W(1)、W(3)操作序列便是写偏异常。

复杂度分析:异象检测算法第一步的复杂度为O(K),其中K为测试线程的个数;第二步的复杂度为O((K-1)*L),即为需要检测异象的操作数,其中L为每个事务中的平均操作数,K-1为正在运行的事务数(不含自身事务);第三步的复杂度为O(L)。因此整个异象检测算法的复杂度为O(K*L),因为在实际评测中,K和L往往都是比较小的数值,一般为两位数,故异象检测算法是高效的。写偏检测是由模糊读异象触发的,检测复杂度也仅与涉及的两个事务当前出现的模糊读异象个数相关,复杂度远低于异象检测。

关于多版本数据库的讨论:上述异象和异常检测机制是针对基于单版本和锁协议实现的数据库设计的,当数据库是基于多版本的并发控制协议时,这里有一定的差异。由于目前主流数据库并发控制都是基于锁协议实现的,关于乐观并发控制协议的情况将在未来的工作中讨论。首先,脏写异象的检测对于目前主流数据库都是适用的,因为主流多版本数据库也是加长写锁的;当前脏读异象是指针对同一个数据项,两个正在运行的事务发生了先写后读的操作序列,这在多版本数据库中是允许发生的,但前提是后面的读不能读到前面未提交的写。因此,针对多版本数据库,脏读异象检测还需加一个读返回集的正确性验证,这在章节4.4.2中会给出解决方案;根据模糊读和幻读异象的语义,其在多版本并发控制下,根据事务执行历史是无法检测的,因此本发明进一步对读操作的结果集正确性进行验证,以对此不足作出补充;写偏是一种异常,无论对于单版本还是多版本、亦或是锁协议还是乐观并发控制协议,检测方式都一样。

本发明读结果集正确性验证:当数据库在读已提交或者更高的隔离级别上运行时,每一个读操作能且仅能看到在其前最近的提交数据。读结果集的正确性即指该读操作是否读到了一个合适版本的数据。本发明将对负载轨迹中所有读操作的返回结果集进行正确性验证,主要思路为:在异象检测的过程中,会在内存中维护一份增量数据以保存所有提交事务更新后的记录,相对来说未更新的所有数据被称为静态数据;然后对于每一个读操作,根据其时间区间先去增量数据中检查读到的数据版本是否合理。如果该操作读的数据没有被更新过,或者增量数据中的版本可能是后面提交事务更新的,继续利用静态数据来验证读结果集是否正确。静态数据可以利用主键值和属性生成器计算出来。下面将详细说明增量数据的维护机制和读结果集的验证算法。

增量数据是用两层哈希表维护的,外面一层哈希表的键为数据表名,里面一层哈希表的键为元组主键,对应的值为一个链表。链表中每个元素为更新后的记录值并附有所属事务的提交时间区间,链表中的元素按事务提交开始时间逆序排序。图5是一个增量数据的示例,从图中可以看到数据表T1中主键值为8的记录维护了3个版本,其中最近提交的版本为tuple1。增量数据的维护时间点位于异象检测算法的第三步,在删除提交事务日志的同时,所有写操作更新的记录会被维护到增量数据中。针对每一个更新操作,首先利用主键信息和属性生成器计算出相应记录的静态数据,然后将更新操作作用在生成的静态数据上,最后将更新后的记录以及当前事务的提交时间区间一起维护到增量数据中。

对于那些不会被用于结果集验证的数据版本可从增量数据中删除,以控制内存使用和提高验证效率。如果是针对单版本数据库的测试,增量数据中每条记录都只需维护一个最新的版本即可;如果是针对多版本数据库的测试,验证过程中会记录当前还未完成验证的读操作的最小时间戳,在这时间之前的版本只需维护一个即可,其他都可删除。旧版本的删除采用的是Lazy机制,每当针对某个主键值维护一个新版本时,会检查链表中的其他旧版本是否可被清除掉。需要注意的是,单个记录的两个版本在提交时间区间上是可能存在重叠的,例如图5中主键7对应的前两个版本,此时这两个版本无法知道其在数据库中的先后关系,故两者要么同时保留,要么同时删除。由于数据访问分布中控制了候选主键值集合的大小,即可能被更新的记录数是一定的,而增量数据的大小与被更新的记录数是线性相关的,因此增量数据的大小是受控的,仅需占用很小的内存空间。

下面将对异象检测算法进行扩充以实现读结果集的正确性验证。原来异象检测算法分为三步,在已有内容保持不动的情况下,在其前三步添加了部分内容,并新增了第四步,具体如下:

第一步:挑选出开始时间最小的操作后,将BTime设置为该操作的开始时间;

第二步:如果当前操作是一个读操作,将其保存到待验证列表RList中;

第三步:在删除提交事务日志的同时,将所有写操作更新的记录维护到增量数据中;

第四步:遍历待验证列表RList中的所有读操作,如果一个读操作的结束时间小于BTime,则对其结果集进行验证并将其从RList中移出。只有当读操作的结束时间小于BTime才能保证该操作在验证中能够看到所有可能的数据版本。

如果一个读操作是基于主键的单点读或者范围读,那么可以针对涉及的每个主键值进行正确性验证。如果是基于外键的或者非键值属性的读操作,那么只能根据返回集中的主键值来验证。对于每一个主键值,首先在增量数据中查询相应记录是否被更新过。如果该记录没有被更新过,便根据主键值和属性生成器生成该记录的静态数据并与返回结果进行对比验证;如果该记录在增量数据中有更新后的版本,需根据当前读操作的执行时间区间判定哪些数据版本可能会被读到,返回结果只要是这些版本中的任意一个都算验证通过。需要注意的是,如果无法确定读操作读到的数据必然位于增量数据中,还需将静态数据作为一种可能情况来验证。比如,增量数据中的最老版本与当前读操作在时间区间上有重叠,表明该版本可能是在读操作之后提交的,因此当前读操作读到的可能是静态数据。

关于快照隔离级别:在快照隔离级别(或可串行化的快照隔离级别)下,数据库中所有读操作的读时间被设定为事务开始时间,因此在读结果集验证时不能使用读操作自身的时间区间来验证,而应使用读操作所属事务中第一个操作的时间区间(即事务开始时间)进行验证。对于读已提交、可重复读和冲突可串行化三个隔离级别,读操作在验证时应使用该操作自身的时间区间。

实施例

本实施例首先利用大规模随机事务负载对MySQL[20]和PostgreSQL[21]的多个版本进行性能评测,以观察在版本更迭下MySQL和PostgreSQL各自的性能变化;然后分别对比了在2013年和2019年MySQL和PostgreSQL的事务处理性能;接着对MySQL、PostgreSQL和Derby[22]三个数据库系统的隔离级别进行了正确性测试;最后对Thor系统各模块的性能进行了测试。

实施环境

实验平台:所有实验共涉及6台服务器,每个服务器配备了两个2.1GHz、8核心的Intel Xeon Silver 4100处理器,单台服务器同时可运行32个线程;每个服务器拥有120GB的内存,4TB的硬盘(RAID-5),磁盘阵列上配有4GB缓存;服务器之间用万兆以太网连接。实验中测试数据库系统选择的是目前使用最广泛的开源数据库MySQL和PostgreSQL,以及单版本数据库Derby。

实验负载:实验中首先随机生成10个数据库模式,然后针对每个数据库模式随机生成10个读写事务负载和10个只读事务负载,因此评测负载共包括100个随机读写事务负载和100个只读事务负载。每个随机数据库模式平均含有10.25个数据表,每个数据表平均含有12个非键值属性和1.75个外键,主键平均含有1.45个主键属性,属性的数据类型可能为整型、字符型、精确小数类型、浮点型、日期类型和布尔型。每个随机负载平均含有9个事务,事务中的操作可能为章节4.3.1中的任意基础数据库操作。性能评测和隔离级别正确性测试的随机负载是不一样的(生成时配置信息不一样),前者相对来说更具有一般性,而后者则更复杂、冲突更高。隔离级别正确性测试仅需要100个读写事务负载,无需测试只读事务负载。实验中,每个负载运行20秒,即性能评测共运行200*20=4000秒,隔离级别正确性测试共运行100*20=2000秒。性能测试负载都是以预编译的方式执行,隔离级别测试负载有80%的操作以预编译的方式执行。

实验设置:下面将给出一些关键实验设置信息。针对性能评测,在随机读写事务负载生成时,9个单SQL语句基础操作、2个多SQL语句基础操作以及分支和循环结构的比例分别为:0.25,0.27,0.05,0.03,0.05,0.02,0.03,0.05,0.05,0.05,0.05,0.06,0.04(顺序与章节4.3.1中的介绍顺序一致)。针对隔离级别正确性测试,在随机事务负载生成时,9个单SQL语句基础操作的比例分别为:0.15,0.05,0.15,0.05,0.1,0,0.1,0.1,0.1;其他比例与性能评测读写负载生成时一致。在日志分析时,日志排序线程数设置为3,每次日志排序包含的日志数N为20000,留转日志数M为2000。所有针对数据库的性能评测,数据库的隔离级别设置为读已提交,测试并发度为50。

实验结果及分析

MySQL在版本更迭下的性能变化

为了评测MySQL数据库在版本更迭下的性能变化,本实施例选择了目前使用最广泛的三个大版本,即5.5、5.6和5.7。针对每个大版本,选择两个小版本,分别为第一个和最后一个发布的稳定版本。实验中选择的最老版本为5.5.8,发布于2010年12月;最新版本为5.7.27,发布于2019年7月。图6展示了MySQL的吞吐量随着版本更迭的变化趋势,图7展示了相应的事务时延变化趋势。测试负载有两组,分别为100个读写事务负载和100个只读事务负载。图中数据是以版本5.5.8的性能数据为基线而计算出的相对性能比值。相对性能比值的计算公式为

PostgreSQL在版本更迭下的性能变化

针对PostgreSQL数据库,本实施例选择了应用比较广泛的5个版本,其中最早的版本8.4.11发布于2012年2月,最新的版本11.0发布于2018年12月。图8和图9分别展示了PostgreSQL的吞吐量和事务时延随着版本更迭的变化趋势。测试负载为100个读写事务负载和100个只读事务负载。图中展示的数据为基于版本8.4.11的相对性能比值,计算方式与图6相同。实验结果表明,PostgreSQL数据库的性能在整体上呈上升趋势,版本11.0的读写事务负载吞吐量相比版本8.4.11上升了54.9%,只读事务负载吞吐量上升了36%,事务时延相应有大幅下降。由图中数据可知,版本9.6有着巨大的性能提升,这与其发布文档[23]是相符的,但是版本10.0相比版本9.6性能有大幅下降,这并未在其发布文档[24]中有任何提及。综上所述,PostgreSQL数据库的性能在开源社区中得到了良好的发展和维护,但依然存在不足,需要大量随机事务负载来监控版本迭代下的性能变化。

MySQL与PostgreSQL的性能对比

MySQL与PostgreSQL的对比,尤其是两者的性能对比,一直是业内比较关心的话题,但很少有基于大规模事务负载评测的量化结论,大家一般都认为PostgreSQL比MySQL性能更好。为此,本实施例做了两组性能对比实验,分别针对2013年和2019年两个数据库系统的主流版本。测试负载为100个读写事务负载和100个只读事务负载。图10展示了在2013年时两个数据库的性能对比情况,MySQL选择的版本是5.6.10,PostgreSQL选择的版本是8.4.11。以MySQL的吞吐量为基线,计算PostgreSQL的相对吞吐量比值。图10中有8个吞吐量比值,其中4个针对读写事务负载,另4个针对只读事务负载。针对每类事务负载,分别有综合吞吐量比值、简单负载吞吐量比值、较复杂负载吞吐量比值和复杂负载吞吐量比值。由图中数据可知,在2013年时,PostgreSQL相对MySQL在总体上没有性能优势,并且针对非简单事务负载PostgreSQL反而有巨大的性能劣势,吞吐量还不到MySQL的一半。图11展示了在2019年时两个数据库的性能对比情况,MySQL选择的版本是5.7.27,PostgreSQL选择的版本是11.0。由图中数据可知,在6年后的2019年,PostgreSQL相比MySQL有了巨大的性能提升,尤其针对简单读写事务负载,PostgreSQL的吞吐量是MySQL的2.3倍;针对只读事务负载,PostgreSQL的吞吐量比MySQL高约50%。但MySQL依然在非简单事务负载下具有比较明显的性能优势。总而言之,在2013年时PostgreSQL相比MySQL没有性能优势,但在2019年PostgreSQL在简单读写负载和只读负载上有明显的性能优势;MySQL一直在非简单事务负载上相比PostgreSQL有明显的性能优势。

MySQL的隔离级别测试

表2:针对MySQL的异象和异常检测结果以及读结果集验证结果

为验证MySQL在不同隔离级别下的正确性,针对版本为5.7.27的MySQL数据库加载了100个随机读写事务负载,并在负载加载过程中设置数据访问分布为高度倾斜。在负载加载完成后,针对负载轨迹进行分析,检测负载轨迹中出现的异象(脏写、脏读、模糊读和幻读)和异常(写偏),并验证所有读操作的结果集是否合理(是否读到了合适版本的数据)。表2给出了在MySQL不同隔离级别下的异象和异常检测结果以及读结果集正确性验证结果。表中日志量指整个负载轨迹中成功提交事务的操作日志数,读操作数即为所有成功执行事务中的读操作个数,对这些读操作的结果集Thor都进行了正确性验证。

由表中数据可知,在MySQL设置为读已提交时,未出现脏写和脏读异象,并且读操作的结果集都是合理的,测试结果符合读已提交隔离级别。在MySQL设置为可重复读时,发现了大量的模糊读异象和写偏异常。注意本实施例的模糊读检测机制是针对单版本并发控制机制实现的,对于多版本并发控制机制无效,但写偏异常的检测结果对单版本和多版本并发控制机制都有效。同时,在本实施例验证读结果集正确性时,发现有大量的读操作结果集错误。根据隔离级别定义[18],可重复读是杜绝写偏异常的,并且这里检测有读操作结果集错误,所以实验结果表明MySQL的可重复读并非传统学术上定义的可重复读。本发明在验证读结果集正确性时,将读操作的时间区间设置为事务中第一个操作的时间区间,此时所有读操作结果集验证通过(表中“可重复读-2”),这表明了MySQL的可重复读隔离级别其实为快照隔离级别。在MySQL设置为冲突可串行化时,所有异象异常都未出现,并且所有读操作结果集验证通过,实验结果符合冲突可串行化隔离级别。实验中未出现模糊读和幻读异象,以及无论利用读操作本身执行时间还是利用其所属事务开始时间(表中“可串行化-2”)读结果集验证都通过,这表明MySQL在冲突可串行化隔离级别下退化为单版本基于锁的并发控制机制。

PostgreSQL的隔离级别测试

表3:针对PostgreSQL的异象和异常检测结果以及读结果集验证结果

本实验针对PostgreSQL 11.0加载了100个随机读写事务负载,表3展示了在PostgreSQL不同隔离级别下的异象和异常检测结果以及读结果集正确性验证结果。当PostgreSQL设置为读已提交和可重复读时,实验结果与表2类似,即PostgreSQL的读已提交隔离级别测试通过;其可重复读隔离级别测试不通过,实际应为快照隔离级别。当PostgreSQL设置为冲突可串行化时,发现有大量的模糊读和幻读异象,这是因为相关检测机制是针对单版本并发控制机制实现的,而PostgreSQL的并发控制机制是基于多版本的;同时,读结果集正确性验证也仅在利用事务开始时间时才能验证通过,这也符合PostgreSQL的实现方式;然而,实验中检测到了写偏异常,在冲突可串行化下是杜绝写偏异常的,实验结果表明PostgreSQL的冲突可串行化隔离级别实现有误。

Derby的隔离级别测试

表4:针对Derby的异象和异常检测结果以及读结果集验证结果

Derby是一个单版本数据库,并发控制是基于锁实现的。表4给出了在Derby不同隔离级别下的异象和异常检测结果以及读结果集正确性验证结果,测试负载为100个随机读写事务负载。由表中数据可知,在Derby设置为读未提交时,出现了大量的脏读、模糊读和幻读异象以及写偏异常,同时读结果集正确性验证也无法通过;当Derby设置为读已提交时,脏读异象被杜绝,并且通过读结果集正确性验证;在可重复读的隔离级别下,表中数据显示仅有幻读异象,模糊读和写偏都被杜绝;当隔离级别设置为可串行化时,所有异象和异常都被杜绝。实验结果与相应的隔离级别完全符合,表明了Derby隔离级别的正确性。

Thor系统的性能测试

本实施例将对Thor系统自身的性能进行测试。首先评估Thor系统的随机数据库模式和随机事务负载的生成效率;然后评估在隔离级别验证时,Thor系统的日志分析效率和内存消耗情况。

图12展示了Thor在生成不同数目数据库模式时的时间消耗。由图中数据可知,Thor的生成时间与数据库模式的个数呈线性关系,并且生成300个随机数据库模式仅需要11.95秒,表明了Thor在随机数据模式生成上的高效性。针对图12中的每个数据库模式,生成10个随机事务负载,图13展示了相应的负载生成时间。实验结果表明Thor的负载生成时间与负载数目呈线性关系,并且平均每个负载的生成时间仅为0.073秒。总而言之,Thor的随机数据库模式和随机事务负载生成是高效的,可以为数据库系统的性能评测以及功能覆盖性测试提供大规模的测试案例。

支持数据库隔离级别的正确性验证是Thor系统的一个重要特征。隔离级别的测试需要大量的随机事务负载以及长时间的高压、高冲突运行,因此相应的负载轨迹可能很长,这对轨迹日志分析效率提出了较高的要求。图14给出了针对不同大小轨迹日志的分析时间。由图中数据可知,日志分析时间与日志规模大小呈线性关系,当日志大小为30GB(约7500万条操作日志)时,日志分析时间小于0.5小时,表明Thor的日志分析效率可以满足实际应用的需求。图15展示了针对不同规模轨迹日志分析时的内存消耗情况。Thor的内存消耗主要源于预读轨迹日志,分析过的日志即可从内存中舍弃。服务于读结果集正确性验证的内存增量数据大小由数据访问分布的候选主键集合大小决定,在实际评测中往往设置为几十至几千,因此增量数据维护消耗的内存与测试数据库大小和轨迹日志规模无关。图15展示了当日志规模超过15GB时,Thor的内存消耗将不再增长,表明Thor可支持任意规模的轨迹日志分析。综上所述,在普通服务器上,Thor的轨迹日志分析效率可满足实际应用需求。

综上,针对大规模事务负载生成与执行正确性验证问题,本发明设计并实现了Thor系统。在Thor系统中,为生成全面且可控的随机事务负载,定义了一组基础数据库操作和多种数据访问分布,然后在用户指定的随机空间生成大规模事务负载测试案例。为实现高压、高冲突事务负载下数据库系统的正确性验证,Thor在负载加载过程中记录了整个事务执行历史,然后基于事务执行历史提出了高效的异象和异常检测算法以及读结果集的正确性验证算法,实现了数据库隔离级别的有效验证。实验结果表明Thor能够对数据库系统的性能和隔离级别正确性进行更充分的测试。

参考文献

[1]DB-Engines Ranking[EB/OL].2019.https://db-engines.com/en/ranking.

[2]SLUTZ D R.Massive stochastic testing of SQL[C]//VLDB 1998,Proceedings of 24rd International Conference on Very Large Data Bases,NewYork City,New York,USA,August 24-27,1998.1998:618-622.

[3]POESS M,STEPHENS J M.Generating thousand benchmark queries inseconds[C]//VLDB 2004,Proceedings of the Thirtieth International Conferenceon Very Large Data Bases,Toronto,Canada,August 31-September 3,2004.2004:1045-1053.

[4]TPC-DS benchmark[EB/OL].2012.http://www.tpc.org/tpcds/.

[5]BATI H,GIAKOUMAKIS L,HERBERT S,et al.A genetic approach for randomtesting of database systems[C]//VLDB 2007,Proceedings of the 33rdInternational Conference on Very Large Data Bases,University of Vienna,Austria,September 23-27,2007.2007:1243-1251.

[6]LETARTE D,GAUTHIER F,MERLO E,et al.Targeted genetic test SQLgeneration for the DB2 database[C]//DBTest 2012,Proceedings of the FifthInternational Workshop on Testing Database Systems,Scottsdale,AZ,USA,May 21,2012.2012:5.

[7]KHALEK S A,ELKARABLIEH B,LALEYE Y O,et al.Query-aware testgeneration using a relational constraint solver[C]//ASE 2008,23rd IEEE/ACMInternational Conference on Automated Software Engineering,L’Aquila,Italy,September 15-19,2008.2008:238-247.

[8]JACKSON D.Alloy:a lightweight object modelling notation[J].ACMTrans.Softw.Eng.Methodol.,2002,11(2):256-290.

[9]KHALEK S A,KHURSHID S.Automated SQL query generation forsystematic testing of database engines[C]//ASE 2010,25th IEEE/ACMInternational Conference on Automated Software Engineering,Antwerp,Belgium,September 20-24,2010.2010:329-332.

[10]KHALEK S A,KHURSHID S.Systematic testing of database enginesusing a relational constraint solver[C]//ICST 2011,Fourth IEEE InternationalConference on Software Testing,Verification and Validation,Berlin,Germany,March 21-25,2011.2011:50-59.

[11]李捷荧,李宇明,张小磊,等.Woodpecker:支持细粒度冲突模拟的数据库测试框架[J].华东师范大学学报(自然科学版),2018,2:77-88.

[12]mysqltest[EB/OL].2019.https://dev.mysql.com/doc/dev/mysql-server/8.0.12/PAGE_MYSQ-LTEST.html.

[13]jenkins[EB/OL].2019.https://jenkins.io/zh/.

[14]LoadRunner[EB/OL].2019.https://www.microfocus.com/en-us/products/loadrunner-load-testing/.

[15]TPC-C benchmark[EB/OL].1992.http://www.tpc.org/tpcc/.

[16]ALOMARI M,CAHILL M J,FEKETE A,et al.The cost of serializabilityon platforms that use snapshot isolation[C]//ICDE 2008,Proceedings of the24th International Conference on Data Engineering,Cancún,Mexico,April 7-12,2008.2008:576-585.

[17]TATP Benchmark Description[EB/OL].2009.http://tatpbenchmark.sourceforge.net.

[18]BERENSON H,BERNSTEIN P A,GRAY J,et al.A critique of ANSI SQLisolation levels[C]//SIGMOD 1995,Proceedings of the ACM SIGMOD InternationalConference on Management of Data,San Jose,California,USA,May 22-25,1995.1995:1-10.

[19]ADYA A,LISKOV B,O’NEIL P E.Generalized isolation leveldefinitions[C]//ICDE 2000,Proceedings of the 16th International Conference onData Engineering,San Diego,California,USA,February 28-March 3,2000.2000:67-78.

[20]MySQL[EB/OL].2019.https://www.mysql.com/.

[21]PostgreSQL[EB/OL].2019.https://www.postgresql.org/.

[22]Derby[EB/OL].2019.http://db.apache.org/derby/.

[23]PostgreSQL Release 9.6[EB/OL].2016.https://www.postgresql.org/docs/9.6/release-9-6.html.

[24]PostgreSQL Release 10.0[EB/OL].2017.https://www.postgresql.org/docs/10/release-10.html.

本发明的保护内容不局限于以上实施例。在不背离发明构思的精神和范围下,本领域技术人员能够想到的变化和优点都被包括在本发明中,并且以所附的权利要求书为保护范围。

去获取专利,查看全文>

相似文献

  • 专利
  • 中文文献
  • 外文文献
获取专利

客服邮箱:kefu@zhangqiaokeyan.com

京公网安备:11010802029741号 ICP备案号:京ICP备15016152号-6 六维联合信息科技 (北京) 有限公司©版权所有
  • 客服微信

  • 服务号