openGauss数据库源码解析系列文章——备份恢复机制
本章主要介绍openGauss的备份恢复原理和技术。备份恢复是数据库日常维护的一个例行活动,通过把数据库数据备份到另外一个地方,可以抵御介质类的损坏,增加数据库数据的可靠性。数据库的备份恢复主要分为逻辑备份恢复和物理备份恢复。
逻辑备份是把数据库中的数据导出为文本文件,这些文本文件内容一般来说是SQL语句。恢复数据时再把文本文件中的SQL语句导入数据库中恢复。逻辑备份比较灵活,可以支持库级、模式级和表级备份,但逻辑备份只读取了某个时间点的数据库快照对应的数据,很难实现增量备份,恢复时也无法恢复到指定的时间点。在openGauss中实现逻辑备份恢复的工具为gs_dump/gs_restore,具体使用方法参考openGauss官网《管理员指南》手册。
物理备份是直接复制数据库的物理文件,性能比较高,对应用的约束比较少,但只能对整个库进行备份。物理备份又分为全量备份和增量备份。增量备份又有两种方式,一种是结合数据库的脏页跟踪实现的增量备份,另外一种是根据redo日志的增量实现的增量备份。根据脏页进行的增量备份可以和历史上的备份进行合并,减少存储空间的占用,恢复时可以恢复到增量备份的时间点,无法恢复到任意时间点。根据redo日志进行的增量备份在恢复时可以恢复到指定时间点,但所有的redo日志都需要进行备份,占用的存储空间较大。
逻辑备份主要用于异构数据库的迁移,物理备份主要用于保障数据库数据的可靠性。本章主要介绍openGauss的物理备份机制,包括全量备份技术和增量备份技术。
一、openGauss全量备份技术
openGauss有两个备份工具gs_basebackup和gs_probackup。gs_basebackup只能进行全量备份,gs_probackup既可进行全量备份,也可进行增量备份。gs_probackup全量备份的原理和gs_basebackup是类似的,本节以gs_basebackup工具为例介绍全量备份的原理。
1.1 gs_basebackup备份工具
gs_basebackup是一个独立的二进制程序,有自己的主函数,代码在src/bin/pg_basebackup目录下。在备份时,gs_basebackup通过指定的IP地址连接openGauss数据库服务器,openGauss数据库服务器把需要备份的数据文件和redo日志文件发送给备份工具gs_basebackup,gs_basebackup收到后把文件存放到本地指定的目录,从而完成数据库的备份。
gs_basebackup主要有两种备份格式:plain普通格式和tar压缩包格式。普通格式就是以通常的数据文件进行备份,tar压缩包格式就是把备份文件打包进行备份。openGauss的tar包头是2048字节,文件名最长支持1024个字节长度,不是标准的tar,所以需要openGauss自己解包,实现解包的命令为GsTar。
gs_basebackup的主干处理流程比较简单,首先对支持的命令行参数进行解析,主要的命令行参数请参照表10-1。参数解析后进入备份主函数BaseBackup,BaseBackup参照后面详细介绍。在主函数之后是free_basebackup,释放前面分配的内存资源,整个备份流程就结束了。
表1 命令参数
参数 | 描述 |
-D | 备份的目的路径 |
-F | 备份的文件格式,plain普通格式和tar压缩包格式 |
-X | 是否进行流复制模式,当前要求必须采用流复制模式,保证备份数据的正确性 |
-Z | 压缩级别 |
-c | 备份时是否做快速检查点 |
-h | 进行备份的数据库服务器监听IP地址 |
-p | 进行备份的数据库服务器监听端口号 |
-U | 进行备份时连接数据库服务器的用户名 |
-W | 进行备份时连接数据库服务器的密码 |
-s | 备份时状态更新时间间隔 |
-v | 是否显示备份详细信息 |
- P | 是否显示备份进度信息 |
1.2 gs_basebackup备份交互流程
1. plain普通格式备份
普通格式备份的主函数为BaseBackup,具体交互流程如图1所示。
图1 备份交互流程
从图1可以看出,数据库物理全量备份主要包括两个流程,一个是数据文件的备份,一个是XLOG文件的备份。详细过程如下。
(1) gs_basebackup在BaseBackup函数中创建数据传输的连接。
(2) 执行IDENTIFY_SYSTEM命令,获取时间线和系统标识符。
(3) 执行BASE_BACKUP LABEL备份命令,获取XLOG的存放路径和备份开始时日志的位置。然后从数据库服务器获取表空间的路径,创建对应的路径。
(4) 在拷贝数据文件之前,创建一个单独的子进程用于日志传输。日志传输处理的主函数为StartLogStreamer,在StartLogStreamer函数中,先调用GetConnection函数创建一个日志传输的连接,然后调用fork函数创建子进程,在子进程内部通过LogStreamerMain函数调用ReceiveXlogStream执行实际的日志传输。在ReceiveXlogStream中,也是先调用IDENTIFY_SYSTEM获取系统标识并且进行校验和前面获取的系统标识是否一致。接着执行START_REPLICATION,通知数据库服务器日志传输的起始位置。调用createHeartbeatTimer启动心跳线程,保证能够实时监控传输过程中的连接状态。接下来进行日志接收循环,接收数据库服务器传输的日志,写入本地日志路径,直到接收到通知的日志停止位置。
(5) 在主进程创建日志接收子进程之后,调用ReceiveAndUnpackTarFile进行数据文件的拷贝,在这个函数中,有一个while (1)循环,循环接收数据库服务器传输的数据文件,直到接收完数据库服务传输的全部数据文件。数据库文件传输完毕后,数据库服务器会返回一个备份结束时的日志位置。
(6) 主进程接收这个位置,把这个位置通过管道发送给日志接收子进程,日志接收子进程把这个位置与当前日志传输位置相比较,如果达到了这个位置,则日志接收结束,日志子进程退出。主进程等到日志传输子进程退出后,数据库备份的主流程就基本结束了。这个过程保证了redo日志覆盖到整个数据库文件的复制过程,即使在复制数据文件时可能由于数据库的并发刷盘导致数据页可能不一致,但这些不一致可以通过redo日志进行恢复,从而保证整个数据库备份数据的一致性。
(7) 后面两个函数,一个是FetchMotCheckpoint函数,这个函数备份MOT内存表的数据文件,流程和前面基本相似;还有一个是backup_dw_file函数,在backup_dw_file文件中,删除存在的双写文件,然后写入一个空的数据页,这个只是一个空文件,避免启动时的文件检查异常。最后释放前面获得的系统标识符,至此,客户端工具完成整个备份流程。
在数据库服务器端,备份主要在HandleWalReplicationCommand函数中进行,该函数主要接收客户端命令,并根据命令标识符进行处理。
(1) IDENTIFY_SYSTEM命令对应的标识符为T_IdentifySystemCmd,处理函数为IdentifySystem,在IdentifySystem中,构造systemid和timeline的数据元组,返回给客户端备份工具。
(2) BASE_BACKUP LABEL命令对应的标识符为T_BaseBackupCmd,对应的主要处理函数为SendBaseBackup,在SendBaseBackup函数中,首先调用parse_basebackup_options解析备份的命令参数,包括备份标签(label)、备份进度(progress)、快速检查点(fast)、是否等待(nowait)、是否包括redo日志(wal)等选项参数,最后调用send_xlog_location函数发送日志文件的路径,接着调用perform_base_backup函数执行数据文件的备份。在perform_base_backup函数中,首先调用do_pg_start_backup执行备份权限检查,根据备份命令行参数决定是否请求检查点(RequestCheckpoint函数),然后生成备份标签文件backup_label,backup_label是备份的重要文件,这个文件包括的内容如下。
① START WAL LOCATION:备份开始时日志的位置。
② CHECKPOINT LOCATION:检查点的位置。
③ BACKUP METHOD:备份方法,pg_start_backup方式还是streamed方式。pg_start_backup没有指定备份标签文件,整个数据库只能同时运行一个备份。streamed方式有备份标签文件,可以同时运行多个备份。
④ BACKUP FROM:备份源standby还是master。
⑤ START TIME:备份开始的物理时间。
⑥ LABEL:备份标签。
backup_label文件最重要的作用是记录数据库恢复的起始位置,在数据库恢复时使用,其次是对本次备份的一个标识及记录一些备份的参考信息。
最后调用SendXlogRecPtrResult函数把备份开始时的日志位置发送给客户端。
perform_base_backup函数在/* Collect information about all tablespaces */while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL) 循环读取每个表空间的数据文件,通过sendTablespace调用sendDir,把表空间目录下的数据文件发送给客户端备份工具。在把全部文件发送给客户备份工具后,调用do_pg_stop_backup进行停止备份的处理,在do_pg_stop_backup函数中,先解析原来备份的backup_label文件,获取备份起始的XLOG位置,写入XLOG_BACKUP_END到日志文件,然后调用RequestXLogSwitch进行XLOG文件段切换,方便归档快速完成。请求一次新的检查点RequestCheckpoint,写当前备份的历史文件“Backup”.文件,调用CleanupBackupHistory清除历史备份文件。如果需要等待归档则等待日志归档完成,do_pg_stop_backup停止备份结束后,调用SendXlogRecPtrResult把备份结束的XLOG位置发送给客户端备份工具,服务器端备份命令的处理流程就结束了。
START_REPLICATION对应的标识符为T_StartReplicationCmd,处理函数为StartReplication,在StartReplication函数中,首先给客户端工具发送CopyBothResponse响应消息,然后调用WalSndSetPercentCountStartLsn设置流复制开始位置,然后设置replication_started为true,启动正式的流复制过程。
2. tar压缩包格式备份
tar压缩包格式备份的处理函数为ReceiveTarFile,具体过程如下。
(1) 根据备份内容(全部还是具体表空间)和是否压缩,确定文件名称是base.tar[.gz]还是.tar[.gz]。
(2) 打开tar文件,接收数据库服务器发送的COPY数据流,写入tar文件,直到复制完整个内容。数据库服务器往GsBaseBackup发送的数据流就是一个压缩后的tar流。
如前所述,openGauss的tar包格式是自定义的,所以需要实现解包。解包的命令为GsTar,主要有两个命令行参数。
① -D, --destination=DIRECTORY,解压后的文件存放路径;
② -F, --filename=FILENAME,需要解压的tar包。
二、openGauss增量备份技术
全量备份每次备份都需要复制全部数据库的文件,备份时间和存储空间的开销都比较大。增量备份只备份自上次备份以来的数据改变,可以减少备份的开销。
openGauss增量备份工具为gs_probackup。gs_probackup支持全量备份、增量备份、对备份元数据进行管理、设置备份的留存策略、合并增量备份、删除过期备份,并且可备份外部目录的内容,如脚本文件、配置文件、日志文件、dump文件等。
增量备份需要数据库服务器端的配合,在conf文件中配置参数enable_cbm_tracking = on,启动数据库服务器对脏页数据修改的跟踪。
增量备份的主要逻辑在gs_probackup工具中实现,一些备份原理和前面介绍的全量物理备份相似,下面主要介绍gs_probackup工具的代码实现逻辑。源代码在src\bin\pg_probackup目录下,gs_probackup是一个独立的二进制工具,有自己的主函数,主函数在pg_probackup.cpp文件中。主函数是增量备份处理的一个框架,开始时调用pgBackupInit初始化当前备份的元数据信息,然后调用init_config初始化实例的备份配置信息,解析备份子命令和命令行参数,根据子命令调用子命令的处理函数进行处理。
2.1 gs_probackup子命令
gs_probackup支持的功能、子命令和处理函数如下。
(1) 打印gs_probackup版本,代码如下:
gs_probackup -V|--version
gs_probackup version
这个子命令没有处理函数,直接打印显示当前版本号。
(2) 显示gs_probackup命令的帮助信息。如果指定了gs_probackup的子命令,则显示可用于此子命令的参数的详细信息。代码如下:
gs_probackup -?|--help
gs_probackup help [command]
处理函数为help_command和help_pg_probackup。
(3) 初始化备份路径backup-path中的备份目录,该目录将存储备份的内容。如果备份路径backup-path已存在,则backup-path必须为空目录。代码如下:
gs_probackup init -B backup-path [--help]
处理函数为do_init。
(4) 在备份路径backup-path内初始化一个新的备份实例,并生成pg_probackup.conf配置文件,该文件保存了指定数据目录pgdata-path的gs_probackup设置。代码如下:
gs_probackup add-instance -B backup-path -D pgdata-path --instance=instance_name
[-E external-directories-paths]
[remote_options]
[--help]
处理函数为do_add_instance。
(5) 在备份路径backup-path内删除指定实例相关的备份内容,代码如下:
gs_probackup del-instance -B backup-path --instance=instance_name
[--help]
处理函数为do_delete_instance。
(6) 将指定的连接、压缩、日志等相关设置添加到pg_probackup.conf配置文件中,或修改已设置的值,不要手动编辑pg_probackup.conf配置文件。代码如下:
gs_probackup set-config -B backup-path --instance=instance_name
[-D pgdata-path] [-E external-directories-paths] [--restore-command=cmdline] [--archive-timeout=timeout]
[--retention-redundancy=retention-redundancy] [--retention-window=retention-window] [--wal-depth=wal-depth]
[--compress-algorithm=compress-algorithm] [--compress-level=compress-level]
[-d dbname] [-h hostname] [-p port] [-U username]
[logging_options] [remote_options]
[--help]
处理函数为do_set_config。
(7) 将备份相关设置添加到backup.control配置文件中,或修改已设置的值。代码如下:
gs_probackup set-backup -B backup-path --instance=instance_name -i backup-id
[--note=text] [pinning_options]
[--help]
处理函数为do_set_backup。
(8) 显示位于备份目录中的pg_probackup.conf配置文件的内容。可以通过指定--format=json选项,以json格式显示。默认情况下,显示为纯文本格式,代码如下:
gs_probackup show-config -B backup-path --instance=instance_name
[--format=plain|json]
[--help]
处理函数为do_show_config。
(9) 显示备份目录的内容。如果指定了instance_name和backup_id,则显示该备份的详细信息。可以通过指定--format=json选项,以json格式显示。默认情况下,备份目录的内容显示为纯文本格式,代码如下:
gs_probackup show -B backup-path
[--instance=instance_name [-i backup-id]] [--archive] [--format=plain|json]
[--help]
处理函数为do_show。
(10) 创建指定实例的备份,代码如下:
gs_probackup backup -B backup-path --instance=instance_name -b backup-mode
[-D pgdata-path] [-C] [-S slot-name] [--temp-slot] [--backup-pg-log] [-j threads_num] [--progress]
[--no-validate] [--skip-block-validation] [-E external-directories-paths] [--no-sync] [--note=text]
[--archive-timeout=timeout]
[logging_options] [retention_options] [compression_options]
[connection_options] [remote_options] [pinning_options]
[--help]
处理函数为do_backup。
(11) 从备份目录backup-path中的备份副本恢复指定实例。如果指定了恢复目标选项,gs_probackup将查找最近的备份并将其还原到指定的恢复目标。否则,使用最近一次备份,代码如下:
gs_probackup restore -B backup-path --instance=instance_name
[-D pgdata-path] [-i backup_id] [-j threads_num] [--progress] [--force] [--no-sync] [--no-validate] [--skip-block-validation]
[--external-mapping=OLDDIR=NEWDIR] [-T OLDDIR=NEWDIR] [--skip-external-dirs] [-I incremental_mode]
[recovery_options] [remote_options] [logging_options]
[--help]
处理函数为do_restore_or_validate。
(12) 将指定的增量备份与其父完全备份之间的所有增量备份合并到父完全备份。父完全备份将接收所有合并的数据,而已合并的增量备份将作为冗余被删除。代码如下:
gs_probackup merge -B backup-path --instance=instance_name -i backup_id
[-j threads_num] [--progress] [logging_options]
[--help]
处理函数为do_merge。
(13) 删除指定备份,或删除不满足当前保留策略的备份,代码如下:
gs_probackup delete -B backup-path --instance=instance_name
[-i backup-id | --delete-expired | --merge-expired | --status=backup_status]
[--delete-wal] [-j threads_num] [--progress]
[--retention-redundancy=retention-redundancy] [--retention-window=retention-window]
[--wal-depth=wal-depth] [--dry-run]
[logging_options]
[--help]
处理函数为do_delete,do_retention和do_delete_status。
(14) 验证恢复数据库所需的所有文件是否存在且未损坏。如果未指定instance_name,gs_probackup将验证备份目录中的所有可用备份。如果指定instance_name而不指定任何附加选项,gs_probackup将验证此备份实例的所有可用备份。如果指定了instance_name并且指定backup-id或恢复目标相关选项,gs_probackup将检查是否可以使用这些选项恢复数据库。代码如下:
gs_probackup validate -B backup-path
[--instance=instance_name] [-i backup-id]
[-j threads_num] [--progress] [--skip-block-validation]
[--recovery-target-time=time | --recovery-target-xid=xid | --recovery-target-lsn=lsn | --recovery-target-name=target-name]
[--recovery-target-inclusive=boolean] [--recovery-target-timeline=timeline]
[logging_options]
[--help]
处理函数为do_validate_all和do_restore_or_validate。
gs_probackup在执行各个子命令处理函数之前,需要解析各个命令的命令行参数,gs_probackup支持的命令行参数如表2所示。
表2 命令行参数
参数 | 类别 | 描述 |
Command | 通用参数 | gs_probackup除version和help以外的子命令:init、add-instance、del-instance、set-config、set-backup、show-config、show、backup、restore、merge、delete、validate |
-?, --help | 通用参数 | 显示gs_probackup命令行参数的帮助信息,然后退出。子命令中只能使用--help,不能使用-? |
-V, --version | 通用参数 | 打印gs_probackup版本,然后退出 |
-B backup-path, --backup-path=backup-path | 通用参数 | 备份的路径。 系统环境变量:$BACKUP_PATH |
-D pgdata-path, --pgdata=pgdata-path | 通用参数 | 数据目录的路径。 系统环境变量:$PGDATA |
--instance =instance_name | 通用参数 | 实例名 |
-i backup-id, --backup-id=backup-id | 通用参数 | 备份的唯一标识 |
--format=format | 通用参数 | 指定显示备份信息的格式,支持plain和json格式。 默认值:plain |
--status =backup_status | 通用参数 | 删除指定状态的所有备份 |
-j threads_num, --threads=threads_num | 通用参数 | 设置备份、还原、合并进程的并行线程数 |
--archive | 通用参数 | 显示WAL归档信息 |
--progress | 通用参数 | 显示进度 |
--note=text | 通用参数 | 给备份添加note |
-b backup-mode, --backup-mode=backup-mode | 备份参数 | 指定备份模式,支持FULL和PTRACK。 FULL:创建全量备份,全量备份包含所有数据文件 PTRACK:创建PTRACK增量备份 |
-C, --smooth-checkpoint | 备份参数 | 将检查点在一段时间内完成。默认情况下,gs_probackup会尝试尽快完成检查点 |
-S slot-name, --slot=slot-name | 备份参数 | 指定WAL流处理的复制槽 |
--temp-slot | 备份参数 | 在备份的实例中为WAL流处理创建一个临时物理复制槽,它确保在备份过程中,所有所需的WAL段仍然是可用的。默认的slot名为pg_probackup_slot,可通过选项--slot/-S更改 |
--backup-pg-log | 备份参数 | 将日志目录包含到备份中。此目录通常包含日志消息,默认情况下不包含日志目录 |
-E external-directories-paths, --external-dirs=external-directories-paths | 备份参数 | 将指定的目录包含到备份中。此选项对于备份位于数据目录外部的脚本、SQL转储和配置文件很有用。如果要备份多个外部目录,请在UNIX上用冒号分隔它们的路径,如-E /tmp/dir1:/tmp/dir2 |
--skip-block-validation | 备份参数 | 关闭块级校验,加快备份速度 |
--no-validate | 备份参数 | 在完成备份后跳过自动验证 |
--no-sync | 备份参数 | 不将备份文件同步到磁盘 |
--archive-timeout=timeout | 备份参数 | 以秒为单位设置流式处理的超时时间。 默认值:300 |
-I, --incremental-mode=none|checksum|lsn | 恢复参数 | 若PGDATA中可用的有效页没有修改,则重新使用他们。 默认值:none |
--external-mapping=OLDDIR=NEWDIR | 恢复参数 | 在恢复时,将包含在备份中的外部目录从OLDDIR重新定位到NEWDIR目录。OLDDIR和NEWDIR都必须是绝对路径。如果路径中包含“=”,则使用反斜杠转义。此选项可为多个目录多次指定 |
-T OLDDIR=NEWDIR, --tablespace-mapping=OLDDIR=NEWDIR | 恢复参数 | 在恢复时,将表空间从OLDDIR重新定位到NEWDIR目录。OLDDIR和NEWDIR必须都是绝对路径。如果路径中包含“=”,则使用反斜杠转义。多个表空间可以多次指定此选项。此选项必须和--external-mapping一起使用 |
--skip-external-dirs | 恢复参数 | 跳过备份中包含的使用--external-dirs选项指定的外部目录。这些目录的内容将不会被恢复 |
--skip-block-validation | 恢复参数 | 跳过块级校验,以加快验证速度。在恢复之前的自动验证期间,将仅做文件级别的校验 |
--no-validate | 恢复参数 | 跳过备份验证 |
--force | 恢复参数 | 允许忽略备份的无效状态。如果出于某种原因需要从损坏的或无效的备份中恢复数据,可以使用此标志。请谨慎使用 |
--recovery-target=immediate|latest | 恢复目标参数 | 恢复目标参数:如果配置了连续的WAL归档,则可以和restore命令一起使用这些参数,定义何时停止恢复。 immediate:当达到指定备份的一致性状态后,停止恢复;如果省略-i/--backup_id参数,则恢复到最新的可用的备份之后,停止恢复。 latest:持续进行恢复,直到应用了所有存档中的所有可用的WAL段。 --recovery-target的默认值取决于要恢复的备份的WAL传输方式,STREAM流备份为immediate,归档模式为latest |
--recovery-target-timeline=timeline | 恢复目标参数 | 指定要恢复到的timeline。缺省情况下,使用指定备份的timeline |
--recovery-target-lsn=lsn | 恢复目标参数 | 指定要恢复到的lsn |
--recovery-target-name=target-name | 恢复目标参数 | 指定要将数据恢复到的已命名的保存点 |
--recovery-target-time=time | 恢复目标参数 | 指定要恢复到的时间 |
--recovery-target-xid=xid | 恢复目标参数 | 指定要恢复到的事务ID |
--recovery-target-inclusive=boolean | 恢复目标参数 | 当该参数指定为true时,恢复目标将包括指定的内容。 当该参数指定为false时,恢复目标将不包括指定的内容。 该参数必须和--recovery-target-name、--recovery-target-time、--recovery-target-lsn或--recovery-target-xid一起使用 |
--recovery-target-action=pause|promote|shutdown | 恢复目标参数 | 指定恢复至目标时,服务器应执行的操作 |
--restore-command=cmdline | 恢复目标参数 | 指定恢复相关的命令。 例如:--restore-command='cp /mnt/server/archivedir/%f "%p"' |
--retention-redundancy=retention-redundancy | 备份留存参数 | 备份留存相关参数:可以和backup和delete命令一起使用这些参数。指定在数据目录中留存的完整备份数。必须为正整数。0表示禁用此设置。 默认值:0 |
--retention-window=retention-window | 备份留存参数 | 指定留存的天数。必须为正整数。0表示禁用此设置。 默认值:0 |
--wal-depth=wal-depth | 备份留存参数 | 每个时间轴上必须留存的执行PITR能力的最新有效备份数。必须为正整数。0表示禁用此设置。 默认值:0 |
--delete-wal | 备份留存参数 | 从任何现有的备份中删除不需要的WAL文件 |
--delete-expired | 备份留存参数 | 删除不符合pg_probackup.conf配置文件中定义的留存策略的备份 |
--merge-expired | 备份留存参数 | 将满足留存策略要求的最旧的增量备份与其已过期的父备份合并 |
--dry-run | 备份留存参数 | 显示所有可用备份的当前状态,不删除或合并过期备份 |
--ttl=interval | 备份留存参数 | 指定从恢复时间开始计算,备份要留存的时间量。必须为正整数。0表示取消备份固定。 支持的单位:ms,s,min,h,d(默认为s)。例如:--ttl=30d。 将某些备份从已建立的留存策略中排除,可以和backup和set-backup命令一起使用这些参数 |
--expire-time=time | 备份留存参数 | 指定备份留存失效的时间戳。必须是ISO-8601标准的时间戳。 例如:--expire-time='2020-01-01 00:00:00+03' |
--log-level-console=log-level-console | 日志参数 | 日志级别:verbose、log、info、warning、error和off。设置要发送到控制台的日志级别。每个级别都包含其后的所有级别。级别越高,发送的消息越少。指定off级别表示禁用控制台日志记录。 默认值:info |
--log-level-file=log-level-file | 日志参数 | 设置要发送到日志文件的日志级别。每个级别都包含其后的所有级别。级别越高,发送的消息越少。指定off级别表示禁用日志文件记录。 默认值:off |
--log-filename=log-filename | 日志参数 | 指定要创建的日志文件的文件名。文件名可以使用strftime模式,因此可以使用%-escapes指定随时间变化的文件名。 例如,如果指定了“pg_probackup-%u.log”模式,则pg_probackup为每周的每一天生成单独的日志文件,其中%u替换为相应的十进制数字,即pg_probackup-1.log表示星期一;pg_probackup-2.log表示星期二,以此类推。 如果指定了--log-level-file参数启用日志文件记录,则该参数有效。 默认值:"pg_probackup.log" |
--error-log-filename=error-log-filename | 日志参数 | 指定仅用于error日志的日志文件名。指定方式与--log-filename参数相同。此参数用于故障排除和监视 |
--log-directory=log-directory | 日志参数 | 指定创建日志文件的目录。必须是绝对路径。此目录会在写入第一条日志时创建。 默认值:$BACKUP_PATH/log |
--log-rotation-size=log-rotation-size | 日志参数 | 指定单个日志文件的最大值。如果达到此值,则启动gs_probackup命令后,日志文件将循环,但help和version命令除外。0表示禁用基于文件大小的循环。 支持的单位:KB、MB、GB、TB(默认为KB)。 默认值:0 |
--log-rotation-age=log-rotation-age | 日志参数 | 单个日志文件的最大生命周期。如果达到此值,则启动gs_probackup命令后,日志文件将循环,但help和version命令除外。$BACKUP_PATH/log/log_rotation目录下保存最后一次创建日志文件的时间。0表示禁用基于时间的循环。 支持的单位:ms,s,min,h,d(默认为min)。 默认值:0 |
-d dbname, --pgdatabase=dbname | 连接参数 | 指定要连接的数据库名称。该连接仅用于管理备份进程,因此您可以连接到任何现有的数据库。如果命令行、PGDATABASE环境变量或pg_probackup.conf配置文件中没有指定此参数,则gs_probackup会尝试从PGUSER环境变量中获取该值。如果未设置PGUSER变量,则从当前用户名获取。系统环境变量:$PGDATABASE |
-h hostname, --pghost=hostname | 连接参数 | 指定运行服务器的系统的主机名。如果该值以斜杠开头,则被用作UNIX域套接字的路径。 系统环境变量:$PGHOST。 默认值:local socket |
-p port, --pgport=port | 连接参数 | 指定服务器正在侦听连接的TCP端口或本地UNIX域套接字文件扩展名。 系统环境变量:$PGPORT。 默认值:5432 |
-U username, --pguser=username | 连接参数 | 指定所连接主机的用户名。 系统环境变量:$PGUSER |
-w, --no-password | 连接参数 | 不出现输入密码提示。如果主机要求密码认证并且密码没有通过其他形式给出,则连接尝试将会失败。该选项在批量工作和不存在用户输入密码的脚本中很有帮助 |
-W, --password | 连接参数 | 强制出现输入密码提示 |
--compress-algorithm=compress-algorithm | 压缩参数 | 可以和backup命令一起使用这些参数,指定用于压缩数据文件的算法。 compress-algorithm取值包括zlib、pglz和none。如果设置为zlib或pglz,此选项将启用压缩。默认情况下,压缩功能处于关闭状态。 默认值:none |
--compress-level=compress-level | 压缩参数 | compress-level指定压缩级别。取值范围:0~9。 0表示无压缩; 1表示压缩比最小,处理速度最快; 9表示压缩比最大,处理速度最慢; 可与--compress-algorithm选项一起使用。 默认值:1 |
--remote-proto=protocol | 远程模式参数 | 通过SSH远程运行gs_probackup操作的相关参数。可以和add-instance、set-config、backup、restore命令一起使用这些参数。 指定用于远程操作的协议。目前只支持SSH协议。取值包括: SSH:通过SSH启用远程备份模式,这是默认值。 none:显式禁用远程模式。 如果指定了--remote-host参数,可以省略此参数 |
--remote-host=destination | 远程模式参数 | 指定要连接的远程主机的IP地址或主机名 |
--remote-port=port | 远程模式参数 | 指定要连接的远程主机的端口号。 默认值:22 |
--remote-user=username | 远程模式参数 | 指定SSH连接的远程主机用户。如果省略此参数,则使用当前发起SSH连接的用户。 默认值:当前用户 |
--remote-path=path | 远程模式参数 | 指定gs_probackup在远程系统的安装目录。 默认值:当前路径 |
--ssh-options=ssh_options | 远程模式参数 | 指定SSH命令行参数的字符串。 例如:--ssh-options='-c cipher_spec -F configfile' |
2.2 gs_probackup主要文件
增量备份与全量备份相比,最重要的就是对备份数据和元数据的管理。备份数据主要通过目录来区分,元数据主要通过backup.control文件来管理。gs_probackup的主要目录文件如下。
(1) backup_path:备份根目录,所有实例的备份文件都存放在这个目录下。
(2) backup_path/backups/:数据根目录,所有实例的数据文件都存放在这个目录下。
(3) backup_path/wal/:日志根目录,所有实例的日志文件都存放在这个目录下。
(4) backup_path/backups/instance_name:实例的数据根目录,一个实例的所有数据都存放在这个目录下。实例备份的配置参数文件pg_probackup.conf存放在这个目录下。
(5) backup_path/wal/instance_name:实例的日志根目录,一个实例的所有WAL日志都存放在这个目录下。
(6) backup_path/backups/instance_name/backupID:一个具体备份的数据目录,一次备份的数据存放在这个backupID下,backupID是用这次备份的开始时间start_time进行36位编码生成的,即backupID等于base36enc(backup->start_time),base36enc是一个36位编码的转换函数。备份元数据控制文件backup.control就存放在这个目录下。
gs_probackup备份元数据文件backup.control内容参照pgBackupWriteControl函数写的内容,也可以通过gs_probackup show -B backup-path查看备份元数据信息。
文件内容具体如下:
(1) #Configuration 配置小节。
① backup-mode = "PAGE","PTRACK","DELTA","FULL"。当前只支持FULL和PTRACK。
② stream = true 或者 false,表示是否流复制备份模式。
③ compress-alg = none,zlib或者pglz。
④ compress-level = 0到9,级别越大,压缩率越高。
⑤ from-replica = true或者 false,true表示是从备机备份数据,false表示从主机备份数据。通过执行pg_is_in_recovery SQL函数来判断主备机。
(2) #Compatibility 兼容性小节。
① block-size = 数据库数据文件数据页的大小。
② xlog-block-size = 数据库日志文件日志页的大小。
③ checksum-version = CRC校验算法的版本号,数值类型。global/pg_control文件中的data_checksum_version。
④ program-version = gs_probackup工具版本号,字符串类型。
⑤ server-version = 数据库服务器版本号,字符串类型。
(3) #Result backup info。
① timelineid = 备份时数据库的时间线。
② start-lsn = 备份开始时的XLOG位置。
③ stop-lsn = 备份结束时的XLOG位置。
④ start-time = 备份开始时的时间(备份状态设置为BACKUP_STATUS_RUNNING的时间)。
⑤ merge-time = 备份合并的时间,如果没有合并,则为0。
⑥ end-time = 备份结束时的时间(或者是备份非正常终止的时间)。
⑦ recovery-xid = 这个备份能够恢复到的最早事务ID。
⑧ recovery-time = 这个备份能够恢复到的最早时间点。
⑨ expire-time = 备份过期的时间。
⑩ merge-dest-id = 备份能合并到的备份ID。
⑪ data-bytes = 备份的数据大小,这个是原始大小。
⑫ wal-bytes = 备份的WAL日志文件大小。
⑬ uncompressed-bytes = 备份的数据未压缩大小,不包括WAL文件。
⑭ pgdata-bytes = 备份时数据库的数据目录PGDATA的大小。
⑮ status = 备份状态 "UNKNOWN","OK","ERROR","RUNNING","MERGING","MERGED","DELETING","DELETED","DONE","ORPHAN","CORRUPT"。
⑯ parent-backup-id = 父备份ID,只有在增量备份的时候有效。
⑰ primary_conninfo = 连接数据库的信息。replication,dbname,fallback_application_name,password等连接信息。
⑱ external-dirs = 备份的外部地址列表。
⑲ note = 备份的注释信息。
⑳ content-crc = 整个备份数据的CRC校验值。backup_content.control文件的CRC值。backup_content.control文件存放了备份文件的信息。
2.3 gs_probackup备份恢复流程
gs_probackup工具在备份之前需要先进行备份目录初始化,然后进行数据库实例的全量备份,在全量备份的基础上才能进行增量备份。类似地,增量恢复也必须以某个全量备份为基础进行恢复。gs_probackup除了支持本地备份外,也支持通过SSH进行远程备份。下面是几个主要的步骤。
(1) 初始化备份目录。在指定的目录下创建backups/和wal/子目录,分别用于存放备份文件和WAL文件,代码如下:
gs_probackup init -B backup_dir
(2) 初始化一个数据库实例的备份,代码如下:
gs_probackup add-instance -B backup_dir -D data_dir --instance instance_name [remote_options]
(3) 创建指定实例的备份。在进行增量备份之前,必须至少创建一次全量备份。全量还是增量由-b backup_mode参数控制,FULL表示创建全量备份,PTRACK表示创建PTRACK增量备份,代码如下:
gs_probackup backup -B backup_dir --instance instance_name -b backup_mode
(4) 从指定实例的备份中恢复数据,代码如下:
gs_probackup restore -B backup_dir --instance instance_name -i backup_id
如果进行远程备份和恢复,需要初始化备份目录和初始化一个数据库实例的备份,第一步、第二步和本地备份恢复是相同的,执行上文中的(1)和(2)即可。但第三步和第四步需要使用SSH的远程连接信息进行备份和恢复,步骤如下所示。
(1) 远程备份,代码如下:
gs_probackup backup -B backup_dir -b FULL --stream --instance=instance_name --remote-user=remote_user --remote-host=ip --remote-port=remote_port -d db -p port -U user
(2) 远程恢复,代码如下:
gs_probackup restore -B backup_dir --instance=instance_name --remote-user=remote_user --remote-host=ip --remote-port=remote_port --incremental-mode=checksum
下面介绍每个处理函数的详细实现。
(1) init命令的处理函数是do_init,在do_init函数中。
① 首先检查命令行输入的备份路径backup_dir是否为空目录,要求必须为空目录。如果backup_dir不存在,则创建。
② 在backup_dir下创建backups子目录,创建wal子目录。
(2) add-instance的处理函数为do_add_instance,在do_add_instance处理函数中。
① 创建backup_dir/backups/instance_name子目录,创建backup_dir/wal/instance_name子目录。
② 获取实例备份参数信息,包括system_identifier,xlog_seg_size,remote.host,remote.proto,remote.port,remote.path,remote.user,remote.ssh_options,remote.ssh_config等,通过调用函数do_set_config把这些实例备份信息写到backup_path/backups/instance_name/pg_probackup.conf配置文件中。
(3) backup的处理函数为do_backup,do_backup根据参数backup_mode是FULL还是PTRACK进行全量或者增量备份。全量备份和增量备份基本流程是一样的,唯一的区别是全量备份拷贝全部数据文件,增量备份只拷贝自上次备份以来的脏数据页。函数的处理流程如下。
① 调用pgNodeInit初始化备份数据库服务器节点的信息。
② 设置备份状态为BACKUP_STATUS_RUNNING和其他备份元数据,包括备份时间、当前版本、压缩算法、压缩级别和外部目录地址。
③ 调用pgBackupCreateDir创建备份路径,备份路径由pgBackupGetPath构造,路径为backup_dir/backups/instance_name/base36enc(backup->start_time),同时创建外部目录的备份地址,地址为backup_dir/backups/instance_name/ extern_direc。
④ 备份元数据写入到backup.control控制文件中。
⑤ 调用pgdata_basic_setup创建到数据库服务器的连接,检查校验备份工具的block_size、wal_block_size,checksum_version等和数据库服务器的版本是兼容的。调用check_system_identifiers校验系统标识符system_identifier是一致的。检查数据库服务器的ptrack版本是兼容的,并且开关是打开的。
⑥ 调用add_note把备份描述信息添加到备份元数据中。
⑦ 调用do_backup_instance进行数据库实例数据备份。
⑧ 更新备份元数据中的备份结束时间,备份状态为BACKUP_STATUS_DONE。更新备份的留存策略ttl或者expire_time。
⑨ 如果需要校验备份,则调用pgBackupValidate对备份数据进行校验。
⑩ 最后如果需要删除过期的备份或者合并备份,则调用do_retention把过期的备份删除。
(4) restore的处理函数为do_restore_or_validate,函数的处理流程如下。
① 检查如果data目录不为空,看是否为增量恢复,并且当前的增量和路径中存在的数据是否兼容。首先检查两者的system_identifier标识符是否一致,如果不一致,则恢复失败。然后检查目录中是否有备份标签文件,如果存在,则恢复失败。
② 调用catalog_get_backup_list获取实例的所有备份。在catalog_get_backup_list函数中,遍历实例所有的backup.control文件,获取所有backup_id,并且根据backup_id排序。所有增量备份和他们的祖先连接起来,备份元数据有一个parent_backup,指向的就是父备份ID。
/* Link incremental backups with their ancestors.*/
for (i = 0; i < parray_num(backups); i++)
{
pgBackup *curr = parray_get(backups, i);
pgBackup **ancestor;
pgBackup key;
if (curr->backup_mode == BACKUP_MODE_FULL)
continue;
key.start_time = curr->parent_backup;
ancestor = (pgBackup **) parray_bsearch(backups, &key,
pgBackupCompareIdDesc);
if (ancestor)
curr->parent_backup_link = *ancestor;
}
③ 在备份列表中,查找满足恢复条件的备份。如果指定了target_backup_id则根据backup_id进行匹配。如果指定了pgRecoveryTarget,则根据pgRecoveryTarget进行匹配,判断函数为satisfy_recovery_target。
④ 如果找到的备份是全量备份,那么当前backup_id就是满足要求的。如果找到的备份是增量备份,需要遍历整个增量备份链表查找之前所有备份都是正常的。
⑤ 检查表空间映射是正常的。
⑥ 如果是INCR_LSN恢复,确定恢复链中的恢复位置。
⑦ 如果恢复前需要验证文件正确性,则调用pgBackupValidate和validate_wal验证数据文件和日志文件正确性。
⑧ 调用restore_chain根据备份链进行恢复。
⑨ 根据传入的恢复参数调用create_recovery_conf创建recovery.conf恢复文件。整个恢复结束。
其他的一些流程处理如下。
(5) help的help_pg_probackup和help_command,这两个函数的处理都在help.cpp中。
① help_pg_probackup命令没有输入参数,就是打印整个工具的命令行使用帮助信息。
② help_command(char *command)有一个输入参数command,根据command参数指定的子命令分别调用相应子命令的帮助处理函数。
(6) del-instance删除实例的处理函数为do_delete_instance,在do_delete_instance处理函数中。
① 调用catalog_get_backup_list获取实例。backup_dir/backups/instance_name子目录下的所有数据备份。遍历删除这些数据备份。
② 删除backup_dir/wal/instance_name子目录下的所有WAL日志文件。
③ 删除实例备份配置文件backup_dir/backups/instance_name/pg_probackup.conf。
④ 删除实例backup_dir/backups/instance_name子目录本身,删除backup_path/wal/instance_name子目录本身。
(7) 设置实例备份配置文件backup_dir/backups/instance_name/pg_probackup.conf的处理函数为do_set_config,do_set_config的根据解析的命令行参数,以name = value的形式把新值设置到配置文件中。pg_probackup.conf是文本文件,为了避免文件写坏,先把内容写到一个pg_probackup.conf.tmp临时文件,最后再重命名为正式文件。
(8) 显示实例备份配置文件backup_dir/backups/instance_name/pg_probackup.conf的处理函数为do_show_config,do_show_config函数根据命令行要求是json还是普通格式把参数以name=value的方式显示出来。
2.4 redo日志增量备份恢复流程
在gs_basebackup或者gs_probackup工具全量备份的基础上,再加上数据库的redo日志,就可以实现基于redo日志的增量备份和恢复。如果把所有redo日志都进行归档备份,那么数据库就可以实现基于时间点的恢复PITR,把数据库恢复到基于全量备份以来的任意时间点。当前openGauss没有提供工具进行redo日志的备份,应用可以通过配置归档命令的方式或者自己拷贝的方式把redo日志拷贝到备份目录进行备份。恢复时只需要一个全量备份加上redo日志就可以进行数据库的恢复。这个过程不涉及代码逻辑,所以不再进行详细描述。
三、小结
物理备份是通过拷贝文件方式进行的备份,备份文件主要分为数据文件和XLOG文件,为了保证备份可用,需要保证XLOG文件的范围覆盖了备份数据的整个过程。因为在拷贝数据的过程中,这些数据页可能被正在执行的在线事务进行修改,这些修改只能通过XLOG恢复保证数据的一致性。增量备份只拷贝上次备份以来的数据脏页,能减少备份的数据量,提高备份效率,但增量备份只能恢复到备份的某个时间点,无法恢复到任意时间点,任意时间点的恢复只能用全量备份和全量XLOG日志的方式进行实现。