PgSQL - 17新特性 - 块级别增量备份

PgSQL - 17新特性 - 块级别增量备份

PgSQL可通过pg_basebackup进行全量备份。在构建复制关系时,创建备机时需要通过pg_basebackup全量拉取一个备份,形成一个mirror。但很多场景下,我们往往不需要进行全量备份/恢复,数据量特别大的时候,这个代价太大了。GPDB中有个工具gprecoverseg支持全量备份和增量备份。所谓全量备份,主要通过pg_basebackup从其他节点全量拷贝一份数据过来;而增量备份主要通过pg_rewind工具,只拷贝新增的数据。而PgSQL中单独的pg_rewind,仅从分叉点之前最近的checkpoint位置开始解析WAL,解析出变动的数据页,然后仅将变动的数据页拷贝过来。所以,仅靠pg_rewind实现不了完美的增量备份。

正在开发中的PgSQL17在pg_basebackup中新增了增量备份的功能。

1、使用方法

1.1 创建用例表及插入数据

=# CREATE TABLE just_for_fun (last_updated timestamptz);
=# INSERT INTO just_for_fun (last_updated) VALUES (now());
=# UPDATE just_for_fun SET last_updated = now();

1.2 执行pg_basebackup

=$ mkdir /var/tmp/backups; pg_basebackup -D /var/tmp/backups
=$ ls -l /var/tmp/backups/
total 360
-rw------- 1 pgdba pgdba 227 Jan  8 17:16 backup_label
-rw------- 1 pgdba pgdba 226076 Jan 8 17:16 backup_manifest
drwx------ 7 pgdba pgdba 4096 Jan  8 17:16 base/
…
-rw------- 1 pgdba pgdba 88 Jan  8 17:16 postgresql.auto.conf
-rw------- 1 pgdba pgdba 29806 Jan  8 17:16 postgresql.conf

相对于老版本的pg_basebackup多了backup_mainfest文件。该备份将PGDATA下的内容拷贝到/var/tmp/backups下。如果修改下冲突配置项,比如端口配置port,则可以通过pg_ctl -D /var/tmp/backups start直接启动。

当然,也可以备份成.tar文件:

=$ rm -rf /var/tmp/backups/; mkdir /var/tmp/backups; pg_basebackup -Ft -D /var/tmp/backups
=$ ls -l /var/tmp/backups/
total 56176
-rw------- 1 pgdba pgdba 226218 Jan  8 17:19 backup_manifest
-rw------- 1 pgdba pgdba 40509440 Jan 8 17:19 base.tar
-rw------- 1 pgdba pgdba 16778752 Jan 8 17:19 pg_wal.tar

1.3 backup_mainfest文件

=$ cat /var/tmp/backups/backup_manifest  | head -n 10
{ "PostgreSQL-Backup-Manifest-Version": 1,
"Files": [
{ "Path": "backup_label", "Size": 227, "Last-Modified": "2024-01-08 16:21:14 GMT", "Checksum-Algorithm": "CRC32C", "Checksum": "f6db08ca" },
{ "Path": "tablespace_map", "Size": 0, "Last-Modified": "2024-01-08 16:21:14 GMT", "Checksum-Algorithm": "CRC32C", "Checksum": "00000000" },
{ "Path": "pg_xact/0000", "Size": 8192, "Last-Modified": "2024-01-08 16:21:13 GMT", "Checksum-Algorithm": "CRC32C", "Checksum": "c79e44f3" },
{ "Path": "PG_VERSION", "Size": 3, "Last-Modified": "2024-01-08 13:08:53 GMT", "Checksum-Algorithm": "CRC32C", "Checksum": "64440205" },
{ "Path": "pg_multixact/offsets/0000", "Size": 8192, "Last-Modified": "2024-01-08 13:09:02 GMT", "Checksum-Algorithm": "CRC32C", "Checksum": "23464490" },
{ "Path": "pg_multixact/members/0000", "Size": 8192, "Last-Modified": "2024-01-08 13:08:53 GMT", "Checksum-Algorithm": "CRC32C", "Checksum": "23464490" },
{ "Path": "conf.d/depesz.conf", "Size": 512, "Last-Modified": "2024-01-08 13:08:54 GMT", "Checksum-Algorithm": "CRC32C", "Checksum": "c6f171e0" },
{ "Path": "pg_ident.conf", "Size": 2640, "Last-Modified": "2024-01-08 13:08:53 GMT", "Checksum-Algorithm": "CRC32C", "Checksum": "0ce04d87" },
…
{ "Path": "base/5/2652", "Size": 16384, "Last-Modified": "2024-01-08 13:08:53 GMT", "Checksum-Algorithm": "CRC32C", "Checksum": "259eec8e" },
{ "Path": "pg_logical/replorigin_checkpoint", "Size": 8, "Last-Modified": "2024-01-08 16:21:13 GMT", "Checksum-Algorithm": "CRC32C", "Checksum": "c74b6748" },
{ "Path": "current_logfiles", "Size": 44, "Last-Modified": "2024-01-08 13:08:54 GMT", "Checksum-Algorithm": "CRC32C", "Checksum": "97357c1c" },
{ "Path": "log/postgresql-2024-01-08_140854.log", "Size": 1021834, "Last-Modified": "2024-01-08 16:21:14 GMT", "Checksum-Algorithm": "CRC32C", "Checksum": "d2498fb2" },
{ "Path": "global/pg_control", "Size": 8192, "Last-Modified": "2024-01-08 16:21:14 GMT", "Checksum-Algorithm": "CRC32C", "Checksum": "43872087" }
],
"WAL-Ranges": [
{ "Timeline": 1, "Start-LSN": "4/86000028", "End-LSN": "4/86000750" }
],
"Manifest-Checksum": "106517baea81404769cd4deb686ff58b58997308f0d90d9afbfa9d0111a5003d"}

这个文件可以用于校验备份是否完成,也可以用于看下自从上次备份以来改变了哪些东西。

1.4 做一个全量备份

=$ rm -rf /var/tmp/backups/; mkdir /var/tmp/backups/
=$ pg_basebackup -Ft -D "/var/tmp/backups/$( date +%Y-%m-%d_%H%M%S-FULL )"
=$ ls -l /var/tmp/backups/
total 4
drwx------ 2 pgdba pgdba 4096 Jan 8 17:39 2024-01-08_173902-FULL/
=$ ls -l /var/tmp/backups/2024-01-08_173902-FULL/
total 56356
-rw------- 1 pgdba pgdba 226219 Jan  8 17:39 backup_manifest
-rw------- 1 pgdba pgdba 40691712 Jan 8 17:39 base.tar
-rw------- 1 pgdba pgdba 16778752 Jan 8 17:39 pg_wal.tar

做增量备份,指定-i:

=$ pg_basebackup -i /var/tmp/backups/2024-01-08_173902-FULL/backup_manifest -Ft -D "/var/tmp/backups/$( date +%Y-%m-%d_%H%M%S-INCREMENTAL )"
pg_basebackup: error: could NOT initiate base backup: ERROR: incremental backups cannot be taken unless WAL summarization IS enabled
pg_basebackup: removing DATA directory "/var/tmp/backups/2024-01-08_173956-INCREMENTAL"

需要开启wal summarization:

$ ALTER system SET summarize_wal = ON;
$ SELECT pg_reload_conf();

1.5 wal_summarization

默认为off,开启后会启动一个wal summarizer进程,自动生成wal summarize信息;当然还需要wal_level>minimal才能开启。记录到一段WAL的内容中:文件大小的变化、哪些block发生变化、需要被更新或删除、lsn范围。每个summary文件包含的信息:

1)某一个TLI上的一个LSN范围

2)每个relation,包括:

a "limit block" which is 0(文件被创建或销毁) if a relation is created or destroyed withina certain range of WAL records

or otherwise the shortest length(文件缩小至某个值) to which the relation was truncated during that range of WAL records

or otherwise InvalidBlockNumber(无效块号).

In addition, it stores a list of blocks which have been modified during that range of WAL records, (被修改过的blocks id). but excluding blocks which were removed by truncation after they were modified and never subsequently modified again. (不记录被truncate并且后面没有被修改过的blocks id)

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=174c480508ac25568561443e6d4a82d5c1103487

Wal summarizer就是哪个LSN范围内的变动?2.1节进行讲述。

1.6 增量备份

=$ pg_basebackup -i /var/tmp/backups/2024-01-08_173902-FULL/backup_manifest -Ft -D "/var/tmp/backups/$( date +%Y-%m-%d_%H%M%S-INCREMENTAL )"
=$ ls -l /var/tmp/backups/
total 8
drwx------ 2 pgdba pgdba 4096 Jan 8 17:39 2024-01-08_173902-FULL/
drwx------ 2 pgdba pgdba 4096 Jan 8 17:40 2024-01-08_174043-INCREMENTAL/
=$ ls -l /var/tmp/backups/2024-01-08_174043-INCREMENTAL/
total 23860
-rw------- 1 pgdba pgdba 236528 Jan  8 17:40 backup_manifest
-rw------- 1 pgdba pgdba 7413248 Jan  8 17:40 base.tar
-rw------- 1 pgdba pgdba 16778752 Jan 8 17:40 pg_wal.tar

增量备份的base.tar只有7MB,而全量备份有40MB。

增量备份和全量备份中的backup_manifest中文件个数一样,增量备份有2中类型文件:

=$ jq .Files[13] /var/tmp/backups/2024-01-08_174043-INCREMENTAL/backup_manifest
{
"Path": "global/1214_fsm",
"Size": 24576,
"Last-Modified": "2024-01-08 16:10:41 GMT",
"Checksum-Algorithm": "CRC32C",
"Checksum": "722d586a"
}
以及
=$ jq .Files[12] /var/tmp/backups/2024-01-08_174043-INCREMENTAL/backup_manifest
{
"Path": "global/INCREMENTAL.2695",
"Size": 12,
"Last-Modified": "2024-01-08 13:08:53 GMT",
"Checksum-Algorithm": "CRC32C",
"Checksum": "e34c7d7c"
}

不以INCREMENTAL开头的文件是普通文件,不是增量的。否则需要拉取一些更早的备份。

1.7 增量备份的合并

=$ mkdir /var/tmp/backups/FULL
=$ tar -x -C /var/tmp/backups/FULL -f /var/tmp/backups/2024-01-08_173902-FULL/base.tar
=$ tar -x -C /var/tmp/backups/FULL/pg_wal/ -f /var/tmp/backups/2024-01-08_173902-FULL/pg_wal.tar
=$ cp /var/tmp/backups/2024-01-08_173902-FULL/backup_manifest /var/tmp/backups/FULL/
=$ mkdir /var/tmp/backups/INCR
=$ tar -x -C /var/tmp/backups/INCR -f /var/tmp/backups/2024-01-08_174043-INCREMENTAL/base.tar
=$ tar -x -C /var/tmp/backups/INCR/pg_wal -f /var/tmp/backups/2024-01-08_174043-INCREMENTAL/pg_wal.tar
=$ cp /var/tmp/backups/2024-01-08_174043-INCREMENTAL/backup_manifest /var/tmp/backups/INCR/

pg_combinebackup将一个全量备份+一个或多个增量备份合并为一个全新的全量备份:

=$ pg_combinebackup -o /var/tmp/backups/combined /var/tmp/backups/FULL /var/tmp/backups/INCR

2、内核原理

2.1 manifest中的WAL-ranges

1)WAL-ranges中的Timeline为备份前checkpoint时的时间线

2)WAL-ranges中的Start-LSN为备份前checkpoint的位置

3)WAL-ranges中的End-LSN备份后XLOG_BACKUP_END后的位置

详情可查询下面函数调用逻辑:

perform_base_backupdo_pg_backup_start(...);|--  RequestCheckpoint(CHECKPOINT_FORCE | CHECKPOINT_WAIT | (fast ? CHECKPOINT_IMMEDIATE : 0));|  state->startpoint = ControlFile->checkPointCopy.redo;|--  state->starttli = ControlFile->checkPointCopy.ThisTimeLineID;state.startptr = backup_state->startpoint;state.starttli = backup_state->starttli;...备份do_pg_backup_stop(backup_state, !opt->nowait);|--  state->stoppoint = XLogInsert(RM_XLOG_ID, XLOG_BACKUP_END);|  state->stoptli = XLogCtl->InsertTimeLineID;|  RequestXLogSwitch(false);|--  ...endptr = backup_state->stoppoint;endtli = backup_state->stoptli;//ckp时的redo点 -- 备份结束后XLOG_BACKUP_END位置AddWALInfoToBackupManifest(&manifest, state.startptr, state.starttli, endptr, endtli);|--  manifest 中End-LSN为endptr位置即backup end位置,Start-LSN为state.startptr位置即开始备份前ckp位置

2.2 wal Summarize中每条记录的是哪个WAL范围的数据变化?

其实,记录的是每个checkpoint周期的WAL中记录的变动的block等信息:

SummarizeWAL...while (1){//Now read the next record.record = XLogReadRecord(xlogreader, &errormsg);switch (XLogRecGetRmid(xlogreader)){case RM_SMGR_ID:SummarizeSmgrRecord(xlogreader, brtab);break;case RM_XACT_ID:SummarizeXactRecord(xlogreader, brtab);break;case RM_XLOG_ID:stop_requested = SummarizeXlogRecord(xlogreader);|--  info = XLogRecGetInfo(xlogreader) & ~XLR_INFO_MASK;|  if (info == XLOG_CHECKPOINT_REDO || info == XLOG_CHECKPOINT_SHUTDOWN){|    return true;|  }|--  return false;break;default:break;}if (stop_requested && xlogreader->ReadRecPtr > summary_start_lsn){//遇到Checkpoint即停止解析summary_end_lsn = xlogreader->ReadRecPtr;//checkpointbreak;}解析得到更改的blockif (summary_end_lsn > summary_start_lsn){//summary文件名://tli(最老的未summarized的时间线)startlsn(最老的未summarized的wal)endlsn(ckp位置)snprintf(temp_path, MAXPGPATH,XLOGDIR "/summaries/temp.summary");snprintf(final_path, MAXPGPATH,XLOGDIR "/summaries/%08X%08X%08X%08X%08X.summary",tli,LSN_FORMAT_ARGS(summary_start_lsn),LSN_FORMAT_ARGS(summary_end_lsn));...将summary内容写入该文件}}

2.3 增量备份

197230acb6738e0205dfec6077bd9953.png

1)pg_basebackup作为客户端通过GetConnection连接服务端,服务端会fork出wal sender进程与之交互

2)pg_basebackup通过RetrieveWalSegSize向wal sender进程发送“SHOW wal_segment_size”,wal sender通过exec_replication_command处理发过来的命令。GetPGVariable获取到wal_segment_size大小,并发送回去:直到ReadyForQuery的pq_flush才将内容发送过去

3)接着pg_basebackup就进入了BaseBackup函数中

4)RunIdentifySystem向wal sender发送IDENTIFY_SYSTEM,wal sender通过IdentifySystem函数获取到系统标记systemid、时间线timeline等发送回去

5)然后进入增量备份相关步骤:PQsendQuery向wal sender发送UPLOAD_MANIFEST命令,wal sender通过UploadManifest进行处理,先发送PGRES_COPY_IN,pg_basebackup接收到后,读取指定的backup_manifest并将它发送给wal sender;wal sender通过HandleUploadManifestPacket放到IncrementalBackupInfo::buf中,直到pg_basebackup发来EOF ‘c’表示发送完。

6)wal sender解析出WAL Ranges内容,也就是得到备份前checkpoint位置

7)pg_basebackup发送BASE_BACKUP命令发起增量备份

8)wal sender通过SendBaseBackup从backup_mainifest解析的checkpoint位置开始(因为checkpoint前的内容都是已备份过的)找到需要的wal summary文件,根据其文件名(tli+ start lsn+ckp )找到需要增量的summary文件(记录的是本次增量备份需要的变动block列表等信息),根据summary文件中的内容,将本次增量备份内容发送回去

3、总结

1)wal Summarize进程通过解析每个checkpoint周期内的WAL日志,将变更信息记录到summary文件中

2)每次备份(全量备份或增量备份)都会生成一个manifest文件,文件中WAL-ranges部分会记录下备份前执行的checkpoint的WAL位置

3)通过manifest中记录的checkpoint位置就可以判断哪个summary文件是上次备份结束,本次增量备份开始的地方

4)遍历summary文件,得到增量变更,然后将变更页发送到pg_basebackup,由pg_basebackup写到指定位置,完成增量备份。

5)增量备份的完成,需要借助wal summary进程,该进程会读取WAL日志并解析,记录到变更,这个IO等代价需要考虑到业务中

参考

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=dc212340058b4e7ecfc5a7a81ec50e7a207bf288

https://www.depesz.com/2024/01/08/waiting-for-postgresql-17-add-support-for-incremental-backup/

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++面试宝典第23题:乌托邦树

题目 乌托邦树每年经历2个生长周期。每年春天,它的高度都会翻倍。每年夏天,他的高度都会增加1米。对于一颗在春天开始时种下的高为1米的树,问经过指定周期后,树的高度为多少? 输入描述:输入一个数字N(0 <= N <= 1000),表示指定周期。 比如:样例输入为3。 输出描…

helm---自动化一键部署

什么是helm?? 在没有这个helm之前&#xff0c;deployment service ingress helm的作用就是通过打包的方式&#xff0c;把deployment service ingress 这些打包在一块&#xff0c;一键式部署服务&#xff0c;类似于yum 官方提供的一个类似于安装仓库的功能&#xff0c;可以实…

基于springboot+vue新能源汽车充电管理系统

摘要 新能源汽车充电管理系统是基于Spring Boot和Vue.js技术栈构建的一款先进而高效的系统&#xff0c;旨在满足不断增长的新能源汽车市场对充电服务的需求。该系统通过整合前后端技术&#xff0c;实现了用户注册、充电桩管理、充电订单管理等核心功能&#xff0c;为用户提供便…

使用DTS实现TiDB到GaiaDB数据迁移

1 概览 本文主要介绍通过 DTS 数据迁移功能&#xff0c;结合消息服务 for Kafka 与 TiDB 数据库的 Pump、Drainer 组件&#xff0c;完成从TiDB迁移至百度智能云云原生数据库 GaiaDB。 消息服务 for Kafka&#xff1a;详细介绍参见&#xff1a;消息服务 for Kafka 产品介绍百度智…

go 语言中 json.Unmarshal([]byte(jsonbuff), j) 字节切片得使用场景

struct_tag的使用 在上面的例子看到&#xff0c;我们根据结构体生成的json的key都是大写的&#xff0c;因为结构体名字在go语言中不大写的话&#xff0c;又没有访问权限&#xff0c;这种问题会影响到我们对json的key的名字&#xff0c;所以go官方给出了struct_tag的方法去修改…

R语言rvest爬虫如何设置ip代理?

前言 在R语言中使用rvest进行网络爬虫时&#xff0c;可以使用代理服务器来隐藏真实IP地址。有一些R包可以帮助爬虫中设置代理&#xff0c;其中一个常用的包是httr。以下是一个简单的例子&#xff0c;演示如何在rvest中设置IP代理 教程 一、获取代理IP并提取 二、详情设置 l…

2024三掌柜赠书活动第四期: Next.js实战,构建现代化的可扩展Web应用

目录 摘要前言Next.js简介关于《 Next.js实战》实战示例最佳实践和进阶应用编辑推荐内容简介作者简介图书目录书中前言/序言《Next.js实战》全书速览结束语 摘要&#xff1a;本文将介绍Next.js&#xff0c;一个流行的React框架&#xff0c;以及如何在实际项目中使用Next.js构…

OSPF协议LSDB同步过程和邻居状态机

知识改变命运&#xff0c;技术就是要分享&#xff0c;有问题随时联系&#xff0c;免费答疑&#xff0c;欢迎联系&#xff01; 厦门微思网络​​​​​​ https://www.xmws.cn 华为认证\华为HCIA-Datacom\华为HCIP-Datacom\华为HCIE-Datacom Linux\RHCE\RHCE 9.0\RHCA\ Oracle O…

技术型企业如何选择安全、性价比高的FTP替代方案?

FTP作为世界上第一款文件传输协议&#xff0c;在全球范围内应用广泛&#xff0c;它解决了文件传输协议空白的问题&#xff0c;为文件传输场景提供了专业的解决方案。 但随着网络技术的演进&#xff0c;技术型企业进行文件传输的需求也更多元和复杂&#xff0c;FTP的缺陷也更多的…

CmakeList教程

一、CmakeList介绍&#xff1a; cmake 是一个跨平台、开源的构建系统。它是一个集软件构建、测试、打包于一身的软件。它使用与平台和编译器独立的配置文件来对软件编译过程进行控制。它会通过写的语句自动生成一个MakeFile,从而实现高效编译 二、CmakeList的常用指令 1.指定…

【 CSS 】定位

不要因为小小的失败而放弃大大的梦想&#xff0c;每一次坚持都是通向成功的一步。- 马克吐温 1. 定位 1.1 为何使用定位 我们先来看一个效果&#xff0c;同时思考一下用标准流或浮动能否实现类似的效果&#xff1f; 场景1: 某个元素可以自由的在一个盒子内移动位置&#xff0c…

小程序学习-21

目前小程序分包大小有以下限制&#xff1a; 整个小程序所有分包大小不超过 20M单个分包/主包大小不能超过 2M 独立分包&#xff1a;"independent": true

docker compose安装milvus

下载对应版本的milvus-standalone-docker-compose.yml wget https://github.com/milvus-io/milvus/releases/download/v2.3.5/milvus-standalone-docker-compose.yml重新命令为docker-compose.yml mv milvus-standalone-docker-compose.yml docker-compose.yml启动milvus doc…

记一次 stackoverflowerror 线上排查过程

一.线上 stackOverFlowError xxx日,突然收到线上日志关键字频繁告警 classCastException.从字面上的报警来看,仅仅是类型转换异常,查看细则发现其实是 stackOverFlowError.很多同学面试的时候总会被问到有没有遇到过线上stackOverFlowError?有么有遇到栈溢出?具体栈溢出怎么来…

postman测试导入文件

01 上传文件参数 1.选择请求方式 选择post请求方式&#xff0c;输入请求地址 2.填写Headers Key&#xff1a;Content-Type &#xff1b; Value&#xff1a;multipart/form-data 如下图 3.填写body 选择form-data&#xff0c;key选择file类型后value会出现按钮&#xff0…

(十二)Head first design patterns代理模式(c++)

代理模式 代理模式&#xff1a;创建一个proxy对象&#xff0c;并为这个对象提供替身或者占位符以对这个对象进行控制。 典型例子&#xff1a;智能指针... 例子&#xff1a;比如说有一个talk接口&#xff0c;所有的people需要实现talk接口。但有些人有唱歌技能。不能在talk接…

表单的总数据为什么可以写成一个空对象,不用具体的写表单中绑定的值,vue3

<el-form :model"form" label-width"120px"><el-form-item label"Activity name"><el-input v-model"form.name" /></el-form-item> </el-form> const form ref({})from为空对象 在v-model里写form…

verde生成网格坐标

文章目录 网格坐标区域调整 Verde是Python用于地理空间数据处理的一个库&#xff0c;由于采用了一些机器学习的方法&#xff0c;所以除了科学计算三件套之外&#xff0c;还需要基于sklearn模块。考虑到依赖关系&#xff0c;这里比较推荐用conda安装。 conda install verde --c…

分布式websocket即时通信(IM)系统保证消息可靠性【第八期】

b站上面本期视频版本&#xff0c;观看视频食用更佳&#xff01;点击即可跳转,找不到视频可以直接搜索我 目前叫 呆呆呆呆梦 目前已经写的文章有。并且有对应视频版本。 git项目地址 【IM即时通信系统&#xff08;企聊聊&#xff09;】点击可跳转 sprinboot单体项目升级成sprin…

Windows 10中的驱动程序与device guard的兼容性

文章目录 Windows 10中的驱动程序与device guard的兼容性windows的device guard是什么如何构建兼容的驱动程序如何验证驱动程序的兼容性驱动程序验证程序兼容性检查启用基于虚拟化的隔离代码完整性HLK测试&#xff08;桌面和服务器&#xff09;Device Guard准备工具DGReadiness…