第二章 checkpoint机制 - 介绍

2024-05-11 08:20

本文主要是介绍第二章 checkpoint机制 - 介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Checkpoint介绍

1、介绍

PostgreSQL基于DRAM+HDD/SSD两层存储架构,所有读写都在DRAM中进行。由于数据写大部分都是随机的,为提高数据库性能,通过写前日志WAL将所有修改都记录到日志中,事务提交时,将日志持久化到磁盘即可,而脏数据页由后台进程异步刷写磁盘,从而将随机写转换成顺序写。

崩溃重启时通过WAL日志将修改回放出来,从而保证数据持久性和一致性,但是如果所有事务的WAL日志都需要回放的话,一旦日志量非常大时,恢复时间就会很长。为减小恢复时间,PostgreSQL通过checkpoint将脏数据刷写到磁盘,崩溃恢复时,只需将checkpoint之后的日志回放即可。

PostgreSQL由checkpoint进程完成刷写脏页(还有一个后台进程bgwriter也会刷写脏页,本文不做过多介绍),并生成一个CHECKPOINT的WAL日志,同时将checkpoint位置记录到pg_control文件中。重启恢复时,从pg_control文件中读取checkpoint位置,作为读取WAL日志和回放的起始位置。启动后可以看到checkpoint进程:

80259 ? Ss 0:00 /home/yzs/bin/postmaster -D /home/yzs/data/
80260 ? Ss 0:00 \_ postgres: logger
80262 ? Ss 0:00 \_ postgres: checkpointer
80263 ? Ss 0:00 \_ postgres: background writer
80264 ? Ss 0:00 \_ postgres: walwriter
80265 ? Ss 0:00 \_ postgres: autovacuum launcher
80266 ? Ss 0:00 \_ postgres: stats collector
80267 ? Ss 0:00 \_ postgres: autoprewarm master
80268 ? Ss 0:00 \_ postgres: logical replication launcher

当将checkpoint子进程kill -9杀掉后,其他进程也会重新启动,这也说明checkpoint子进程对数据一致性有很重要保护作用。

pg_control文件记录的checkpoint信息:

2、checkpoint相关参数

1)log_checkpoints

该参数默认关闭,开启后将每次checkpoint详细信息记录到错误日志中,可以通过此信息了解系统负载。一个相关信息如下:

“checkpoint starting: immediate force wait”//这条信息由函数LogCheckpointStart输出
“checkpoint complete: wrote 1 buffers (0.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.000 s, sync=0.000 s, total=0.001 s; sync files=1, longest=0.000 s, average=0.000 s; distance=0 kB, estimate=11948 kB”//这条信息由函数LogCheckpointEnd输出

2)checkpoint_warning

该参数默认30s,如果填充的WAL段文件导致检查点之间的间隔低于这个参数表示的时间,就向服务器日志写一个消息。0表示关闭警告。如果checkpoint_timeout小于checkpoint_warning值,则不会有警告产生。如果磁盘性能好,可以适当将这个值设置小点,但这个参数不会影响性能,仅用于检查检查点的频率。

3)checkpoint_timeout

自动检查点之间的最长时间。如果没有指定单位,则以秒为单位。默认值是5分钟。增加这个值,会增加崩溃恢复的时间。

checkpoint_timeout用到的位置:

  • checkpoint进程距上次检查点时间超过这个值,就强制触发检查点。在3节 checkpoint发生时机详细介绍。
  • Checkpoint进程执行完一次检查点后,如果执行的时间不够checkpoint_timeout 时间,则等待直到达到这个时间,流程简化后:
CheckpointerMainfor(;;){now = (pg_time_t) time(NULL);CreateCheckPoint(flags);//执行检查点last_checkpoint_time = now;//检查点开始时间now = (pg_time_t) time(NULL);elapsed_secs = now - last_checkpoint_time;//检查点执行的时间if (elapsed_secs >= CheckPointTimeout)continue;//检查点超时,不进行休眠cur_timeout = CheckPointTimeout - elapsed_secs;(void) WaitLatch(MyLatch,WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,cur_timeout * 1000L /* convert to ms */ ,WAIT_EVENT_CHECKPOINTER_MAIN);//检查点休眠}
  • 每次刷写完一个脏页后进行检查点调度判断,若刷写IO太过频繁则休息100ms
BufferSync->CheckpointWriteDelay->|-- IsCheckpointOnSchedulegettimeofday(&now, NULL);elapsed_time = ((double) ((pg_time_t) now.tv_sec - ckpt_start_time) +now.tv_usec / 1000000.0) / CheckPointTimeout;//脏页刷写率大于checkpoint消耗时间率的话,需要sleep 100msif (progress < elapsed_time){ckpt_cached_elapsed = elapsed_time;return false;}|-- pg_usleep(100000L);

 注意:IsCheckpointOnSchedule中除了判断时间的进度外,会先对日志产生的进度进行判断,从而对刷新脏页进行限速

if (RecoveryInProgress())recptr = GetXLogReplayRecPtr(NULL);//恢复场景:回放的WAL日志lsn
elserecptr = GetInsertRecPtr();//产生的WAL的lsn
elapsed_xlogs = (((double) (recptr - ckpt_start_recptr)) /wal_segment_size) / CheckPointSegments;//检查点以来产生WAL的进度
if (progress < elapsed_xlogs){ckpt_cached_elapsed = elapsed_xlogs;return false;
}

4)min_wal_size

用于回收WAL文件时设置未来日志文件段号值。段号值最小即为min_wal_size计算所得。所以只要WAL磁盘用量保持在这个设置之下,在检查点时旧的文件总是被回收以便未来使用,而不是直接删除。这个可以用来确保足够的WAL空间被保留下来应付WAL使用高峰,例如大量写任务下。如果指定时没有单位,则以MB为单位,默认80MB。

执行完checkpoint后,回收WAL文件时,用于判断回收后日志文件段号的范围:

XLOGfileslopminSegNo = RedoRecPtr / wal_segment_size +ConvertToXSegs(min_wal_size_mb, wal_segment_size) - 1;maxSegNo = RedoRecPtr / wal_segment_size +ConvertToXSegs(max_wal_size_mb, wal_segment_size) - 1;distance = (1.0 + CheckPointCompletionTarget) * CheckPointDistanceEstimate;/* add 10% for good measure. */distance *= 1.10;recycleSegNo = (XLogSegNo) ceil(((double) RedoRecPtr + distance) /wal_segment_size);if (recycleSegNo < minSegNo)recycleSegNo = minSegNo;if (recycleSegNo > maxSegNo)recycleSegNo = maxSegNo;return recycleSegNo;

 说明:回收WAL日志文件后,增加的段号要在min_wal_size和max_wal_size范围内

5)max_wal_size

自动WAL检查点之间允许WAL增长到的最大尺寸。这是一个软限制,特殊情况下WAL尺寸会超过max_wal_size。如果没有指定单位,则以MB为单位,默认1GB。增加这个参数会增加崩溃恢复时间。

在回收WAL文件时,预留的日志文件号最大是这个值计算出的段文件号。也就是说超过这量的日志需要删除。

另外就是和checkpoint_complete_target联合使用。

用到该参数的地方除了上文介绍的回收WAL日志文件处外,还用于计算CheckPointSegments值(checkpoint触发值),该值同样用于判断是否进行检查点调度。该值计算方法:

CalculateCheckpointSegmentstarget = (double) ConvertToXSegs(max_wal_size_mb, wal_segment_size) /(1.0 + CheckPointCompletionTarget);CheckPointSegments = (int) target;if (CheckPointSegments < 1)CheckPointSegments = 1;

说明:如果检查点不能立即完成,则老WAL日志就不能立即删除。max_wal_size规定了WAL日志的最大值。达到WAL日志大小的顶峰是checkpoint即将执行完成的时刻,因为此时包含这次触发的WAL日志加上新增的WAL日志。假设触发值是target,则checkpoint_timeout时间内,WAL日志新增大小最多为target。假设WAL日志增长速度相同,则此时增长的日志大小为target*checkpoint_completion_target,为保证峰值,wal日志大小是max_wal_size,由此可以计算出触发值:

target+target*checkpoint_completion_target=max_wal_size
target=max_wal_size/(1+checkpoint_completion_target)

6)checkpoint_completion_target

该参数表示checkpoint的完成时间占两次checkpoint时间间隔的比例,默认值是0.5,也就是说每个checkpoint需要在checkpoint时间间隔checkpoint_timeout的50%内完成。Checkpoint执行会消耗大量系统资源,尤其时IO资源,需要对IO进行限速以减少系统影响,使得磁盘IO变得平缓。

这个值除了在计算WAL日志大小触发checkpoint阈值(上小节介绍)、计算回收日志后最大段号(min_wal_size部分介绍)外,还在判断是否进行checkpoint调度时用到:

IsCheckpointOnScheduleprogress *= CheckPointCompletionTarget;//将刷脏页率缩放后,用于后续判断....

7)checkpoint_flush_after

自动上次checkpoint以来刷写了这么多脏页后,发起sync操作。这样做限制操作系统缓冲中脏页数量,降低checkpoint末尾发出sync或者OS在后台大批量写回数据时被卡住的可能性。如果没有指定单位,默认是页数,指定MB则转换成页数。

由函数ScheduleBufferTagForWriteback进行sync调度。

SyncOneBufferFlushBuffer(bufHdr, NULL);//刷写一个脏页tag = bufHdr->tag;ScheduleBufferTagForWriteback(wb_context, &tag);//调度是否sync|--	if (*context->max_pending > 0){//将脏页sync请求放入请求队列pending = &context->pending_writebacks[context->nr_pending++];pending->tag = *tag;}if (context->nr_pending >= *context->max_pending)IssuePendingWritebacks(context);//若请求数>=checkpoint_flush_after则sync//context->max_pending来自checkpoint_flush_afterBufferSync->WritebackContextInit(&wb_context, &checkpoint_flush_after);context->max_pending = max_pending;context->nr_pending = 0;

3、checkpoint发生时机

Checkpoint触发时机分为以下多种:

1)时间触发:后台checkpoint进程,距上次执行时间超过checkpoint_timeout值就会触发。由时间超时触发的时机:

CheckpointerMain:for (;;){now = (pg_time_t) time(NULL);elapsed_secs = now - last_checkpoint_time;//距上次检查点时间if (elapsed_secs >= CheckPointTimeout){//超过checkpoint_timeoutdo_checkpoint = true;flags |= CHECKPOINT_CAUSE_TIME;//发起CHECKPOINT_CAUSE_TIME的检查点}if (do_checkpoint){CreateCheckPoint(flags);last_checkpoint_time = now;//checkpoint开始时间}...}

2)数据库正常关闭时,触发一次:

CheckpointerMainpqsignal(SIGUSR2, ReqShutdownHandler);/* 注册信号处理函数 */for (;;){if (shutdown_requested){//checkpoint进程接收到shutdown请求ExitOnAnyError = true;ShutdownXLOG(0, 0);|--	CreateCheckPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE);proc_exit(0);}...}
//接收到信号SIGUSR2后,发起shutdown checkpoint
static void ReqShutdownHandler(SIGNAL_ARGS)
{int			save_errno = errno;shutdown_requested = true;SetLatch(MyLatch);errno = save_errno;
}

3)数据库崩溃恢复,修复完成后触发一次:

StartupXLOG//为恢复进程CreateCheckPoint(CHECKPOINT_END_OF_RECOVERY | CHECKPOINT_IMMEDIATE);

4)手动执行CHECKPOINT命令

5)基础备份:当进行数据库基础备份时,会执行pg_start_backup->do_pg_start_backup触发一次:

do_pg_start_backupRequestCheckpoint(CHECKPOINT_FORCE | CHECKPOINT_WAIT |(fast ? CHECKPOINT_IMMEDIATE : 0));

6)每次将日志XLogWrite写入磁盘并且一个WAL日志文件写满后,自从上次checkpoint以来产生的超过max_wal_size放大checkpoint_completion_target后触发一次:

XLogWriteif (finishing_seg){//写满一个WAL段文件if (IsUnderPostmaster && XLogCheckpointNeeded(openLogSegNo)){(void) GetRedoRecPtr();if (XLogCheckpointNeeded(openLogSegNo))RequestCheckpoint(CHECKPOINT_CAUSE_XLOG);}}
//判断WAL自从上次checkpoint以来产生量是否超过阈值
static bool XLogCheckpointNeeded(XLogSegNo new_segno)
{XLogSegNo	old_segno;XLByteToSeg(RedoRecPtr, old_segno, wal_segment_size);if (new_segno >= old_segno + (uint64) (CheckPointSegments - 1))return true;return false;
}
//其中CheckPointSegments来自函数CalculateCheckpointSegments,由max_wal_size放大
//checkpoint_completion_target倍后计算得来,在第2节的max_wal_size中介绍。

4、checkpoint监控

除了log_checkpoints监听日志的方式外,还可以通过pg_stat_bgwriter视图查看checkpoint。下面介绍与checkpoint相关的列:

checkpoints_timed

因为时间触发的次数

checkpoints_req

其他原因触发的次数

checkpoint_write_time

缓存刷写到文件系统cache花费的时间

checkpoint_sync_time

缓存对应的文件系统cache刷写到磁盘花费的时间

buffers_checkpoint

buffer刷新到磁盘的数目

buffers_backend

checkpoint接收到sync请求次数

buffers_backend_fsync

后台因为发送sync请求失败,需要自身执行fsync操作的次数

stats_reset

更新时间

这篇关于第二章 checkpoint机制 - 介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/979001

相关文章

java中反射(Reflection)机制举例详解

《java中反射(Reflection)机制举例详解》Java中的反射机制是指Java程序在运行期间可以获取到一个对象的全部信息,:本文主要介绍java中反射(Reflection)机制的相关资料... 目录一、什么是反射?二、反射的用途三、获取Class对象四、Class类型的对象使用场景1五、Class

MySQL中慢SQL优化的不同方式介绍

《MySQL中慢SQL优化的不同方式介绍》慢SQL的优化,主要从两个方面考虑,SQL语句本身的优化,以及数据库设计的优化,下面小编就来给大家介绍一下有哪些方式可以优化慢SQL吧... 目录避免不必要的列分页优化索引优化JOIN 的优化排序优化UNION 优化慢 SQL 的优化,主要从两个方面考虑,SQL 语

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程

Python实现html转png的完美方案介绍

《Python实现html转png的完美方案介绍》这篇文章主要为大家详细介绍了如何使用Python实现html转png功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 1.增强稳定性与错误处理建议使用三层异常捕获结构:try: with sync_playwright(

Java使用多线程处理未知任务数的方案介绍

《Java使用多线程处理未知任务数的方案介绍》这篇文章主要为大家详细介绍了Java如何使用多线程实现处理未知任务数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 知道任务个数,你可以定义好线程数规则,生成线程数去跑代码说明:1.虚拟线程池:使用 Executors.newVir

JAVA SE包装类和泛型详细介绍及说明方法

《JAVASE包装类和泛型详细介绍及说明方法》:本文主要介绍JAVASE包装类和泛型的相关资料,包括基本数据类型与包装类的对应关系,以及装箱和拆箱的概念,并重点讲解了自动装箱和自动拆箱的机制,文... 目录1. 包装类1.1 基本数据类型和对应的包装类1.2 装箱和拆箱1.3 自动装箱和自动拆箱2. 泛型2

Nginx之upstream被动式重试机制的实现

《Nginx之upstream被动式重试机制的实现》本文主要介绍了Nginx之upstream被动式重试机制的实现,可以通过proxy_next_upstream来自定义配置,具有一定的参考价值,感兴... 目录默认错误选择定义错误指令配置proxy_next_upstreamproxy_next_upst

Spring排序机制之接口与注解的使用方法

《Spring排序机制之接口与注解的使用方法》本文介绍了Spring中多种排序机制,包括Ordered接口、PriorityOrdered接口、@Order注解和@Priority注解,提供了详细示例... 目录一、Spring 排序的需求场景二、Spring 中的排序机制1、Ordered 接口2、Pri

MySQL 缓存机制与架构解析(最新推荐)

《MySQL缓存机制与架构解析(最新推荐)》本文详细介绍了MySQL的缓存机制和整体架构,包括一级缓存(InnoDBBufferPool)和二级缓存(QueryCache),文章还探讨了SQL... 目录一、mysql缓存机制概述二、MySQL整体架构三、SQL查询执行全流程四、MySQL 8.0为何移除查

一文详解Java Condition的await和signal等待通知机制

《一文详解JavaCondition的await和signal等待通知机制》这篇文章主要为大家详细介绍了JavaCondition的await和signal等待通知机制的相关知识,文中的示例代码讲... 目录1. Condition的核心方法2. 使用场景与优势3. 使用流程与规范基本模板生产者-消费者示例