前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PostgreSQL备机checkpoint

PostgreSQL备机checkpoint

作者头像
yzsDBA
发布2020-10-29 10:50:29
7720
发布2020-10-29 10:50:29
举报
文章被收录于专栏:PostgreSQL研究与原理解析

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

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

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

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

调用流程:

代码语言:javascript
复制
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、备机回放

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

2、回放函数

代码语言:javascript
复制
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

代码语言:javascript
复制
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赋值

代码语言:javascript
复制
ReadRecord
  for (;;)
  {
    char     *errormsg;
 
    record = XLogReadRecord(xlogreader, RecPtr, &errormsg);
    ReadRecPtr = xlogreader->ReadRecPtr;
    EndRecPtr = xlogreader->EndRecPtr;
    ...
  }

5、备机createcheckpoint

代码语言:javascript
复制
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

代码语言:javascript
复制
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-04-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 yanzongshuaiDBA 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档