GreenPlum高并发查询锁优化
1.1 GreenPlum简介
Greenplum数据库是一种大规模并行处理(MPP)数据库服务器,其架构特别针对管理大规模分析型数据仓库以及商业智能工作负载而设计。Greenplum数据库是基于PostgreSQL开源技术的。它本质上是多个PostgreSQL面向磁盘的数据库实例一起工作形成的一个紧密结合的数据库管理系统(DBMS)。
其组网中通常会有一个主节点和standby主节点,同时分布着多个子节点(segment节点)。主节点只负责查询任务的解析及分发,不存储和处理数据,子节点将数据分布式存储进行并行查询,并反馈查询结果及状态到主节点。
GreenPlum分布式数据库运行流程大致如下:
1、client端由libpq协议连接master节点,master节点创建QD进程进行SQL解析等,生成查询计划
2、QD进程通过libpq协议与各子节点连接,分发查询任务,子节点再创建QE进程执行SQL查询任务
3、各子节点QE进程查询结果由interconnect汇总返回至QD进程
4、QD进程通过libpq将汇总结果返回客户端
更多信息可在官网主页https://cn.greenplum.org/获取。
在GreenPlum数据库查询场景,会出现s_lock热点函数,影响鲲鹏服务器上查询性能,需进一步进行优化。
1.2 软硬件配置信息
数据库版本:GreenPlum 6.9.1 操作系统:Centos7.6
硬件配置信息如下:
配置项 |
鲲鹏 |
X86 |
CPU型号 |
Kunpeng 5230 |
Intel(R) Xeon(R) Gold 5218 CPU @ 2.30GHz |
内存 |
256G |
256G |
磁盘(数据盘) |
500G HDD |
500G HDD |
均采用单机模式,一个主节点,子节点配置4个segment,无standby节点。
1.3 性能优化
1.3.1 S_lock热点函数复现
1、生成测试数据
通过pagebnech测试工具,执行以下命令生成14GB的测试数据:
# 其中-F参数为装填因子,-s值得是比例因子,比例因子越大,测试数据集也越大
pgbench -i -F 100 -s 1000 -p port -h con_addr -U postgres postgres
如:pgbench -h master -U gpadmin -p 5432 -c 100 -j 100 -S -T 60 -r postgres
2、执行压测命令
执行以下命令进行压测:
pgbench -h con_addr -p port -r -n -c 100 -j 100 -T 60 -S -U postgres postgres
3、压测现象如下
100并发压测结果:TPS 为805左右
进一步看到热点函数非常集中,s_lock占比达到82.42%
此时CPU资源消耗99%,主要集中在s_lock函数上
1.3.2 优化分析
- 问题分析
通过s_lock热点函数复现可以看到,s_lock函数已成为当前瓶颈点,是优化的核心点。
默认GreenPlum编译后是release版本,调试时无法看到详细信息,为了跟踪s_lock形成原因及进一步优化,需重新编译debug版本。
- 编译GreenPlum的Debug版本
# 重新编译debug版本 ./configure --with-perl --with-python --with-libxml --prefix=/usr/local/gpdb-debug --enable-debugntuplestore --enable-debug --enable-debug-extensions make -j32make install |
- 调用栈分析
完成debug版本编译后,重新运行数据库并进行压测,压测同时用gdb进行跟踪调试
gdb attach -p postgres-PID #可进行多次尝试,直到atach到的函数停留在s_lock
然后执行 bt 命令打印调用栈:
结合调用栈可以发现,最终会调用tas函数去完成s_lock函数功能,进入tas函数所在文件路径gpdb\src\include\storage\s_lock.h,tas在arm分枝下的实现:
核心问题转化为优化tas实现,提升锁的性能。
- TAS函数优化
Tas是test and set的缩写,该操作是实现一种不可中断的原子运算,对尝试的变量进行赋值操作,通常是置1,如果失败则重试,最后返回之前的旧值。
代码中tas的实现调用了gcc内存的tas原子操作 __sync_lock_test_and_set,编写相关测试代码观察函数的汇编实现如下:
mov w1, 1 .L3: ldxr w2, [x0] stxr w3, w1, [x0] cbnz w3, .L3 dmb ish |
汇编中可以看到,由于ldxr+stxr指令并不能保存内存一致性,从而需要内存屏障指令dmb ish配合来实现内存一致性,该内存屏障指令将带来性能上的损失。
- CAS实现优化分析
CAS需要3个参数,一个内存位置(ptr),一个期望旧值(old_value),一个待写入内存的新值(new_value),过程大致是:
- 比较内存值*ptr是否与olad_value相等
- 如果相等,则用新值new_value一直重试写入
- 如果不相等,不做任何操作
- 无论哪种情况,CAS最终返回值是内存ptr的原始值
使用ldaxr+stlxr两条指令实现原子操作时,可以同时保证内存一致性,相比以上方式更加高效。同时分析可以发现,TAS是直接写操作,CAS是先比较,满足条件 后再写。而写是一个相对耗时的操作,因此在高并发、频繁使用锁的场景,CAS性能会更好。
综合以上分析,使用内嵌汇编方式重新实现Tas函数:https://github.com/greenplum-db/gpdb/pull/12848/files
优化后100并发运行时TPS 3800,整体热点函数占用也下降到38%。
- LSE编译选项优化分析
LL/SC(Load-link/Store-condition)原子指令需要把共享变量先load到本核所在的L1cache中进行修改,在锁竞争少的情况下性能较好,但在锁竞争激烈时会导致系 统性能下降严重。ARMv8.1规范中引入了新的原子操作指令扩展LSE(Large SystemExtensions),将计算操作放到L3 cache去做,增大数据共享范围,减少 cache一致性耗时,在锁竞争激烈时可以提升锁的性能。
在Configure文件添加以下编译选项重新编译:
CFLAGS="-march=armv8-a+lse"
CXXFLAGS="-march=armv8-a+lse"
实际测试发现该编译选项可以降低热点函数占用,但性能基本无提升:
(1)100并发下CAS优化+ LSE 编译选项后热点函数CAS进一步下降到27%,但TPS也由3652下降到2985,性能弱化了。
(2)不做CAS优化,使用原有的TAS+LSE编译选项优化后,热点函数占比由83%下降到77.8%,同时TPS 也由805下降到577,性能也劣化了。
初步分析看,当前GreenPlum场景下,鲲鹏LSE编译选项优化有负向效果,暂不采用。
1.3.3 优化措施
已在GreenPlum开源社区提交PR进行全量测试,PR review中,待合入;相关优化代码可参考PR #12848:improv spinlock(TAS) performance on aarch64 platform, such as kunpeng
1.4 优化前后测试结果
锁优化后,鲲鹏平台上性能平均提升383.47%,较x86性能平均领先108.92%。
- 点赞
- 收藏
- 关注作者
评论(0)