数据库内核月报 - 2015 / 09-PgSQL · 特性分析 · 谈谈checkpoint的调度

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介:

在PG的众多参数中,参数checkpoint相关的几个参数颇为神秘。这些参数与checkpoint的调度有关,对系统的稳定性还是比较重要的,下面我们为大家解析一下,这要先从PG的数据同步机制谈起。

PG的数据同步机制

众所周知,数据库的后台进程在执行用户事务时,发生的数据更改是先写入缓冲池中,对应PG就是shared buffers。PG的缓冲池一般设置为总内存的1/4左右,缓冲池里面的这些数据更改,在事务提交时,是无需同步写入到磁盘的。因为在事务提交时,会先写入WAL日志,有了WAL日志,就可以在异常情况下将数据恢复,保障数据安全,因此数据本身是否在提交时写入磁盘就没那么重要了。PG是只是在需要的时候,例如脏页较多时、或一定时间间隔后,才将数据写回磁盘。

脏页处理的过程分为几个步骤。首先是由background writer将shared buffers里面的被更改过的页面(即脏页),通过调用write写入操作系统page cache。在函数BgBufferSync可以看到,PG的background writer进程,会根据LRU链表,扫描shared buffers(实际上是每次扫描一部分),如果发现脏页,就调用系统调用write。可以通过设置bgwriter_delay参数,来控制background writer每次扫描之间的时间间隔。background writer在对一个页面调用write后,会将该页面对应的文件(实际上是表的segement,每个表可能有多个segment,对应多个物理文件)记录到共享内存的数组CheckpointerShmem->requests中,调用顺序如下:

BackgroundWriterMain -> BgBufferSync -> SyncOneBuffer -> FlushBuffer -> smgrwrite
                                                                           |
                                                                           |
                                                                           V
                       ForwardFsyncRequest <- register_dirty_segment <- mdwrite

这些request最终会被checkpointer进程读取,放入pendingOpsTable,而真正将脏页回写到磁盘的操作,是由checkpointer进程完成的。checkpointer每次也会调用smgrwrite,把所有的shared buffers脏页(即还没有被background writer清理过得脏页)写入操作系统的page cache,并存入pendingOpsTable。这样pendingOpsTable存放了所有write过的脏页,包括之前background writer已经处理的脏页。随后PG的checkpointer进程会根据pedingOpsTable的记录,进行脏页回写操作(注意每次调用fysnc,都会sync数据表的一个文件,文件中所有脏页都会写入磁盘),调用顺序如下:

CheckPointGuts->CheckPointBuffers->->mdsync->pg_fsync->fsync

如果checkpointer做磁盘写入的频率过高,则每次可能只写入很少的数据。我们知道,磁盘对于顺序写入批量数据比随机写的效率要高的多,每次写入很少数据,就造成大量随机写;而如果我们放慢checkpoint的频率,多个随机页面就有可能组成一次顺序批量写入,效率大大提高。另外,checkpoint会进行fsync操作,大量的fsync可能造成系统IO阻塞,降低系统稳定性,因此checkpoint不能过于频繁。但checkpoint的间隔也不能无限制放大。因为如果出现系统宕机,在进行恢复时,需要从上一次checkpoint的时间点开始恢复,如果checkpoint间隔过长,会造成恢复时间缓慢,降低可用性。整个同步机制如下图所示:

数据同步机制

图1. 数据同步机制

checkpoint的调度

那么如何调度checkpoint,即控制checkpoint的间隔呢?PG提供了几个参数:checkpoint_segmentscheckpoint_completion_targetcheckpoint_timeout

决定是否做checkpoint有两个指标维度:

  1. 系统的数据修改量。
    评估修改量,有两种方法:一种是记录shared buffer里面的脏页有多少,占所有buffer的多大比例;另外一种,记录用户事务的数据修改量是多少。如果用系统的脏页数量或所占比例,来评估修改量,会不太准确,用户有可能反复修改相同的页面,脏页不多,但实际修改量很大,这时候也是应该尽快进行checkpoint,减少恢复时间的。而通过记录WAL日志的产生量,可以很好的评估这个修改量,所以就有了checkpoint_segments这个参数,它用于指定产生多少WAL日志后,进行一次checkpoint。例如设置为16时,产生16个WAL日志文件后(如果每个日志文件的大小为16M,即产生16*16M字节的日志),进行一次checkpoint。判断是否触发checkpoint的调用如下:

     XLogInsert->XLogFlush->XLogWirte->XLogCheckpointNeeded
    
  2. 距离上一次checkpoint的时间。
    也就是在上一次checkpoint后,多长时间必须做一次checkpoint。PG提供了checkpoint_timeout这个参数,缺省值为300秒,即如果上一次checkpoint后过了300秒没有做checkpoint了,就强制做一次checkpoint。

那么另外一个参数checkpoint_completion_target是做什么的呢?

checkpoint_completion_target 参数

这个看似不起眼的参数其实对checkpoint调度的影响很大。它是怎么使用的呢?checkpoint会调用BufferSync,将所有shared buffers的页面扫描一遍,如果发现脏页即调用write,写入page cache。每次write完一个脏页后,会调用IsCheckpointOnSchedule()这个函数。这个函数的主要逻辑是,判断新产生的日志文件数除以checkpoint_segments,结果是否小于checkpoint_completion_target。注意,这里的新产生日志文件数,是checkpoint开始后新产生的日志数,不是从上一次checkpoint结束后的新日志数。如果IsCheckpointOnSchedule()返回true,则checkpointer进程会进行sleep,sleep一定时间后,再读取下一个shared buffers页面进行write。这样做的效果是,当所有页面write完成时,新产生的日志页面数占checkpoint_segements的比例约为checkpoint_completion_target的设定值。例如,如果checkpoint_segements为16,checkpoint_completion_target为0.9,则当上一次checkpoint后,新的第16个日志文件产生后,写日志的那个进程会触发一次checkpoint。checkpoiter进程随即调用CreateCheckPoint,做一次checkpoint,checkpointer进程会调用BufferSync,扫描shared buffers写脏页。此时每次write一个脏页后,如果新产生的日志文件数小于16*0.9,即15个日志文件时,会进行sleep。最后当write脏页完成时,从上次checkpoint开始新产生的日志文件约为16+15=31个,即

checkpoint_segments + checkpoint_segments * checkpoint_completion_target

由此可见,checkpoint_completion_target直接控制了checkpoint中的write脏页的速度,使其完成时新产生日志文件数为上述期望值。

除了日志文件数,IsCheckpointOnSchedule()还会检查从checkpoint开始到现在的时间占checkpoint_timeout的比例,是否小于checkpoint_completion_target,以决定是否sleep。按checkpoint_completion_target为0.9,checkpoint_timeout为300秒计算,脏页write的完成时间距离checkpoint开始的时间,大约是270秒。实际上,这个时间上的约束和产生日志文件数的约束是同时起作用的。

当脏页全部被write完,就要进行真正的磁盘操作了,即fsync。此时每个文件的fsync之间没有sleep,是尽快完成的。一般做fsync总时间不会超过10秒,因此会赶在时间间隔到达checkpoint_timeout或新日志文件数到达checkpoint_segments前(都从checkpoint开始时间点开始算起)结束此次checkpoint。

总结起来,每次checkpoint所耗时间可以用下面的公式计算:

min(产生checkpoint_segments*checkpoint_completion_target个日志文件的时间,checkpoint_timeout*checkpoint_completion_target)+ 做fsync的时间

比如上面的例子,将会是:

min (产生15个日志文件的时间,270秒)+ fsync的时间

而这个时间一般小于产生checkpoint_segments个日志或checkpoint_timeout的时间。这样综合的效果是,每产生checkpoint_segments个日志或经历checkpoint_timeout的时间做一次checkpoint。在两次checkpoint的开始时间之间,会在checkpoint_completion_target比例的时间点完成脏页write,随后很快进行完fsync,如下图所示:

checkpoint过程

图2. checkpoint过程

以上便是checkpoint的调度机制。我们要注意调整上述几个参数时,不要让checkpoint产生过于频繁,否则频繁的fsync操作会是系统不稳定。比如,checkpoint_segments一般设置为16个以上,checkpoint_completion_target设为0.9,checkpoint_timeout为300秒,这样一般checkpoint的间隔能达到1分钟以上。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
23天前
|
关系型数据库 MySQL 分布式数据库
PolarDB 与传统数据库的性能对比分析
【8月更文第27天】随着云计算技术的发展,越来越多的企业开始将数据管理和存储迁移到云端。阿里云的 PolarDB 作为一款兼容 MySQL 和 PostgreSQL 的关系型数据库服务,提供了高性能、高可用和弹性伸缩的能力。本文将从不同角度对比 PolarDB 与本地部署的传统数据库(如 MySQL、PostgreSQL)在性能上的差异。
56 1
|
2月前
|
SQL Linux 数据库
|
28天前
|
存储 消息中间件 人工智能
AI大模型独角兽 MiniMax 基于阿里云数据库 SelectDB 版内核 Apache Doris 升级日志系统,PB 数据秒级查询响应
早期 MiniMax 基于 Grafana Loki 构建了日志系统,在资源消耗、写入性能及系统稳定性上都面临巨大的挑战。为此 MiniMax 开始寻找全新的日志系统方案,并基于阿里云数据库 SelectDB 版内核 Apache Doris 升级了日志系统,新系统已接入 MiniMax 内部所有业务线日志数据,数据规模为 PB 级, 整体可用性达到 99.9% 以上,10 亿级日志数据的检索速度可实现秒级响应。
AI大模型独角兽 MiniMax 基于阿里云数据库 SelectDB 版内核 Apache Doris 升级日志系统,PB 数据秒级查询响应
|
18天前
|
SQL Java OLAP
Hologres 入门:实时分析数据库的新选择
【9月更文第1天】在大数据和实时计算领域,数据仓库和分析型数据库的需求日益增长。随着业务对数据实时性要求的提高,传统的批处理架构已经难以满足现代应用的需求。阿里云推出的 Hologres 就是为了解决这个问题而生的一款实时分析数据库。本文将带你深入了解 Hologres 的基本概念、优势,并通过示例代码展示如何使用 Hologres 进行数据处理。
72 2
|
26天前
|
网络协议 NoSQL 网络安全
【Azure 应用服务】由Web App“无法连接数据库”而逐步分析到解析内网地址的办法(SQL和Redis开启private endpoint,只能通过内网访问,无法从公网访问的情况下)
【Azure 应用服务】由Web App“无法连接数据库”而逐步分析到解析内网地址的办法(SQL和Redis开启private endpoint,只能通过内网访问,无法从公网访问的情况下)
|
2月前
|
存储 人工智能 分布式数据库
现代数据库技术的发展与应用前景分析
随着信息时代的发展,数据库技术在各行各业中扮演着至关重要的角色。本文探讨了现代数据库技术的最新发展趋势,以及其在未来的应用前景,涵盖了分布式数据库、区块链技术与数据库融合、人工智能驱动的数据管理等领域。
|
3月前
|
SQL 存储 运维
网易游戏如何基于阿里云瑶池数据库 SelectDB 内核 Apache Doris 构建全新湖仓一体架构
随着网易游戏品类及产品的快速发展,游戏数据分析场景面临着越来越多的挑战,为了保证系统性能和 SLA,要求引入新的组件来解决特定业务场景问题。为此,网易游戏引入 Apache Doris 构建了全新的湖仓一体架构。经过不断地扩张,目前已发展至十余集群、为内部上百个项目提供了稳定可靠的数据服务、日均查询量数百万次,整体查询性能得到 10-20 倍提升。
网易游戏如何基于阿里云瑶池数据库 SelectDB 内核 Apache Doris 构建全新湖仓一体架构
|
2月前
|
DataWorks 关系型数据库 MySQL
DataWorks操作报错合集之从OceanBase(OB)数据库调度数据到MySQL数据库时遇到连接报错,该怎么办
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
2月前
|
存储 大数据 关系型数据库
从 ClickHouse 到阿里云数据库 SelectDB 内核 Apache Doris:快成物流的数智化货运应用实践
目前已经部署在 2 套生产集群,存储数据总量达百亿规模,覆盖实时数仓、BI 多维分析、用户画像、货运轨迹信息系统等业务场景。
|
3月前
|
关系型数据库 MySQL 测试技术
《阿里云产品四月刊》—瑶池数据库微课堂|RDS MySQL 经济版 vs 自建 MySQL 性能压测与性价比分析
阿里云瑶池数据库云原生化和一体化产品能力升级,多款产品更新迭代