Opengauss的TPCE测试

编程入门 行业动态 更新时间:2024-10-09 06:21:56

Opengauss的TPCE<a href=https://www.elefans.com/category/jswz/34/1771117.html style=测试"/>

Opengauss的TPCE测试

网上有一个对PostgreSQL(PG)做TPCE测试的开源软件:dbt5,代码路径为:

它使用C++编写,遵守TPCE规范。

由于工作需要,我尝试使用这个软件和网上相关信息,对Opengauss(OG)做TPCE测试,主要针对Opengauss的MOT(内存表)进行测试。

源码编译、配置、测试流程参考了这篇文章:金仓数据库在 TPCE(dbt5,tpsE)测试框架方面的实践和突破_kangming7508的博客-CSDN博客

非常感谢作者的开创性工作。

我将修改后可用于Opengauss的代码上传到。TPCE标准也在源代码的根目录下,增加了标签,便于阅读。

第一,dbt5网上代码和脚本不加修改,直接用来测Opengauss的MOT表是不行的,因为目前MOT还不支持外键,而TPCE许多表都定义了外键,因此脚本中创建外键的部分需要修改一下,我将dbt5-pgsql-create-indexes中创建外键的语句都注释掉了。

第二,建表时用CREATE FOREIGN TABLE建表,修改了建表脚本dbt5-pgsql-create-tables。

第三,TPCE总共包括12个事务,每个事务由1到6个存储过程组成,一个存储过程称为一个Frame。在PG或OG中,这些存储过程可以通过PL/pgSQL实现,也可以通过C或其它语言实现。原dbt5代码中有一套C语言实现的存储过程,在storedproc/pgsql/c/,还有一套PL/pgSQL实现的存储过程,在storedproc/pgsql/pgsql/,两套存储过程可以互相替代。

dbt5测试程序使用的是C语言存储过程,PL/pgSQL已经不再维护,有很多错误,接口也无法对齐,但是,OG使用C语言存储过程,虽然编译安装没有问题,但运行时经常出现段错误(segment fault),导致整个数据库崩溃,且出错的存储过程非常多。我尝试过调试解决,但难度大耗时长,遂决定放弃C语言编写的存储过程,在已有的PL/pgSQL存储过程基础上参照规范重写一遍。这样的好处:一是PL/pgSQL在PG和OG中兼容性较好,二是如果PL/pgSQL如果再出现段错误,那一定是OG研发的问题,我可以把导致段错误的PL/pgSQL代码给OG的研发研究解决,但如果是因为调用C语言存储过程(SPI C接口)导致了段错误,很难确定是OG本身的问题还是因为SPI C接口使用不当。

因此,我花了两周多的时间,调试修改storedproc/pgsql/pgsql/下的sql脚本,调通了每个存储过程,接口(存储过程函数的输入和输出)与C语言版大部分兼容,这样以后调用C语言的存储过程,dbt5的调用代码可以不变。

因此,原来初始化脚本中,加载C语言存储过程的部分,要改成执行storedproc/pgsql/pgsql/下的脚本,即修改了dbt5-pgsql-load-stored-procs。

注意,OG或PG的max_connections要调到足够大,大约是并发客户数的两倍多,否则会有很多事务失败,最终结果显示rollback。

第四,OG的MOT不支持BLOB、CLOB等大对象类型。字符串类型的列,最长只支持1024个字节,并且实际存储的数据还要小于1024字节。而TPCE的NEWS_ITEM表的NI_ITEM列,是一个长度为10万字节的BLOG类型列。对此只能降低要求,改为1000字节的VARCHAR。

第五,dbt5的测试流程

1、执行dbt5-pgsql-build-db,创建数据库、创建表、生成假数据导入表,创建主键、索引、外键、存储过程。

2、执行dbt5-run-workload,运行测试程序,测试程序由三个进程组成,分别是DriverMain、BrokerageHouseMain(BH)、MarketExchangeMain(ME)。只有BH与数据库连接,向数据库发请求执行事务。DriverMain、ME则与BH连接,DriverMain按照规范要求,生成事务输入参数,按照不同比例,要求BH执行事务,ME在特定触发条件下,也会要求BH执行事务。DriverMain和ME统计事务从请求到返回的时间,作为性能指标,网络延迟也被计算在内。

3、每个事务执行时间和结果会被记录到两个文本文件中,具体是DriverMain写到ce_mix.log和ME写到mee_mix.log,结束时它们又被汇总为一个文本文件mix.log,然后再由分析程序dbt5-post-process分析,打印出性能信息。(注意,dbt5-post-process是python程序并且调用了R语言,需要操作系统安装R语言库,和python的R语言调用模块,我对dbt5-post-process做了一点修改,就是使用python3)

第六,实现原理

DriverMain通过TCP连接BH服务器,根据参数,DriverMain创建多个客户连接,每个客户一个线程,表示多个客户并发执行事务。BH为每个客户连接,创建一个线程和一个到数据库的连接。测试开始后,每个客户独立向BH发请求,要求它执行12个事务中的某一个,事务之间的个数比例按照规范决定。BH执行完事务,无论成功与否都会将状态通过网络返回给客户,客户将执行结果和执行时间记到日志中,用来统计性能指标,网络延迟也被计算在内。

但是这个测试模型还并不是那么简单。对于一个TradeOrder事务(发起一个股票买卖的事务),BH执行完后,会向ME发消息(通过TCP连接),ME收到消息后,会再向BH发送TradeResult事务(完成一个股票买卖的事务)请求(通过另一个TCP连接),对BH来说,就像有一个新的客户连接进来发送请求一样,会为这个请求创建一个线程和到数据库的连接,并执行TradeResult事务,结果再返回给ME(通过同一个TCP连接)。ME会记录从发送TradeResult请求到BH返回的耗时,TPCE的最重要的性能指标,就是每秒执行的TradeResult数。

ME除了会请求BH执行TradeResult外,还会请求BH执行MarketFeed。

为了说明MarketFeed是一个什么样的事务(TPCE规范最难理解的部分),这里需要先说一下TPCE所模拟的股票交易的业务逻辑。

各位应该在A股买卖过股票吧,所谓TradeOrder事务,就下单买入或卖出股票,但是下单了并不等于成功买到和卖出了股票,只是将单子挂到了交易大厅,只有当买入的价格高于市场价,或卖出的价格低于市场价时,才能完成交易。当能够完成交易时,TradeResult事务会被调用,执行完成交易的工作,TradeResult事务执行完成后,一桩股票买卖的交易才算真正完成。

不精确地讲,TradeOrder事务(注意一个TradeOrder事务只完成一个股票的买卖),有两种订单:a)MarketOrder -- 是按照市场价格买卖,这样的交易可以立即完成,TradeResult事务会紧接着被调用。b)LimitOrder -- 是按照指定的价格买卖,当市场价格没有达到指定值时,这种交易只能先挂在那里,等市场价格变动到其指定的范围内,才会触发交易完成。

a 类型的TradeOrder事务,先把交易信息存储到TRADE表中,其后TradeResult事务紧接着执行,表示交易订单立刻被处理,TradeResult是真正完成买卖交易的事务,它更新TRADE表中前面TradeOrder存入的未完成的交易记录,使用交易的数量和价格,修改账户的持股数量和现金,记录交易历史,标记交易完成等。(注意,一个TradeResult事务完成一笔交易,一笔交易就是一个股票的买卖,它有一个trade_id输入参数,表示只对这个交易进行完成处理。)

b 类型的TradeOrder事务,交易信息除了存储到TRADE表中,还会存储到TRADE_REQUEST表中,表示这个交易处于挂起状态,之后TradeResult事务并不执行,ME对它的处理就算完成了。(忽略了一个细节,会把它暂存到ME内存中的队列里)

那什么时候,这些“挂起”的交易会完成呢?这就引出了另一个问题,在真实股市中,随着股票的买卖,股票的价格会变动的,TPCE如何模拟股票价格变动的呢?

TradeOrder事务执行完后,交易信息(包括买卖股票的价格)会发给ME,无论MarketOrder还是LimitOrder类型,ME都会这些把交易信息加入到一个队列(在ME的内存中),其中股票价格不再是原来的价格,而是随机生成的价格(严格的说不是随机生成,实现在CMEESecurity::CalculatePrice),这个随机生成的价格就模拟了股票价格变动。当这个队列中的交易达到20个时,触发ME向BH发送MarketFeed事务请求,并将队列中的交易信息作为参数传入。

MarketFeed事务做什么呢?1、更新股票的市场价,模拟价格波动。2、处理挂起的Limit Order。

股票的市场价格记录在LAST_TRADE表中,MarketFeed使用传入的20个交易中的股票价格,更新LAST_TRADE中对应股票的价格。模拟最后20个交易,对股票市场价格带来的波动。

挂起的LimitOrder都存储在TRADE_REQUEST表中。某些股票市场价格的变动,可能使TRADE_REQUEST中某些交易,符合交易完成条件(股票市场的价格在其买卖区间内)。

然后MarketFeed对20个交易中的每一个股票,搜索TRADE_REQUEST表,寻找符合条件的交易,然后从TRADE_REQUEST中移除。(即对这些交易作为MarketOrder类型,做了TradeResult操作,具体见规范中MarketFeed存储过的定义)

MarketFeed的输出,就是所有符合交易完成条件的LimitOrder交易信息,BH对每一个交易,会向ME发一个MarketOrder类型的TradeOrder执行完的消息,这又导致ME向BH发TradeResult请求,从而完成这个LimitOrder。(LimitOrder变成了MarketOrder后被处理了)如果MarketFeed输出为空,BH什么也不做。

按照规范,EGenDriverMEE会创造条件(为LimitOrder交易中的股票生成符合条件的价格?),使每个挂起的LimitOrder都会在15分钟内被处理掉:

第七,优化

前面介绍原理,是为了优化时明明白白。原版本的测试程序有个问题,就是对于线程的管理。假如DriverMain创建了100个客户连接到BH,BH会为每个客户创建一个线程、到ME的连接和到数据库的连接,ME接收到BH的连接后(ME只能接收来自BH的连接),会为这个连接创建一个线程,等待来自这个连接的消息(具体就是TradeOrder执行完的消息),也就是DriverMain的100个客户线程在BH中生成了100个线程,在ME中生成了100个线程,这也还没什么。问题是,当ME中的一个线程收到了BH的TradoOrder执行完的消息后,经过判断需要向BH发TradeResult或MarketFeed请求时,每个请求又会创建一个线程。即一个DriverMain的客户线程,可以导致ME中生成多个线程。由于这样的设计,在测试中,经常DriverMain客户并发连接数还不到100,ME就因为生成的线程太多资源不足而退出了。

因此有必要对ME的线程管理做一下优化,关于ME的优化文章《金仓数据库在 TPCE(dbt5,tpsE)测试框架方面的实践和突破_kangming7508的博客-CSDN博客》已经提到过,但是未给出代码。我自己尝试了三种优化方案:1、ME使用一个线程处理所有工作,监听网络请求使用epoll多路复用。2、ME仍然每个来自BH的连接创建一个线程,这部分不变,但发送TradeResult和MarketFeed时,不创建新线程。3、ME监听网络连接和数据使用一个线程和epoll,接收到消息经过判断需要向BH发送TradeResult和MarketFeed请求时,请求信息放入队列中,ME初始化时创建多个工作线程,它们不断从队列中取请求信息(使用互斥锁或自旋锁同步),然后向BH发TradeResult或MarketFeed请求,并记录响应时间。

它们都可以解决ME创建太多线程的的问题,经过多次测试,出乎意料的是,方案1和方案2的性能差不多,而方案3的性能最差。如果仔细研究ME的代码,就会发现,原来的代码尽管创建了多个线程,但是这些线程都引用了同一个CMarketExchange对象(因为20个最新的交易部分客户的加入共享的队列,有一部分数据结构是所有客户共享的),并且它们向BH发请求时使用的是同一socket,每个线程使用这个socket时都要对它加锁,事务执行完返回后才释放锁,我感觉这与只是用一个线程处理所有工作没太大区别,实际测试也证明了这一点,而且,我尝试过在方案3基础上,每个线程使用独立的到BH的连接执行TradeResult或MarketFeed请求,性能并没有提升,所以我最终选择的优化方案是方案1,这种方案的好处是逻辑简单,无论多少个并发客户,ME都只有一个线程,扩展性较好。

目前在2个CPU,每个32核,每核2个线程,2GHz,500G内存,x86架构的海光服务器上,使用MOT表测试的最好的结果如下,初始化脚本的参数为,

dbt5-pgsql-build-db -l 5432 -s 500 -c 5000 -t 5000 -w 5 -b 1

运行脚本的参数,运行20分钟,大约100个到数据库的并发连接,

dbt5-run-workload -a pgsql -p 5432 -c 5000 -t 5000 -d 1200 -u 100 -w 5 -n dbt5 -o ./results

  在2个CPU,每个64核,最大2.6GHz,380G内存的鲲鹏ARM服务器测试结果(100个并发),

作为对比,我也测试了一下PG在2个CPU,每个32核,每核2个线程,2GHz,500G内存,x86架构的海光服务器上跑TPCE的数据:

 第八,杂项

关于TPCE的介绍和如何配置和运行测试程序,参考文章讲的很清楚,本文也是记录在参考这篇文档的基础上,对Opengauss做的工作。金仓数据库在 TPCE(dbt5,tpsE)测试框架方面的实践和突破_kangming7508的博客-CSDN博客

所以我就不在记录如何配置和运行dbt5了,目前网上的TPCE测试工具,不像TPCC那样已经很成熟,并且优化较好,使用方便,支持数据库多,dbt5的代码仍然有优化空间,存储过程使用c语言实现是不是性能更好?

本文是一篇抛砖引玉的文章,如果读者在工作中需要TPCE的测试软件可以在我的基础上修改,并提交,有兴趣可以增加对mysql、oracle等其它数据库的支持。

代码下载后的目录是osdldbt-dbt5,如果要开启代码中的DEBUG打印,可以在osdldbt-dbt5/CMakeLists.txt中最后一行添加ADD_DEFINITIONS(-DDEBUG)。这样每个执行的存储过程和它的输入输出就会打印到bh/bh.out中。

TestTxn -i /home/omm/osdldbt-dbt5/egen/flat_in -p 5432 -u postgres -s Post123 -f 500 -c 1000 -g dbt5 -w 1 -t A

TestTxn程序可以一次只跑一个事务,它直接连接数据库,用来调试存储过程,我的代码做了修改需要传入OG的用户名和密码,对于TradeOrder事务,如果是market order则会有一个TradeResult事务紧接着执行,如果是limit order则什么也不会执行。有时执行TradeOrder,类型也是market order,并且打印了“Sending to Market a Market-Order: Trade-Result & Market-Feed should trigger”,但是TradeResult没有执行,这是因为TradeResult是按照egen设置的一段时间后执行的,而我的代码是等待1秒钟,egen设置的延迟时间是随机的,大部分在1秒以内,所以,遇到这种情况多执行几次就行了。

TestTxn -b 127.0.0.1 -i /home/omm/osdldbt-dbt5/egen/flat_in -c 1000 -g dbt5 -w 1 -t A

TestTxn有两种测试模式,一种是指定数据库连接信息,直接连数据库执行事务,另一种是当存在BH和ME进程时,指定BH的地址(-b参数),TestTxn像DriverMain一样,连接BH,请求BH连接数据库执行事务,这样更接近真实场景,我的代码目前这部分还没调好。

更多推荐

Opengauss的TPCE测试

本文发布于:2024-02-06 17:55:27,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1750846.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:测试   Opengauss   TPCE

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!