PgSQL · 源码分析 · PostgreSQL物理备份内部原理
介绍
-
pg_basebackup 备份客户端pg_basebackup实现原理 -
backup server 备份内核服务端实现原理 -
rds_basebackup 对于pg_basebackup做的优化方案
pg_basebackup原理介绍
pg_basebackup使用方法
pg_basebackup [option...]
-D directory 保存备份数据的本地目录,如果为 - 且F为tar就输出到标准输出流
--pgdata=directory
-F format 备份文件的格式,p 为平面文件,t为tar文件包。
--format=format plain|tar
-r rate 从该服务器传输数据的最大传输率。值的单位是千字节每秒。加上一个后缀M表示兆字节每秒。也接受后缀k,但是没有效果。合法的值在 32 千字节每秒到 1024 兆字节每秒之间。
--max-rate=rate
-R 在输出目录中(或者当使用 tar 格式时再基础归档文件中)写一个最小的recovery.conf来简化设置一个后备服务器。recovery.conf文件将记录连接设置(如果有)以及pg_basebackup所使用的复制槽,这样流复制后面就会使用相同的设置。
--write-recovery-conf
-S slotname 这个选项只能和-X stream一起使用。它导致 WAL 流使用指定的复制槽。如果该基础备份意图用作一个使用复制槽的流复制后备服务器,它应该使用recovery.conf中相同的复制槽名称。那样就可以确保服务器不会移除基础备份结束和流复制开始之前任何必要的 WAL 数据。
--slot=slotname
-X method 如果为n,则备份时不会包含日志, 如果为f,在备份末尾收集日志文件,如果为s,在备份被创建时流传送预写日志。这将开启一个到服务器的第二连接并且在运行备份时并行开始流传输预写日志。
--wal-method=method none|fetch|stream
从上述的两图中可以看出,pg_basebackup对于全量备份的数据和日志,提供了串行备份和并行备份的方式。fetch模式也就是串行备份需要保证在备份数据的过程中,备份开始时刻的日志需要一直保存下来, 也就说pg的wal_keep_segments需要足够大去保存日志文件,如果备份数据期间,日志开始时刻的日志已经被移除,那么备份就会失败。而stream模式,也就是并行备份过程中wal_max_sender必须保证不小于2。而stream模式不支持,将数据和日志以流的方式输出到标准输出。
pg_basebackup原理
main
为程序入口,接收pg_basebackup –args ,根据参数决定备份的方式选择。进入main
函数后首先进行各种参数合法性判断,最后调用BaseBackup()
函数进行开始备份数据。 BaseBackup
备份数据函数,首先对版本进行判断,必须大于9.1版本,建立服务器连接,创建recovery.conf
文件如果需要,发送IDENTIFY_SYSTEM
命令给服务器设置复制协议,调用 RunIdentifySystem
获取相关信息。发送BASE_BACKUP
命令通知服务器准备备份数据并创建检查点。创建检查点完成后获取检查点在xlog中的lsn,然后获取备份头部数据,计算数据的size,并获取表空间map, 如果参数设置包含日志备份调用StartLogStreamer
函数,创建管道,启动日志备份子进程,开始备份日志。根据F参数t或p判断以tar格式接收(ReceiveTarFile
)还是以平面文件格式接收(ReceiveAndUnpackTarFile
)。获取备份数据结束时wal的lsn,使用管道将endlsn发送给接收日志的子进程。然后等待后台接收日志子进程结束退出,清理recovery.conf
文件, 确定data备份数据持久化到磁盘上,关闭连接,备份完成。 StartLogStreamer
开始日志流备份函数,具体实现,首先获取备份日志的起始LSN,然后创建管道,fork子进程调用LogStreamerMain
函数,开始并行备份日志文件。 ReceiveTarFile
接收tar格式数据文件函数。根据参数判断是输出标准输出流还是写入.tar或者压缩文件。循环获取流数据并拷贝写入文件或者输出流。 ReceiveAndUnpackTarFile
接收平面文件格式数据函数,获取表空间集合,根据目录递归的拷贝文件并写入本地。 LogStreamerMain
备份日志主函数,通过获取连接,和管道接收参数来初始化StreamCtl
日志流操作结构体,然后调用ReceiveXlogStream
函数接收日志流。具体细节如下图:
pg_basebackup存在的问题
备份内核服务端实现原理
备份流程
基础数据发送
重做日志发送
针对于pg_basebakcup做的改进
它的主要思想是交叉的备份数据和日志,然后支出输出标准输出流。我使用了两个线程,一个主线程,一个日志线程,主线程发送备份命令,后接收基础备份数据,日志线程发送流复制命令,接收日志。日志线程接收到日志之后就会将一个个完整的日志文件写入日志缓存区,主线程接收一个完整的数据文件后以tar的格式写入标准输出流,然后就去日志缓冲区刷掉所有的缓冲日志,同时每个日志文件以tar的格式写入流。日志线程会在缓存区满了之后睡眠。这个缓存区我是用的是一个循环双向队列,然后对他的节点加互斥锁,避免主线程读到不完整的数据。这个缓冲区的大小,我提供了参数给用户设置,默认值是24个。
PostgreSQL中文社区欢迎广大技术人员投稿
投稿邮箱:[email protected]