openGauss鲲鹏多核优化解读

网友投稿 896 2022-05-29

从集成电路诞生到现在,CPU主要经历了三个发展阶段,第一阶段是提升CPU的主频。在集成电路问世6年后,摩尔就提出了摩尔定律,预言了芯片上集成的晶体管数量将每两年翻一番。摩尔定律不是自然定律,但半导体芯片发展的事实证明,摩尔的预言是准确的。芯片的技术进步主要受益于两个方面:制程变小和硅片变大。但当芯片工艺规格小于7nm的时候,就会出现量子隧穿效应,芯片量产变得困难,导致制造成本急剧上升。

第二阶段是增加核数,在单核CPU频率无法继续增加的情况下,可以通过增加CPU的核数来提升算力。但CPU只是逻辑计算单元,必须把内存中的程序和数据加载到CPU中才能进行计算。所有CPU核都是通过共享一个北桥来读取内存,随着核数的快速发展,北桥在响应时间上的性能瓶颈越来越明显。

第三阶段是CPU核NUMA化,为了解决北桥中读取内存的部分即内存控制器的瓶颈,可以把内存平均分配在各个die上,但这导致了不同CPU核访问不同内存时延的非对称性。原因是虽然内存直接attach在CPU上,但当CPU访问自身直接attach内存对应的物理地址时(即Local Access),响应时间较短。如果访问其他CPU attach的内存数据(即Remote Access),就需要通过inter-connect通道访问,响应时间就会变慢。这也是NUMA(Non-Uniform Memory Access)名称的由来。在NUMA架构下,NUMA Node的处理器和内存块的物理距离被称为NUMA距离,通过numactl工具可以查询到CPU访问的距离信息。以鲲鹏服务器为例,图示如下:

从集成电路诞生到现在,CPU主要经历了三个发展阶段,第一阶段是提升CPU的主频。在集成电路问世6年后,摩尔就提出了摩尔定律,预言了芯片上集成的晶体管数量将每两年翻一番。摩尔定律不是自然定律,但半导体芯片发展的事实证明,摩尔的预言是准确的。芯片的技术进步主要受益于两个方面:制程变小和硅片变大。但当芯片工艺规格小于7nm的时候,就会出现量子隧穿效应,芯片量产变得困难,导致制造成本急剧上升。

第二阶段是增加核数,在单核CPU频率无法继续增加的情况下,可以通过增加CPU的核数来提升算力。但CPU只是逻辑计算单元,必须把内存中的程序和数据加载到CPU中才能进行计算。所有CPU核都是通过共享一个北桥来读取内存,随着核数的快速发展,北桥在响应时间上的性能瓶颈越来越明显。

第三阶段是CPU核NUMA化,为了解决北桥中读取内存的部分即内存控制器的瓶颈,可以把内存平均分配在各个die上,但这导致了不同CPU核访问不同内存时延的非对称性。原因是虽然内存直接attach在CPU上,但当CPU访问自身直接attach内存对应的物理地址时(即Local Access),响应时间较短。如果访问其他CPU attach的内存数据(即Remote Access),就需要通过inter-connect通道访问,响应时间就会变慢。这也是NUMA(Non-Uniform Memory Access)名称的由来。在NUMA架构下,NUMA Node的处理器和内存块的物理距离被称为NUMA距离,通过numactl工具可以查询到CPU访问的距离信息。以鲲鹏服务器为例,图示如下:

openGauss鲲鹏多核优化解读

CPU NUMA化给服务器带来澎湃算力的同时,也给软件开发带来了很大挑战。从整个IT软件栈来看,首先需要对NUMA化进行支持的是操作系统,现在通用的企业操作系统是Linux操作系统。在NUMA出现后,Linux也提供了针对性的优化方案,优先尝试在请求线程当前所处的CPU的Local内存上分配空间。如果local内存不足,优先淘汰local内存中无用的Page。但Linux提供的NUMA内存使用方式并不适合数据库,因为数据库是一个数据密集型高并发的应用,内部有很多的内核数据结构,这些数据结构既会被本核的CPU访问,也会被远程的CPU核访问。为了提高数据访问性能,数据库还有自己的共享数据缓冲区,这些共享缓冲区是随机的被各个CPU核上的业务线程访问。从IT软件栈来看,数据库是处于企业应用的核心位置,很多应用后台都有一个数据库,数据库的性能决定了很多应用的整体吞吐量。因此如果数据库无法在NUMA下发挥最大性能,实现随着核数的增加,性能呈现一定的线性比,那么CPU NUMA虽然算力很丰富,但可能没有企业愿意买单。

反过来,NUMA作为CPU发展的一种必然趋势,一款企业级的数据库如果不能适应硬件的发展,在企业的数据库选型中,这款数据库也将被淘汰出局。

openGauss作为一款开源关系型数据库管理系统,针对CPU NUMA 化的硬件发展趋势,从并发控制算法,内核数据结构,数据访问等全方位进行了优化,释放处理器多核算力,实现两路鲲鹏128核场景150万tpmC性能。本文深度解读openGauss在鲲鹏服务器上的NUMA多核优化技术,同时也为其他数据库在鲲鹏上进行性能优化提供借鉴和参考。

openGauss鲲鹏多核优化解读

数据库是高并发,数据访问冲突严重的软件系统。数据库领域图灵奖获得者Stonebraker等人于2014年在VLDB发表的论文:Staring into the abyss: an evaluation of concurrency control with one thousand cores。这个论文观点表明传统数据库的事务处理机制无法有效利用数十到上百个核的处理能力。通过对数据库进行更深入的分析,发现这里面既有并发控制算法的原因,也有实现机制的原因。数据库为了实现并发,内部使用了很多锁,比如openGauss中的Clog、WALInsert、WALWrite、ProcArray、XidGen等。这些锁是性能瓶颈点,而锁的本质是保护内核数据结构。所以openGauss需要对这些数据结构进行调整和优化,来应对鲲鹏NUMA架构下多核的并发问题。主要目的有三个:实现CPU的就近访问,去除单点瓶颈,共享数据的内存均匀分配和访问。

1.1 线程绑核,避免线程在核间偏移

为了实现CPU核的就近访问,首先需要把线程固定到具体的核上。openGauss有一个GUC配置参数numa_distribute_mode控制CPU绑核分配。通过这个参数,可以把业务处理线程绑定到具体NUMA NODE上。openGauss是一个客户端服务器结构,客户端和服务器通过网络通信来进行交互,网络是一个频繁的操作,为了避免网络中断和业务处理相互干扰,也需要进行网络中断绑核,同时需要考虑网络中断绑核和后台业务线程绑核区分开。

1.2 NUMA化数据结构改造,减少跨核访问

WALInsertLock用来对WAL Insert操作进行并发保护,可以配置多个,如16。访问行为主要有两种:1)Xlog Insert 时分配一个Insert Lock;2)遍历访问所有WALInsertLock,比如查找是否存在空洞信息,用于XLogFlush等。

在原来的实现方案中,所有的WALInsertLock都在同一个全局数组,存放在共享内存中。WALInsertLock竞争激烈,大概率会涉及到远端访存,即多个线程会进行跨Node、跨P竞争。而实际上Insert Lock有多个实例,大部分操作每次仅需申请一个Insert Lock,可以考虑将申请操作限制在相同的NUMA Node内部。

优化后的方案将全局WALInsertLock数组按照NUMA Node的数目分为多份,分别在对应NUMA Node上申请内存。每个事务线程根据自己所归属的NUMA Node,选择WALInsertLocks子数组。WALInsertLock引用了共享内存中的LWLock,为了最大化减少跨Node竞争,将LWLock直接嵌入到WALInsertLock内部,这样就可以一起进行NUMA分布,同时还减少了一次Cache Line访问。

1.3 数据分区,减少线程访问冲突

CLOG日志即事务提交日志,用来记录事务的最终状态,是XLOG日志的辅助,用来加速通过日志判断事务状态的过程,存在四种事务状态,即:IN_PROGRESS、COMMITED、ABORTED、SUB_COMMITED,每条日志占2 bit,CLOG需要存储在磁盘上,一个页面(8k)可包含215条,每个日志文件(段=2048x8k)226条,而日志ID位32位,因此可能存在256个clog文件,CLOG文件在 PGDATA/pg_clog 目录下,为了加速对磁盘文件的访问,对CLOG的访问是通过缓冲池实现的,代码中使用统一的SLRU缓冲池。

优化前CLOG的日志缓冲池在共享内存中且全局唯一,名称为“CLOG Ctl”,各工作线程使用由线程局部变量ClogCtl来指向该资源,在高并发的场景下,该资源的竞争成为性能瓶颈。优化后按照PageNo将日志均分到多个共享内存的缓冲池中,由线程局部对象的数组 ClogCtlData来记录,名称为“CLOG Ctl i”,同步增加共享内存中的缓冲池对象及对应的全局锁。

类似的,对内部其他的共享关键数据结构也都进行了数据分区。

1.4 并发控制算法调整,减少单点瓶颈

优化前事务启动获取事务快照,需要获取ProcArrayLock。事务结束清理事务状态快照时,需要获取ProcArrayLock。并发连接增大时导致全局事务管理器上获取的快照变大。

优化后使用事务提交快照,每个非只读事务在运行过程中会取得一个XID,在事务提交时会推进CSN,同时会将当前CSN与事务的XID映射关系保存起来。棕色竖线表示取snapshot时刻,如果不使用CSN方案,那么棕色竖线对应snapshot的集合应该是{2,4,6}。如果采用CSN方案,会获取当前的CSN值,也就是3,事务TX2、TX4、TX6、TX7、TX8的CSN分别为4、6、5、7、8,对于该snapshot而言,这几个事务的修改都不可见。

1.5 借助ARM原子指令,减少计算开销

传统编译器的原子操作默认采用ll/sc原子指令,任何核要获取共享变量的写权限,必须先 “排他性”的获取共享全部变量的ownership,即把“最新数据”先Load到本核所在的L1 Cache中,才能进行修改操作,在多CPU的情况下,会由于激烈的竞争导致系统性能下降。

在ARMv8.1引入了一种新的原子操作LSE,将计算操作放到存储端去做,从而提升计算性能。理论上在多核系统下,LSE的性能优于ll/sc, 实测在6.4.0中使用LSE的性能在高并发下是ll/sc的3~5倍。

openGauss鲲鹏多核优化结果

数据库系统运行会涉及多种资源,包括CPU,内存,网络IO,磁盘IO。性能优化的极致就是各个资源占用恰好都达到瓶颈点。但在实际调优时,环境可能是由各种硬件组成的,所以调优的目标偏重会有不同,但充分发挥CPU的能力是一个系统调优的基本目标。经过针对NUMA架构优化后,openGauss基于鲲鹏920,TPCC测试性能达到150W tpmC,CPU运行效率接近95%,这些实际实验数据表明,openGauss充分发挥了CPU的多核算力。

openGauss开源社区官方网站:https://opengauss.org

openGauss组织仓库:https://gitee.com/opengauss

openGauss镜像仓库:https://github.com/opengauss-mirror

云数据库 GaussDB(for openGauss) 鲲鹏

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Qt6 程序开机自启找不到配置文件及外部程序
下一篇:Apache ZooKeeper - JMX监控 ZooKeeper 的运行状态
相关文章