千家信息网

PostgreSQL备机checkpoint

发表于:2024-10-17 作者:千家信息网编辑
千家信息网最后更新 2024年10月17日,数据库异常关闭时,数据库关闭时来不及或者没机会做checkpoint,则需要从上一个一致性检查的开始恢复。PostgreSQL备机checkpoint是不能产生checkpoint WAL的,因为如果
千家信息网最后更新 2024年10月17日PostgreSQL备机checkpoint

数据库异常关闭时,数据库关闭时来不及或者没机会做checkpoint,则需要从上一个一致性检查的开始恢复。

PostgreSQL备机checkpoint是不能产生checkpoint WAL的,因为如果写这样类型的checkpoint的话,就会将接收的WAL打乱,那么日志将混乱,回放会出问题。

那么问题来了,备机支持checkpoint吗?他的checkpoint怎么做的?

PostgreSQL为了缩短恢复时间,备机上也支持checkpoint,即CreateRestartPoint。但是其pg_control文件的checkpoint记录的位点是从主机传过来WAL里面的checkpoint记录位置。

1、备机回放

StartupXLOG    do{        ...        RmgrTable[record->xl_rmid].rm_redo(xlogreader);//回放        ...        record = ReadRecord(xlogreader, InvalidXLogRecPtr, LOG, false);//读取一个xlog    } while (record != NULL);

2、回放函数

voidxlog_redo(XLogReaderState *record){    ...    else if (info == XLOG_CHECKPOINT_SHUTDOWN){        ...        memcpy(&checkPoint, XLogRecGetData(record), sizeof(CheckPoint));        ...        RecoveryRestartPoint(&checkPoint);    }else if (info == XLOG_CHECKPOINT_ONLINE){        ...        memcpy(&checkPoint, XLogRecGetData(record), sizeof(CheckPoint));        ...        RecoveryRestartPoint(&checkPoint);    }    ...}

3、RecoveryRestartPoint

static voidRecoveryRestartPoint(const CheckPoint *checkPoint){    ...    SpinLockAcquire(&XLogCtl->info_lck);    XLogCtl->lastCheckPointRecPtr = ReadRecPtr;//ReadRecPtr为读取checkpoint记录后的位置    XLogCtl->lastCheckPointEndPtr = EndRecPtr;    XLogCtl->lastCheckPoint = *checkPoint;    SpinLockRelease(&XLogCtl->info_lck);}

4、ReadRecPtr赋值

ReadRecord    for (;;)    {        char       *errormsg;        record = XLogReadRecord(xlogreader, RecPtr, &errormsg);        ReadRecPtr = xlogreader->ReadRecPtr;        EndRecPtr = xlogreader->EndRecPtr;        ...    }

5、备机createcheckpoint

boolCreateRestartPoint(int flags){    LWLockAcquire(CheckpointLock, LW_EXCLUSIVE);    /* Get a local copy of the last safe checkpoint record. */    SpinLockAcquire(&XLogCtl->info_lck);    lastCheckPointRecPtr = XLogCtl->lastCheckPointRecPtr;//checkpoint的位置来自XLogCtl->lastCheckPointRecPtr    lastCheckPointEndPtr = XLogCtl->lastCheckPointEndPtr;    lastCheckPoint = XLogCtl->lastCheckPoint;    SpinLockRelease(&XLogCtl->info_lck);    ...    if (XLogRecPtrIsInvalid(lastCheckPointRecPtr) || lastCheckPoint.redo <= ControlFile->checkPointCopy.redo){        //回放了最后一个checkpoint记录后,备机再次手动执行checkpoint命令        UpdateMinRecoveryPoint(InvalidXLogRecPtr, true);        if (flags & CHECKPOINT_IS_SHUTDOWN){            LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);            ControlFile->state = DB_SHUTDOWNED_IN_RECOVERY;            ControlFile->time = (pg_time_t) time(NULL);            UpdateControlFile();            LWLockRelease(ControlFileLock);        }        LWLockRelease(CheckpointLock);        return false;    }    ...    LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);    if (ControlFile->state == DB_IN_ARCHIVE_RECOVERY && ControlFile->checkPointCopy.redo < lastCheckPoint.redo){        ControlFile->prevCheckPoint = ControlFile->checkPoint;        ControlFile->checkPoint = lastCheckPointRecPtr;//checkpoint的位置        ControlFile->checkPointCopy = lastCheckPoint;        ControlFile->time = (pg_time_t) time(NULL);        ...        if (flags & CHECKPOINT_IS_SHUTDOWN)            ControlFile->state = DB_SHUTDOWNED_IN_RECOVERY;        UpdateControlFile();    }    ...    return true;}

6、备机shutdown

voidShutdownXLOG(int code, Datum arg){    /*     * Signal walsenders to move to stopping state.     */    WalSndInitStopping();    /*     * Wait for WAL senders to be in stopping state.  This prevents commands     * from writing new WAL.     */    WalSndWaitStopping();    if (RecoveryInProgress())//备机写checkpoint        CreateRestartPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE);    else    {        /*         * If archiving is enabled, rotate the last XLOG file so that all the         * remaining records are archived (postmaster wakes up the archiver         * process one more time at the end of shutdown). The checkpoint         * record will go to the next XLOG file and won't be archived (yet).         */        if (XLogArchivingActive() && XLogArchiveCommandSet())            RequestXLogSwitch(false);        CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE);    }    ShutdownCLOG();    ShutdownCommitTs();    ShutdownSUBTRANS();    ShutdownMultiXact();}

7、总结

PostgreSQL备库也可以写检查点,目的是避免每次重启备库都需要从上一个检查点(由主库产生,在WAL中回放出来的)APPLY后面所有的WAL。但是他记录的checkpoint位点是从主库传过来的。这样的话就有问题了,如果主机很长时间都没有做checkpoint了,备机即使正常关闭,重启时,也会从上一个checkpoint开始恢复,这样也会恢复很长时间;并且多次重启也需要从上一次checkpoint开始重复恢复。

0