暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL备机checkpoint

yanzongshuaiDBA 2019-04-19
856

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


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


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


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


调用流程:

    StartupXLOG
    do{
    ...
    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、备机回放

      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开始重复恢复。


                最后修改时间:2019-11-24 18:41:39
                文章转载自yanzongshuaiDBA,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                评论