当数据库发生宕机重启之后需要从检查点位置开始回放之后所有的日志。不同类型的日志的回放逻辑由对应的资源管理器来实现。
当用户业务压力较大时会同时有很多业务线程并发执行事务和日志记录的插入,单位时间内产生的日志量是非常大的。对此openGauss采用多种回放线程组来进行日志的并行回放,各个回放线程组之间采用高效的流水线工作方式,各个回放线程组内采用多线程并行的工作方式,以便保证日志的回放速率不会明显低于日志产生的速率。

图4-35 openGauss并行回放流程示意图
openGauss并行回放流程如图4-35所示,其中每个线程(组)的运行机制如下。
(1) “Walreceiver”线程收到日志成功写入磁盘后,“XLogReadWorker”线程从“Walreceiver”线程的缓冲区中读取字节流,“XLogReadManager”线程将字节流decode(解码)成redoitem(单个回放对象)。“Startupxlog”线程按照表文件名粒度(refilenode)将redoitem发放给各个“ParseRedoRecord”线程,其他的日志发送给“TrxnManager”线程。
(2) “ParseRedoRecord”线程负责表文件(relation)相关的日志处理,从队列中获取批量的日志进行解析,将日志按照页面粒度进行拆分,然后发给“PageRedoManager”线程。拆分原理如下。
针对行存储表、索引等数据页面操作的日志,按照涉及的页面个数拆成多条日志。例如heap_update日志,如果删除的老元组和插入的新元组在不同的页面上,那么会被拆成2条,分别插入到哈希表中。
xact、truncate、drop database等日志是针对表的,不能进行拆分。针对这些日志,先清理掉哈希表中相关日志,然后等这些日志之前的日志都回放之后,再在PageRedoManger中进行回放,并将该日志分发给所有“PageRedoWorker”线程来进行invalid page(无效页面)的清理、数据写入磁盘等操作。
针对Createdb(创建数据库)操作要等所有“PageRedoWorker”线程将Createdb日志之前的日志都回放后,再由一个“PageRedoManager”线程进行Createdb操作的回放。这个过程中其余线程需要等待Createdb操作回放结束后才能继续回放后续日志。
(3) “PageRedoManager”线程利用哈希表按照页面粒度组织日志,同一个页面的日志按照lsn顺序放入到一个列表中,之后将页面日志列表分发给“PageRedoWorker”线程。
(4) “PageRedoWorker”线程负责页面日志回放功能,从队列中获取一个日志列表进行批量处理。
(5) “TrxnManager”线程负责事务相关的XLOG日志的分发,以及需要全局协调的事务处理。
(6) “TrxnWorker”线程负责事务日志回放功能,从队列中获取一个日志进行处理。当前只有一个“TrxnWorker”线程负责处理事务日志。
为了保证高效的日志分发性能,“PageRedoManager”进程和“PageRedoWorker”进程之间采用了带阻塞功能的无锁单生产者单消费者(single producer single consumer,SPSC)队列。如图4-36所示,分配线程作为生产者将解析后的日志放入回放线程的列队中,回放线程从队列中消费日志进行回放。另一方面为了提升整体并行回放机制的可靠性,会在一个页面的回放动作中对日志记录头部的lsn和页面头部的lsn进行校验,以保证回放过程中数据库系统的一致性。

图4-36 无锁SPSC队列示意图
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




