目录
本文主要介绍openGauss的备份恢复原理和技术。备份恢复是数据库日常维护的一个例行活动,通过把数据库数据备份到另外一个地方,可以抵御介质类的损坏,增加数据库数据的可靠性。数据库的备份恢复主要分为逻辑备份恢复和物理备份恢复。
逻辑备份是把数据库中的数据导出为文本文件,这些文本文件内容一般来说是SQL语句。恢复数据时再把文本文件中的SQL语句导入数据库中恢复。逻辑备份比较灵活,可以支持库级、模式级和表级备份,但逻辑备份只读取了某个时间点的数据库快照对应的数据,很难实现增量备份,恢复时也无法恢复到指定的时间点。在openGauss中实现逻辑备份恢复的工具为gs_dump/gs_restore,具体使用方法参考openGauss官网《管理员指南》手册。
物理备份是直接复制数据库的物理文件,性能比较高,对应用的约束比较少,但只能对整个库进行备份。物理备份又分为全量备份和增量备份。增量备份又有两种方式,一种是结合数据库的脏页跟踪实现的增量备份,另外一种是根据redo日志的增量实现的增量备份。根据脏页进行的增量备份可以和历史上的备份进行合并,减少存储空间的占用,恢复时可以恢复到增量备份的时间点,无法恢复到任意时间点。根据redo日志进行的增量备份在恢复时可以恢复到指定时间点,但所有的redo日志都需要进行备份,占用的存储空间较大。
逻辑备份主要用于异构数据库的迁移,物理备份主要用于保障数据库数据的可靠性。本章主要介绍openGauss的物理备份机制,包括全量备份技术和增量备份技术。
10.1 openGauss全量备份技术
openGauss有两个备份工具gs_basebackup和gs_probackup。gs_basebackup只能进行全量备份,gs_probackup既可进行全量备份,也可进行增量备份。gs_probackup全量备份的原理和gs_basebackup是类似的,本节以gs_basebackup工具为例介绍全量备份的原理。
10.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的主干处理流程比较简单,首先对支持的命令行参数进行解析,主要的命令行参数请参照表1。参数解析后进入备份主函数BaseBackup,BaseBackup参照后面详细介绍。在主函数之后是free_basebackup,释放前面分配的内存资源,整个备份流程就结束了。
表1 命令参数
参数 | 描述 |
-D | 备份的目的路径 |
-F | 备份的文件格式,plain普通格式和tar压缩包格式 |
-X | 是否进行流复制模式,当前要求必须采用流复制模式,保证备份数据的正确性 |
-Z | 压缩级别 |
-c | 备份时是否做快速检查点 |
-h | 进行备份的数据库服务器监听IP地址 |
-p | 进行备份的数据库服务器监听端口号 |
-U | 进行备份时连接数据库服务器的用户名 |
-W | 进行备份时连接数据库服务器的密码 |
-s | 备份时状态更新时间间隔 |
-v | 是否显示备份详细信息 |
- P | 是否显示备份进度信息 |
10.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]还是<tablespaceoid>.tar[.gz]。
(2) 打开tar文件,接收数据库服务器发送的COPY数据流,写入tar文件,直到复制完整个内容。数据库服务器往GsBaseBackup发送的数据流就是一个压缩后的tar流。
如前所述,openGauss的tar包格式是自定义的,所以需要实现解包。解包的命令为GsTar,主要有两个命令行参数。
① -D, --destination=DIRECTORY,解压后的文件存放路径;
② -F, --filename=FILENAME,需要解压的tar包。
以上内容为备份恢复机制:openGauss全量备份技术的相关内容,后续将接着分享“openGauss增量备份技术”的精彩内容,敬请期待!
END