赞
踩
本文主要为了对比PG和XL的单个事务处理时间,并统计XL处理事务的耗时分布。
结论:在我们的部署环境下,XL处理单个事务的耗时约为PG的4倍,XL处理事务耗时较大的为: 获取快照、获取全局事务ID、远程执行、提交事务这几个部分。详细见后文。
SystemTap 是可以动态监控和跟踪Linux 内核的工具,具体介绍及安装使用不做赘述,参照 《Linux 自检和 SystemTap》
这里主要用来统计函数执行耗时。脚本样例:
- global s1
-
- #process中是可执行文件的全路径,function中为要统计的函数名,在该函数return时计算耗时
- probe process("/opt/pgsql10.5/bin/postgres").function("exec_simple_query").return {
- s1 <<< gettimeofday_us() - @entry(gettimeofday_us()) #以微秒精度来统计,@entry方法将一个表达式放置于函数入口处
- }
-
- probe timer.s(5) { #每5s执行一次以下内容
- #打印统计的次数和平均值
- printf("\ns1:\t")
- print(@avg(s1))
- printf("\t")
- print(@count(s1))
-
- }
PG-XL部署方式:
三台机器连接同一个交换机,网络延迟为50us左右(使用qperf测试)。
PG部署方式:
在上述PG-XL中99.94的机器上部署PG:
- --建表脚本,XL中使用HASH分片
- create table stest(id int,name varchar(20))DISTRIBUTE BY HASH(id);
-
- --写入数据(auto commit)
- insert into stest values(1,'11');
1. 编写好SystemTab脚本,统计事务执行过程中各个函数的调用时间,并在连接的节点执行该脚本
2. 使用psql连接,重复执行上述insert语句N次
3. 结束SystemTab脚本,查看执行结果
由上图可看出两者commit耗时差异不大,XL主要耗时在获取快照、获取事务ID、执行写入。
上面说到网络延迟为50us,在我们的测试环境中,coordinator任何需要与GTM交互的请求,都需要通过gtm_proxy。
获取快照:约350us; 去除网络延迟,实际耗时约250us.
获取事务ID:约350us; 去除网络延迟,实际耗时约250us.
ExecutorRun:约800us;该函数是执行计划的函数,具体耗时不知去向。我们进一步分析ExecutorRun函数内部的耗时分布:
以下是函数调用堆栈及耗时(us):
ProtalRun :1079
ProtalRunMulti :1068
ProcessQuery : 1058
ExecutorRun :743 (其他300左右时间耗在获取事务ID)
ExecRemoteQuery : 723 (在datanode节点执行)
pgxc_node_receive :700 (等待datanode返回执行结果)
由上述结果可以看出等待datanode返回执行结果是主要的耗时所在。
由此我们进一步统计了datanode从接收到请求到返回个部分耗时分布:
我们发现datanode执行一个请求的时间与PG几乎一样,对比PG:
我们看一下coordinator发送远程执行请求到datanode的代码,datanode接收到的请求是一条sql,这也就解释了为什么datanode执行请求的时间与PG一样:
- static int
- pgxc_node_send_query_internal(PGXCNodeHandle * handle, const char *query,
- bool rollback)
- {
- int strLen;
- int msgLen;
-
- /*
- * Its appropriate to send ROLLBACK commands on a failed connection, but
- * for everything else we expect the connection to be in a sane state
- */
- elog(DEBUG5, "pgxc_node_send_query - handle->state %d, node %s, query %s",
- handle->state, handle->nodename, query);
- if ((handle->state != DN_CONNECTION_STATE_IDLE) &&
- !(handle->state == DN_CONNECTION_STATE_ERROR_FATAL && rollback))
- return EOF;
-
- strLen = strlen(query) + 1;
- /* size + strlen */
- msgLen = 4 + strLen;
-
- /* msgType + msgLen */
- if (ensure_out_buffer_capacity(handle->outEnd + 1 + msgLen, handle) != 0)
- {
- add_error_message(handle, "out of memory");
- return EOF;
- }
-
- handle->outBuffer[handle->outEnd++] = 'Q';
- msgLen = htonl(msgLen);
- memcpy(handle->outBuffer + handle->outEnd, &msgLen, 4);
- handle->outEnd += 4;
- memcpy(handle->outBuffer + handle->outEnd, query, strLen);
- handle->outEnd += strLen;
-
- PGXCNodeSetConnectionState(handle, DN_CONNECTION_STATE_QUERY);
-
- handle->in_extended_query = false;
- return pgxc_node_flush(handle);
- }
为了验证网络延迟对事务响应时间的影响,我在上述pc94的物理机上重新搭建了一个单机XL环境,gtm/coordinator/datanode之间交互要用到的host配置都配置为localhost而不是IP,并取消了gtm_proxy节点。
环境部署对比图:
为了验证获取事务快照对事务响应时间的影响,我对XL的源码做了一点修改,在执行insert时不从GTM获取快照,而是直接生成一个快照,保证在不从GTM获取快照的情况下数据也能正常写入(代码修改不够严谨,导致并发情况下存在数据丢失问题,此处仅用来做单个事务响应时间测试)。然后用修改后的代码编译部署一个同样的XL单机环境进行测试。
测试结果:
由上图可以看出:
单机环境比多机环境获取快照和获取事务ID的时间都少了一些,说明网络延迟在一定程度上影响了事务响应时间;
不获取快照时事务响应时间减少了1/4,说明减少coordinator与GTM的交互能有效提高事务响应性能。
以上仅是对单个事务的响应时间做了初步调研,对于高并发时,性能无法线性提升的问题还有待深入研究。
单个事务耗时相比PG主要可改进的地方有以下三点:
1. 获取快照
2. 获取事务ID
3. 远程执行
关于1和2,之前统计过GTM中生成快照和生成GTXID的耗时,即使在高并发的情况下也基本能在32us内执行完成,相比之下,减少网络交互可能提升更大,比如将获取事务ID和获取快照的请求合并成一个,即可降低coordinator与GTM之间一半的网络开销;比如在不需要获取快照时不进行快照获取;比如修改现有的全局事务ID生成方式改用逻辑时钟替代等。
关于3,datanode执行请求时大部分操作与coordinator是重复的,比如解析sql、生成执行计划等等,如果能减少这部分重复,也许性能会有小幅度提升(之前统计过,对于insert操作,生成计划树之前的步骤耗时只占整个流程的3%左右);
欢迎分享其他优化建议。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。