数据库异常关闭时,数据库关闭时来不及或者没机会做checkpoint,则需要从上一个一致性检查的开始恢复。
PostgreSQL备机checkpoint是不能产生checkpoint WAL的,因为如果写这样类型的checkpoint的话,就会将接收的WAL打乱,那么日志将混乱,回放会出问题。
那么问题来了,备机支持checkpoint吗?他的checkpoint怎么做的?
PostgreSQL为了缩短恢复时间,备机上也支持checkpoint,即CreateRestartPoint。但是其pg_control文件的checkpoint记录的位点是从主机传过来WAL里面的checkpoint记录位置。
调用流程:
StartupXLOGdo{...RmgrTable[record->xl_rmid].rm_redo(xlogreader);|-- RecoveryRestartPoint(&checkPoint);|-- lastCheckPointRecPtr = XLogCtl->lastCheckPointRecPtr;|-- ControlFile->checkPoint = lastCheckPointRecPtr;...record = ReadRecord(xlogreader, InvalidXLogRecPtr, LOG, false);|-- record = XLogReadRecord(xlogreader, RecPtr, &errormsg);|-- ReadRecPtr = xlogreader->ReadRecPtr;} while (record != NULL);ShutdownXLOG->CreateRestartPoint:lastCheckPointRecPtr = XLogCtl->lastCheckPointRecPtr;ControlFile->checkPoint = lastCheckPointRecPtr;
1、备机回放
StartupXLOGdo{...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赋值
ReadRecordfor (;;){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->lastCheckPointRecPtrlastCheckPointEndPtr = 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())//备机写checkpointCreateRestartPoint(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开始重复恢复。
最后修改时间:2019-11-24 18:41:39
文章转载自yanzongshuaiDBA,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




