目录
openGauss数据库SQL引擎
openGauss数据库执行器技术
openGauss存储技术
一、openGauss存储概览
二、openGauss行存储引擎
三、openGauss列存储引擎
四、openGauss内存引擎
Ⅰ.内存引擎的兼容性设计
Ⅱ.内存引擎索引
Ⅲ.内存引擎的并发管制
Ⅳ.内存引擎的内存管控
Ⅴ.内存引擎的长久化
openGauss事务机制
openGauss数据库安全
openGauss存储技术
四.openGauss内存引擎
内存引擎的并发管制03
内存引擎的并发管制机制采纳OCC,在操作数据抵触少的场景下,并发性能很好。
内存引擎的事务周期以及并发管控组件构造,如图42所示。
图42 内存引擎的事务周期以及并发管控组件构造
这里须要解释一下,内存引擎的数据组织为什么整体是一个靠近无锁化的设计。
除去以上提到的Masstree自身的无锁化机制外,内存引擎的流程机制也进一步最小化了并发抵触的存在。
每个工作线程会将事务处理过程中所有须要读取的记录,复制一份至本地内存,保留在read-set(读数据集)中,并在事务全程基于这些本地数据进行相应计算。相应的运算后果保留在工作线程本地的write set(写数据集)中。直至事务运行结束,工作线程会进入尝试提交流程,对read set(读数据集)和write set进行validate(查看验证)操作并在容许的状况下对write set中数据对应的全局版本进行更新。
这样的流程,会把事务流程中对于全局版本的影响,放大到validation的过程,而在事务进行其余任何操作的过程中都不会影响到其余的并发事务。并且,在仅有的validation(查看验证)过程中,所须要的也并不是传统意义上的锁,而仅是记录头部信息中的代表锁的数位(lock bit)。相应的这些思考,都是为了最小化并发中可能呈现的资源争抢以及抵触,并更无效地应用CPU缓存。
同时read set(读数据集)和write set(写数据集)的存在,能够良好地反对各个隔离级别,不同隔离级别能够通过在validation(查看验证)阶段对read set(读数据集)和write set(写数据集)进行不同的审查机制来取得。通过查看两个set(数据集)中行记录在全局版本中对应的lock bit(锁定位)以及行头中的TID构造,能够判断本人的读、写与其余事务的抵触状况,进而判断本人在不同隔离级别下是否能够commit(提交)、或是须要abort(终止)。同时因为Masstree中Trie node中存在版本记录,Masstree的结构性改变(insert/delete,插入/删除)会更改相干Trie node(节点)下面的版本号。因而保护一个Range query(范畴查问)波及的node set(节点集),并在validation(查看验证)阶段对其进行比照校验,能够比拟容易地在事务提交阶段查看此Range query所波及的子集是否有过变动,从而可能检测到Phantom(幻读)的存在,是一个工夫复杂度很低的操作。
内存引擎的内存管控04
因为内存引擎的数据是全内存态的,因而能够依照记录来组织数据,不须要听从页面的数据组织模式,从而从数据操作的抵触粒度这一点上有着很大劣势。解脱了段页式的限度,不再须要共享缓存区进行缓存以及与磁盘间的交互淘汰,设计上不须要思考IO以及磁盘性能的优化(比方索引B+ 树的高度以及HDD(Hard Disk Driv,磁盘)对应的随机读写问题),数据读取和运算就能够进行大量的优化和并发改进。
因为是全内存的数据状态,内存资源的管控就显得尤为重要,内存分配机制及实现会很大水平上影响到内存引擎的计算吞吐能力。内存引擎的内存治理次要分为3层,如图43所示。
图43 内存引擎的内存治理示意图
上面别离对3层设计进行介绍:
(1) 第一层为内存引擎本身,蕴含了长期的内存应用以及长期的内存应用(数据存储)。
(2) 第二层为对象的内存池,次要负责为第一层对象如表、索引、行记录、Key值、以及Sentinel(行指针)提供内存。该层从底层索取大块内存,再进行细粒度的调配。
(3) 第三层为资源管理层,次要负责与操作系统之间的交互,以及理论的内存申请。为升高内存申请的调用开销,交互单位个别在2 MB左右。此层同时也有内存预取和预占用的性能。
第三层实际上是十分重要的,次要因为:
(1) 内存预取能够十分无效的升高内存调配开销,进步吞吐量。
(2) 与NUMA库进行交互的性能老本十分高,如果间接放在交互层会对性能产生很大影响。
内存引擎对短期与长期的内存应用针对NUMA构造适配的角度也是不同的。短期应用,个别为事务或session(会话)自身,那么此时个别须要在解决该session的CPU核对应的NUMA节点上获取本地内存,使得transaction(交易)自身的内存应用有着较小的开销;而长期的内存应用,如表、索引、记录的存储,则须要NUMA概念中interleaved内存,并且要尽量平均分配在各个NUMA节点上,来避免单个NUMA节点内存耗费过多带来的性能降落。
短期的内存应用,也就是NUMA角度的本地内存,也有一个很重要的个性,就是这部分内存仅供本事务本身应用(比方复制的读取数据以及做出的更新数据),因而也就防止了这部分内存上的并发管控。
内存引擎的长久化05
内存引擎基于同步的WAL机制以及Checkpoint(检查点)来保证数据的长久化,并且此处通过兼容openGauss的WAL机制(即Transaction log,事务日志),在数据长久化的同时,也能够保证数据可能在主备节点之间进行同步,从而提供RPO=0的高牢靠以及较小RTO的高可用能力。
内存引擎的长久化机制如图44所示。
图44 内存引擎的长久化机制
能够看到,openGauss的Xlog模块被内存引擎对应的manager(管理器)所调用,长久化日志通过WAL的writer线程(刷新磁盘线程)写至磁盘,同时被wal_sender(事务日志发送线程)调起发往备机,并在备机wal_receiver(事务日志接管线程)处接管、落盘与复原。
内存引擎的Checkpoint也是依据openGauss本身的Checkpointer机制被调起。
openGauss中的Checkpoint机制是通过在做Checkpoint时进行shared_buffer(共享缓冲区)中脏页的刷盘,以及一条非凡checkpoint日志来实现的。内存引擎因为是全内存存储,没有脏页的概念,因而实现了基于CALC的Checkpoint机制。
这里次要波及一个局部多版本(partial multi-versioning)的概念:当一个Checkpoint指令被下发,应用两个版本来追踪一个记录:沉闷(live)版本,也就是该记录的最新版本;稳固(stable)版本,也就是在Checkpoint被下发、造成虚构一致性点时此记录对应的版本。在一致性点之前提交的事务须要更新沉闷(live)和稳固(stable)两个版本,而在一致性点之后的事务仅更新沉闷(live)版本本放弃stable版本不变。在无Checkpoint状态的时候,实际上稳固(stable)版本是空的,代表着stable与live版本在此时理论是雷同的值;仅有在Checkpoint过程中,在一致性点后有事务对记录进行更新,此时才会须要依据双版本来保障checkpoint与其余失常事务流程的并行运作。
CALC(Checkpointing Asynchronously using Logical Consistency,逻辑一致性异步检查点)的实现有5个阶段:
(1) rest(劳动)阶段:这个阶段内,没有Checkpoint(检查点)的流程,每个记录仅存储live版本。
(2) prepare(筹备)阶段:整个零碎触发Checkpoint后,会马上进入这个阶段。在这个阶段中事务对读写的更改,也会更新live版本;然而在更新前,如果stable版本不存在,那么在更新live版本前,live版本的数据会被存入stable版本。在此事务的更新完结,在放锁前,会进行查看:如果此时零碎依然处于prepare阶段,那么刚刚生成的stable版本能够被移除;反之,如果整个零碎曾经脱离prepare阶段进入下一阶段,那么stable版本就会被保留下来。
(3) resolve(解析)阶段:在进入prepare阶段前产生的所有事务都已提交或回滚后,零碎就会进入resolve阶段,进入这个阶段也就代表着一个虚构一致性点曾经产生,在此阶段前提交的事务相干的改变都会被反映到此次Checkpoint中。
(4) capture(捕捉)阶段:在prepare阶段所有事务都完结后,零碎就会进入capture阶段。此时后盾线程会开始将Checkpoint对应的版本(如果没有stable版本的记录即则为live版本)写入磁盘,并删除stable版本。
(5) complete(实现)阶段:在Checkpoint写入过程完结后,并且capture阶段中进行的所有事务都完结后,零碎进入complete阶段,零碎事务的写操作的体现会复原和rest阶段雷同的默认状态。
CALC有着以下长处:
(1) 低内存耗费:每个记录至少在Checkpoint时造成两份数据。在Checkpoint进行中如果该记录stable版本和live版本雷同,或在没有checkpoint的状况下,内存中只会有数据本身的物理存储。
(2) 较低的实现代价:绝对其余内存库Checkpoint机制,对整个零碎的影响较小。
(3) 应用虚构一致性点:不须要阻断整个数据库的业务以及解决流程来达到一份物理一致性点,而是通过局部多版本来达到一个虚构一致性点。
至此,“openGauss存储技术”章节全副完结,下一篇文章将开始对“openGauss事务机制”章节进行解说,敬请期待......