第二章 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

更新时间

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3030208.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Java入门基础学习笔记12——变量详解

变量详解&#xff1a; 变量里的数据在计算机中的存储原理。 二进制&#xff1a; 只有0和1&#xff0c; 按照逢2进1的方式表示数据。 十进制转二进制的算法&#xff1a; 除二取余法。 6是110 13是1101 计算机中表示数据的最小单元&#xff1a;一个字节&#xff08;byte&…

通俗的理解网关的概念的用途(一)

网关这个概念最早使用于网络&#xff0c;但在当今的智能设备/产品界中&#xff0c;硬生生的被产品人也搞出来一个“网关”的概念&#xff0c;这让早期的咱们这些只知道网络中的网关的人&#xff0c;听得稀里糊涂的。比如智能门锁、安防摄像头等&#xff0c;在产品的使用和介绍中…

java JMH 学习

JMH 是什么&#xff1f; JMH&#xff08;Java Microbenchmark Harness&#xff09;是一款专用于代码微基准测试的工具集&#xff0c;其主要聚焦于方法层面的基准测试&#xff0c;精度可达纳秒级别。此工具由 Oracle 内部负责实现 JIT 的杰出人士编写&#xff0c;他们对 JIT 及…

服务号转订阅号的操作步骤(吐血整理)

服务号和订阅号有什么区别&#xff1f;服务号转为订阅号有哪些作用&#xff1f;我们知道&#xff0c;公众号分为服务号和订阅号两种&#xff0c;服务号只能企业才可以申请&#xff0c;订阅号是企业和个人都可以申请。其中最大的区别是服务号一个月只能发送4次群发&#xff0c;但…

shopro商城 源码搭建/部署/上线/运营/售后/更新

基于Fastadmin和Uniapp进行开发的多平台&#xff08;微信公众号、微信小程序、H5网页、Android-App、IOS-App&#xff09;购物商城&#xff0c;拥有强大的店铺装修、自定义模板、路由同步、多端支付&#xff08;微信&#xff0c;支付宝&#xff09;、多规格商品、运费模板、多地…

我在洛杉矶采访到了亚马逊云全球首席信息官CISO(L11)!

在本次洛杉矶举办的亚马逊云Re:Inforce全球安全大会中&#xff0c;小李哥作为亚马逊大中华区开发者社区和自媒体代表&#xff0c;跟着亚马逊云安全产品团队采访了亚马逊云首席信息安全官(CISO)CJ Moses、亚马逊副总裁Eric Brandwine和亚马逊云首席高级安全工程师Becky Weiss。 …

【学习AI-相关路程-工具使用-自我学习-Ubuntucudavisco-开发工具尝试-基础样例 (2)】

【学习AI-相关路程-工具使用-自我学习-cuda&visco-开发工具尝试-基础样例 &#xff08;2&#xff09;】 1、前言2、环境说明3、总结说明4、工具安装0、验证cuda1、软件下载2、插件安装 5、软件设置与编程练习1、创建目录2、编译软件进入目录&创建两个文件3、编写配置文…

可微分矢量图形光栅化用于编辑和学习

图1. 我们引入了一种通过反向传播将光栅和矢量域联系起来的矢量图形可微分光栅化器。可微分光栅化实现了许多新颖的矢量图形应用。&#xff08;a&#xff09;在几何约束下&#xff0c;通过局部优化图像空间度量&#xff08;如不透明度&#xff09;来实现交互式编辑。&#xff0…

如何使用vue脚手架创建项目

前言 使用vue搭建项目的时候&#xff0c;我们可以通过对应的cmd命令去打开脚手架&#xff0c;然后自己配置对应的功能插件 说明&#xff1a; 要使用Vue脚手架创建项目&#xff0c;你需要先确保你已经安装了Node.js和npm&#xff08;Node.js的包管理器&#xff09;。然后&#…

uniapp 版本检查更新

总体来说uniapp的跨平台还是很不错的&#xff0c;虽然里面各种坑要去踩&#xff0c;但是踩坑也是开发人员的必修课和成长路。 这不&#xff0c;今天就来研究了一下版本检查更新就踩到坑了。。。先来看看检查更新及下载、安装的实现。 先来看看页面&#xff1a; 从左到右依次为…

CSRF、XSS攻防原理及解决方案

一、CSRF CSRF 全称叫做&#xff0c;跨站请求伪造(Cross—Site Request Forgery)&#xff0c;顾名思义&#xff0c;攻击者盗用了你的身份&#xff0c;以你的名义发送恶意请求&#xff0c;对服务器来说这个请求是完全合法的&#xff0c;但是却完成了攻击者所期望的一个操作&…

bbr 是真不行

bbr 作为 mimd 实例如何收敛到公平请看 瓶颈带宽的公平收敛&#xff0c;但这只是公平收敛&#xff0c;并不是 buffer 收敛。 上午跟朋友讨论了一个有趣的问题&#xff0c;感觉有必要揭露一下 bbr 的 buffer 不收敛。若不是有 probertt&#xff0c;多流共享瓶颈链路场景下&…

TC377TX 超声波雷达数据更新缓慢问题排查

1、问题表象 通过标定数据查看超声波雷达实时的距离大小,发现距离并没有实时更新,而是在实际值与默认值之间跳变,更新十分缓慢。   泊车功能必须依赖超声波雷达测距来实现,当雷达数据更新缓慢时,会导致泊车失败。 2、超声波雷达测距实现原理 MCU给超声波雷达发送一个40…

【SpringBoot整合系列】SpringBoot整合RabbitMQ-消息可靠性

目录 确保消息的可靠性RabbitMQ 消息发送可靠性分析解决方案开启事务机制发送方确认机制单条消息处理消息批量处理 失败重试自带重试机制业务重试 RabbitMQ 消息消费可靠性如何保证消息在队列RabbitMQ 的消息消费&#xff0c;整体上来说有两种不同的思路&#xff1a;确保消费成…

Python专题:十、字典(1)

数据类型:字典,是一个集合性质的数据类型 字典的初始化 字典{关键字:数值} 新增元素 修改元素 字典元素访问 字典[关键字} in 操作符 字典关键字检测 字典元素遍历 ①遍历关键字

ESP32引脚入门指南(六):从理论到实践(UART)

ESP32开发板具有UART0、UART1和UART2三个UART接口&#xff0c;支持异步通信(RS232和RS485)和IrDA速率高达5mbps。这些接口提供了丰富的串行通信选项&#xff0c;允许与各种设备进行全双工通信。 UART接口概述与引脚配置 UART 是一种全双工通信协议&#xff0c;允许数据同时在…

JAVA获取application.yml配置文件的属性值

application.yml配置参数 方式一&#xff1a;使用Value方式(常用) 语法 Value("${配置文件中的key:默认值}") Value("${配置文件中的key}")方法1&#xff1a;使用的类文件中定义变量&#xff0c;直接使用变量 import org.springframework.beans.factory.an…

初阶数据结构—顺序表和链表

第一章&#xff1a;线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#xff0c;也就…

STM32MP157_程序烧录

STM32MP157_程序烧录 说明&#xff1a; 1、使用emmc作为存储媒介&#xff0c;emmc是核心板上的存储颗粒空间有8GB 2、SD卡作为存储媒介&#xff0c;底板上有SD卡的插槽 emmc方式 软件&#xff1a;烧录软件使用STM32CubeProgrammer 连接线&#xff1a;硬件连接线使用type_c数据线…

哪里有高清视频素材软件?哪里有视频素材网站?

在这个视觉内容至关重要的时代&#xff0c;高质量的视频素材不仅能够增强信息传递的效果&#xff0c;还能显著提升观众的观看体验。接下来介绍的这些视频素材网站&#xff0c;将为您的创作提供广泛的选择&#xff0c;从本土到国际&#xff0c;满足您不同的需求和偏好。 1. 蛙学…