您好,登錄后才能下訂單哦!
? 數據庫異常關閉時,數據庫關閉時來不及或者沒機會做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、回放函數
void
xlog_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 void
RecoveryRestartPoint(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
bool
CreateRestartPoint(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
void
ShutdownXLOG(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開始重復恢復。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。