当前位置: 首页 > article >正文

openGauss极致RTO流程讲解及运维方法

极致RTO简单介绍

极致RTO是openGauss在并行回放的基础上,实现的一个加速回放功能。其主要原理是将record粒度的日志拆分成block粒度的日志进行回放,通过增加流水线和redoworker线程的数量,并且利用相关hash算法,保证同一张表的日志由同一流水线回放,以此提高回放速度和回放并发度。

极致RTO相关参数

recovery_parse_workers > 1 或 recovery_redo_workers > 1,即为开启极致RTO.

recovery_parse_workers

参数说明: 是极致RTO特性中ParseRedoRecord线程的数量。

该参数属于POSTMASTER类型参数,请参考表1中对应设置方法进行设置。

取值范围:整型,1~16

仅在开启极致RTO情况下可以设置recovery_parse_workers为>1。需要配合recovery_redo_workers使用。若同时开启recovery_parse_workers和recovery_max_workers,以开启极致RTO的recovery_parse_workers为准,并行回放特性失效。因极致RTO不支持主备从模式,仅在参数replication_type设置成1时可以设置recovery_parse_workers为>1。另外,极致RTO也不支持列存,在已经使用列存表或者即将使用列存表的系统中,请关闭极致RTO。极致RTO不再自带流控,流控统一由recovery_time_target参数来控制。

默认值: 1

recovery_redo_workers

参数说明: 是极致RTO特性中每个ParseRedoRecord线程对应的PageRedoWorker数量。

该参数属于POSTMASTER类型参数,请参考表1中对应设置方法进行设置。

取值范围:整型,1~8

需要配合recovery_parse_workers使用。在配合recovery_parse_workers使用时,只有recovery_parse_workers大于1,recovery_redo_workers参数才生效。

默认值: 1

recovery_parallelism

参数说明: 查询实际回放线程个数,该参数为只读参数,无法修改。

该参数属于POSTMASTER类型参数,受recovery_max_workers以及recovery_parse_workers参数影响,任意一值大于0时,recovery_parallelism将被重新计算。

取值范围: 整型,1~2147483647

exrto_standby_read_opt

参数说明:支持极致RTO备机读优化,默认开启。主机和备机间不同步该参数。 该参数属于POSTMASTER类型参数,请参考表1中对应设置方法进行设置。(该功能在社区还属于创新版) (传统HA模式特有参数,资源池化模式原生支持极致RTO+备机读)

取值范围:布尔型。

  • on表示开启优化。
  • off表示关闭优化。

默认值:on

极致RTO回放线程类型

REDO_BATCH 负责record粒度的日志拆分成block粒度,并分发给redo manager线程

REDO_PAGE_MNG, 负责向redo worker线程分发xlog

REDO_PAGE_WORKER, 负责回放

REDO_TRXN_MNG, 负责向trxn worker分发xlog

REDO_TRXN_WORKER, 负责回放事务日志

REDO_READ_WORKER, 流复制场景,用于从磁盘读xlog

REDO_READ_PAGE_WORKER, 负责从磁盘读取xlog或从xlog缓冲区读取xlog,并校验完整性

REDO_READ_MNG, 负责控制读xlog线程

REDO_SEG_WORKER, 按需回放新增线程, (非资源池化模式不涉及)

REDO_HTAB_MNG, 按需回放新增线程, (非资源池化模式不涉及)

REDO_CTRL_WORKER, 按需回放新增线程,(非资源池化模式不涉及)

Startup线程:负责将日志分发给对应的流水线

传统HA模式回放流程示意图

主备同步场景,极致RTO处理流程

传统HA场景,用户在主机执行写业务时,backend线程(业务线程)在修改数据时,会先通过wal writer线程向磁盘中写入xlog(也称wal日志、预写日志),然后主机会通过wal sender线程从磁盘中读取xlog日志,发送到备机,由备机的wal receiver接收到后写入到备机的磁盘中。备机将xlog接受到后,由XLogReadWorker线程读取xlog,发送给Startup线程,并分发给回放线程进行回放。在相关的日志回放完成后,用户可以从备机读到相关的数据,以此完成主备节点之间的同步。
在这里插入图片描述

主备故障、备机failover,极致RTO处理流程

主机故障场景,需要备机通过failover进行故障恢复后升主。在此期间,由于主机故障,新主节点的wal receiver线程会退出,XLogReadPageWorker线程会继续从磁盘中把还没读取的xlog继续读完,发送给Startup线程,并分发给回放线程进行回放。当所有的已有xlog全部读取并回放完,新主节点才完成failover阶段,此时该节点正式升为主节点。
在这里插入图片描述

极致RTO流水线示意图

极致RTO回放功能大体流程如下所示:极致RTO是多流水线、多线程架构,由同一xlog读取线程从磁盘中读取,然后经由Startup分发给不同的回放流水线,再由BatchRedo线程将xlog解析为block粒度的日志**(与并行回放的主要差别)**,最后经由RedoManager线程分发给具体的回放线程完成回放。通过特定的hash算法,可以保证同一个表相同block的日志会路由到同一流水线的同一RedoWorker线程回放,以保证日志回放时有序。

所有回放线程之间通过一种无锁队列SPSCBlockingQueue完成xlog在流水线中的分发,每两个互相存在上下级关系的回放线程之间都有一个独有的SPSCBlockingQueue,上级流水线处理后将xlog日志SPSCBlockingQueue,由下级从SPSCBlockingQueue中循环读取并处理。

大体分发流程如下:

  1. 备机的XLogReadWorker线程或XLogReadPageWorker线程从磁盘中按条读取xlog日志,并将读取到的xlog发送给Startup线程,Startup线程会根据xlog的类型,和修改的表的oid等信息选择对应的流水线分发xlog。
  2. 事务日志会通过Startup线程->TrxnManagerMain->TrxnWorkerMain的流程完成回放;
  3. 页面修改的日志会通过Startup->BatchRedoMain->RedoPageManagerMain->RedoPageWorker,完成分发、xlog细粒度化解析、二次分发、回放的处理流程。
    在这里插入图片描述

回放线程数量计算方式

以recovery_redo_workers = 4, recovery_parse_workers = 4 为例,recovery_parallelism = (BatchRedoMain + RedoPageManagerMain + RedoPageWorkerMain * 4) * 4 + TxnManageMain + TrxnWorkerMain + XLogReadPageWorkerMain + XLogReadWorkerMain + XLogReadManagerMain = 29

各线程功能简述

REDO_READ_WORKER

主函数:XLogReadWorkerMain

流复制场景,用于从磁盘读xlog,该线程会把xlog从磁盘读取到g_recordbuffer->xlogsegarray[readindex],read buffer中。

代码流程

XLogReadWorkerMain->XLogReadWorkRun->XLogReadFromWriteBuffer

  1. 获取wal receiver线程从备机接收并刷盘的xlog最新位置。receivedUpto = GetWalRcvWriteRecPtr(NULL);
  2. 获取xlogreadworker线程已经读取到的xlog位置
uint32 readindex = pg_atomic_read_u32(&(g_recordbuffer->readindex));
RecordBufferAarray *readseg = &g_recordbuffer->xlogsegarray[readindex];
  1. 通过比较receivedUpto 和readseg判断有xlog要读
  2. 如果有就调用XLogReadFromWriteBuffer读取xlog,并将xlog写到g_recordbuffer->xlogsegarray[readindex]。
    在这里插入图片描述

REDO_READ_PAGE_WORKER

XLogReadPageWorkerMain,循环读取xlog,将读到的xlog record,解析为XLogReaderState,并置入g_dispatcher->readLine.readPageThd->queue传递给startup线程

  • 流复制场景(传统HA模式),
    • failover阶段,IsRecoveryDone == false,从磁盘读xlog。
    • 备机normal状态,IsRecoveryDone == true,用于从g_recordbuffer->xlogsegarray[readindex]缓冲区读取日志。
  • 资源池化场景,XLogReadPageWorkerMain同时负责读取xlog和解析xlog传递给startup线程。

代码流程

xlog读取主流程

XLogReadPageWorkerMain->XLogParallelReadNextRecord->ParallelReadRecord->ParallelReadPageInternal->ParallelXLogPageRead

读xlog的场景分类

  1. 流复制场景(传统主备):ParallelXLogReadWorkBufRead->XLogPageReadForExtRto
  2. 资源池化,从DSS读xlog文件:SSXLogPageRead
  3. 非池化,通过文件系统读xlog文件:ParallelXLogPageReadFile

XLogReadPageWorkerMain循环流程

  1. 读xlog:XLogParallelReadNextRecord

  2. 生成下一个readerState: NewReaderState

  3. 更新读取最新xlog的起止点:

g_redoWorker->lastReplayedReadRecPtr = xlogreader->ReadRecPtr;
g_redoWorker->lastReplayedEndRecPtr = xlogreader->EndRecPtr;
  1. 更新g_GlobalLsnForwarder:SendLsnFowarder

  2. 把读到的xlog(XLogReaderState)存入队列:PutRecordToReadQueue

在这里插入图片描述

StartupXLOG

代码流程

循环执行以下流程直到XLogReaderState == NULL

  • 从队列中读取下一条xlog:ReadNextXLogRecord->ReadNextRecordFromQueue->SPSCBlockingQueueTake(g_dispatcher->readLine.readPageThd->queue)
    • 读取获取到record后解析xlog,从XLogReaderState解析到XLogRecord,DecodeXLogRecord
    • 如果读到g_redoEndMark.record,则退出循环
    • 如果读取到g_GlobalLsnForwarder.record或g_cleanupMark.record,调用StartupSendFowarder,向所有batchRedo线程和txnmanager线程分发该日志
  • 将xlog解析成RedoItem ,并分发给下一级流水线线程
    • DispatchRedoRecord->ExtremeDispatchRedoRecordToFile->g_dispatchTable[rmid].rm_dispatch(record, expectedTLIs, recordXTime);
    • 根据XLogReaderState 偏移获取RedoItem : RedoItem *item = GetRedoItemPtr(record);
    • 根据xlog的类型(rmid),选择对应的分发方法:g_dispatchTable[rmid].rm_dispatch(record, expectedTLIs, recordXTime);
      • 普通日志通常分发给batchRedo线程(g_dispatcher->pageLines[i].batchThd)。其中,同一个表的日志一般发给某个特定流水线,会通过rnode计算流水线Id:GetSlotId
      • 事务日志分发给txnmanager线程。(g_dispatcher->trxnLine.managerThd),对应函数:DispatchXactRecord
      • ddl相关日志,如果是create table则只分发给对应的流水线、如果是truncate则会分发给所有的流水线,对应函数:DispatchSmgrRecord
    • 不同类型的xlog分发方法参考
      • src\gausskernel\storage\access\transam\extreme_rto\dispatcher.cpp
      • static const RmgrDispatchData g_dispatchTable[RM_MAX_ID + 1]

分发策略:

极致RTO通过ExtremeDispatchRedoRecordToFile函数向下级流水线分发

具体分发方法会根据xlog类型rmid选择对应的分发算法g_dispatchTable[rmid].rm_dispatch(record, expectedTLIs, recordXTime);

在选择流水线时,为了尽量避免回放时的页面交换问题,极致RTO根据relfilenode计算hash值,该hash值用于选择哪一条流水线向下分发日志。对应函数:GetWorkerIds。
在这里插入图片描述

BatchRedoMain

循环把record级别的xlog(RedoItem)解析成Block级别的xlog(XLogRecParseState),并传递给PageRedoManager线程进行回放。

  • 从流水线中循环读取出xlog:BatchRedoMain->SPSCBlockingQueueGetAll(g_redoWorker->queue, &eleArry, &eleNum)
  • 把record级别的xlog(RedoItem)解析成Block级别的xlog(XLogRecParseState): BatchRedoDistributeItems->BatchRedoParseItemAndDispatch->XLogParseToBlockForExtermeRTO->g_xlogParseBlockTable[rmid].xlog_parseblock(record, blocknum)
  • 把 Block级别的xlog分发给下一级流水线:AddPageRedoItem(myRedoLine->managerThd, recordblockstate);

在这里插入图片描述

图中是一条由pg_xlogdump解析出来的xlog日志,该条xlog是一个XLOG_HEAP_UPDATE类型日志,该条xlog涉及到两个跨页面的tuple的修改,即将原tuple(663/15825/15213/-1/0-0 blkno 24 off 41 置为无效),并插入一条新tuple(1663/15825/15213/-1/0-0 blkno 22 off 10)。BatchRedo线程会将该日志拆分为两条block粒度的xlog(XLogRecParseState):

  • 对页面rel 1663/15825/15213/-1/0, forknum:0 storage HEAP DISK blk 24,元组 off 41的修改
  • 对页面rel 1663/15825/15213/-1/0, forknum:0 storage HEAP DISK blk 22,元组 off 10 的修改。

然后把以上解析后的日志分发给下级流水线。

REDO @ 0/80AA0E8; LSN 0/80AA1F0: prev 0/80A9F78; xid 14259; term 1; len 5; total 260; crc 2577088048; desc: Heap - XLOG_HEAP_UPDATE update: off 41 new off 10, blkref #0: rel 1663/15825/15213/-1/0, forknum:0 storage HEAP DISK blk 24 lastlsn 0/7CF57A8, blkref #1: rel 1663/15825/15213/-1/0, forknum:0 storage HEAP DISK blk 22 lastlsn 0/80AA0E8

RedoPageManagerMain

把XLogRecParseState根据rnode等信息,分发给RedoPageWorker线程,

  • RedoPageManagerMain->PageManagerRedoDistributeItems->PageManagerRedoParseState->根据日志类型选择解析方式
  • 通过将xlog置入无锁队列分发给下级流水线:AddPageRedoItem(myRedoLine->redoThd[work_id], record_block_state);

在这里插入图片描述

RedoPageWorkerMain

回放上一层流水线下发的日志。不同xlog类型执行函数不同

RedoPageWorkerMain->XLogBlockRedoForExtremeRTO->g_xlogExtRtoRedoTable[block_valid].xlog_redoextrto(blockhead, blockrecbody, bufferinfo);

在这里插入图片描述

一些关键变量

特殊xlog标记

RedoItem g_redoEndMark = { false, false, NULL, 0, NULL, 0 };

RedoItem g_terminateMark = { false, false, NULL, 0, NULL, 0 };

RedoItem g_GlobalLsnForwarder;

RedoItem g_cleanupMark;

RedoItem g_closefdMark;

RedoItem g_cleanInvalidPageMark;

不同类型XLOG的处理函数

极致RTOxlog分发函数

src\gausskernel\storage\access\transam\extreme_rto\dispatcher.cpp

static const RmgrDispatchData g_dispatchTable[RM_MAX_ID + 1]

极致RTO batchRedo线程解析函数

src\gausskernel\storage\access\redo\redo_xlogutils.cpp

static const XLogParseBlock g_xlogParseBlockTable[RM_MAX_ID + 1] = {

极致RTO 回放函数

src\gausskernel\storage\access\redo\redo_xlogutils.cpp

static const XLogBlockRedoExtreRto g_xlogExtRtoRedoTable[BLOCK_DATA_CSNLOG_TYPE + 1] = {
    { XLogBlockDataCommonRedo, BLOCK_DATA_MAIN_DATA_TYPE }, { XLogBlockVmCommonRedo, BLOCK_DATA_VM_TYPE },
    { XLogBlockUndoCommonRedo, BLOCK_DATA_UNDO_TYPE },
    { XLogBlockFsmCommonRedo, BLOCK_DATA_FSM_TYPE },        { XLogBlockDdlCommonRedo, BLOCK_DATA_DDL_TYPE },
    { XLogBlockBcmCommonRedo, BLOCK_DATA_BCM_TYPE },        { XLogBlockNewCuCommonRedo, BLOCK_DATA_NEWCU_TYPE },
    { XLogBlockClogCommonRedo, BLOCK_DATA_CLOG_TYPE },      { XLogBlockCsnLogCommonRedo, BLOCK_DATA_CSNLOG_TYPE },
};

回放相关视图

select * from dbe_perf.GLOBAL_REDO_STATUS

部分回放信息展示

名称类型描述
node_nametext数据库进程名称。
redo_start_ptrbigint当前实例日志回放的起始点。
redo_start_timebigint当前实例日志回放的起始UTC时间。
redo_done_timebigint当前实例日志回放的结束UTC时间。
curr_timebigint当前实例的当前UTC时间。
min_recovery_pointbigint当前实例日志的最小一致性点位置。(在此之前的日志都回放完毕)
read_ptrbigint当前实例日志的读取位置。
last_replayed_read_ptrbigint当前实例的日志回放位置。(当前实例回放的最新日志)
recovery_done_ptrbigint当前实例启动完成时的回放位置。
speedbigint当前实例日志回放速率,单位:KB/s。
local_max_ptrbigint当前实例启动成功后walreceiver线程收到的回放日志的最大值。
primary_flush_ptrbigint主机落盘日志的位置。

select * from pg_last_xlog_replay_location()

当前xlog的回放位置

openGauss=# select * from pg_last_xlog_replay_location();
 term |    lsn
------+-----------
 1    | 0/84773B8
(1 row)

gs_ctl query可以查询备机的回放进度

其中receiver_replay_location表示备机的回放进度。

[zhoucong_normal@openGauss111 pg_xlog]$ gs_ctl query -D /home/zhoucong_normal/work/data-list/1p2s-6.0.0/node1
[2024-10-29 11:51:16.398][772625][][gs_ctl]: gs_ctl query ,datadir is /home/zhoucong_normal/work/data-list/1p2s-6.0.0/node1
 HA state:
        local_role                     : Standby
        static_connections             : 2
        db_state                       : Normal
        detail_information             : Normal

 Senders info:
No information
 Receiver info:
        receiver_pid                   : 2139555
        local_role                     : Standby
        peer_role                      : Primary
        peer_state                     : Normal
        state                          : Normal
        sender_sent_location           : 0/8822518
        sender_write_location          : 0/8822518
        sender_flush_location          : 0/8822518
        sender_replay_location         : 0/8822518
        receiver_received_location     : 0/8822518
        receiver_write_location        : 0/8822518
        receiver_flush_location        : 0/8822518
        receiver_replay_location       : 0/8822478
        sync_percent                   : 100%
        channel                        : 20.20.20.111:46912<--20.20.20.111:36144

: 0/8822518
receiver_received_location : 0/8822518
receiver_write_location : 0/8822518
receiver_flush_location : 0/8822518
receiver_replay_location : 0/8822478
sync_percent : 100%
channel : 20.20.20.111:46912<–20.20.20.111:36144



http://www.kler.cn/a/421617.html

相关文章:

  • HTTP 探秘之旅:从入门到未来
  • 万字长文解读深度学习——多模态模型BLIP2
  • Kafka配置SASL/PLAINTEXT安全认证
  • 基于链表的基础笔试/面试题
  • 使用ESP32通过Arduino IDE点亮1.8寸TFT显示屏
  • 组合数学——鸽巢原理
  • vue实现懒加载
  • 30分钟学会正则表达式
  • Wwise SoundBanks内存优化
  • renderExtraFooter 添加本周,本月,本年
  • 数据库——创建索引的原则
  • 学成在线day08
  • k8s 亲和性之Affinity
  • 《Python基础》之Pandas库
  • PostgreSQL认证培训需要什么条件
  • 上天入地,智能诊断,多语言支持,璞华IETM打造产品技术信息管理极致用户体验
  • Python虚拟环境管理工具:Pipenv
  • Linux-Ubuntu16.04摄像头 客户端抓取帧并保存为PNG
  • Golang教程第24篇(语言接口)
  • Meta-Llama-3-8B-Instruct 模型的混合精度训练显存需求:AdamW优化器(中英双语)
  • STM32G4系列MCU的Direct memory access controller (DMA)功能之一
  • 更多开源创新 挑战OpenAI-o1的模型出现和AI个体模拟突破
  • 删除 MySQL 的多余实例
  • Redis使用场景-缓存-缓存击穿
  • pytest(二)excel数据驱动
  • winform跨线程更新界面