当前位置: 代码迷 >> 综合 >> postgres 源码解析2 pg_basebackup
  详细解决方案

postgres 源码解析2 pg_basebackup

热度:75   发布时间:2023-11-24 18:34:46.0

介绍

? ? 在postgres中pg_basebackup提供一个全量备份,可以将整个数据库实例的数据都拷贝出来,需要使用 replication协议连接到数据库实例上。该工具常用来搭建流复制环境,属于物理备份。逻辑备份工具时pg_dump

pg_basebackup 参数介绍

[postgres@node196 data]$ pg_basebackup --help
pg_basebackup takes a base backup of a running PostgreSQL server.Usage:pg_basebackup [OPTION]...Options controlling the output:-D, --pgdata=DIRECTORY receive base backup into directory     // 备份目标目录-F, --format=p|t       output format (plain (default), tar)   // 输出格式 p:原样输出,把主库数据库中// 的各个数据文件、配置文件、目录结构都完全一样地写入备份目录;t:将输出文件打包成tar文件形式。-r, --max-rate=RATE    maximum transfer rate to transfer data directory(in kB/s, or use suffix "k" or "M")// 最大传输速率(KB/s)-R, --write-recovery-confwrite configuration for replication// 备份后写 recovery.conf文件-T, --tablespace-mapping=OLDDIR=NEWDIRrelocate tablespace in OLDDIR to NEWDIR// 指定NEWDIR 代替 OLDDIR--waldir=WALDIR    location for the write-ahead log directory// 指定WAL日志位置-X, --wal-method=none|fetch|stream include required WAL files with specified method-z, --gzip             compress tar output // tar包进行gzip压缩-Z, --compress=0-9     compress tar output with given compression level General options:-c, --checkpoint=fast|spreadset fast or spread checkpointing //设置checkpoint模式为fast|spread-C, --create-slot      create replication slot  // 创建复制槽-l, --label=LABEL      set backup label-n, --no-clean         do not clean up after errors  -N, --no-sync          do not wait for changes to be written safely to disk // 不必等待更该安持久化至磁盘-P, --progress         show progress information  // 显示备份进度-S, --slot=SLOTNAME    replication slot to use    // -v, --verbose          output verbose messages-V, --version          output version information, then exit--manifest-checksums=SHA{
    224,256,384,512}|CRC32C|NONEuse algorithm for manifest checksums--manifest-force-encodehex encode all file names in manifest--no-estimate-size do not estimate backup size in server side--no-manifest      suppress generation of backup manifest--no-slot          prevent creation of temporary replication slot--no-verify-checksumsdo not verify checksums-?, --help             show this help, then exitConnection options:       // 连接参数选项-d, --dbname=CONNSTR   connection string     -h, --host=HOSTNAME    database server host or socket directory-p, --port=PORT        database server port number-s, --status-interval=INTERVALtime between status packets sent to server (in seconds) // 向服务器反馈周期时间间隔-U, --username=NAME    connect as specified database user-w, --no-password      never prompt for password-W, --password         force password prompt (should happen automatically)

源码解读 src/bin/pg_basebackup/pg_basebackup.c

? ? pg_basebackup的执行流程如下:
1 变量初始化,进行环境检查;
2 解析命令行参数,如果 --help || -?,打印帮助说明,并退出;
3 清理本地已存在的数据目录+内容/WAL目录 + 内容(如果与指定的备份目录同名)
4 获取完整的命令行选项,据此设置填充相应的参数供后续使用(有兴趣详见源代码);
5 参数合理性检查,未指明目标目录;输出格式为p时不能指定compresslevel;
6 以replication模式与server建立连接;
7 验证目标文件是否存在,如果不存在,则新建,若存在但内容非空,则pg_basebackup执行失败;
8 确定server 端XLOG 段文件的大小是否合法,
9 调用BaseBackup函数实现基础备份,实现逻辑如下:
1)检查当前服务端版本,BASE_BACKUP命令在9.1版本引入,因此在9.1之前不能工作;
2)如果需要写recovery.conf文件,则调用GenerateRecoveryConfig函数将PQconninfoOption参数信息写入PQExpBuffer中;
3)调用RunIdentifySystem向主发送 IDENTIFY_SYSTEM命令,主接收到命令解析执行并返回系统标识符和时间线;
4) 生成BASEBACKUP
5)获取WAL复制起始点和时间线(9.3版本时间线为WAL起始点对应的时间线,9.3版本前默认为最新的时间线latest timeline);
6) 循环遍历表空间,计算总文件大小,如果向将tar格式的文件标准输出只能写入单个表空间;
7)如果采用WAL 流复制的方式进行基础备份时,调用StartLogStreamer函数在本地启动WAL receiver后台进程接收主发送的数据文件;
8) 对于每个表空间:分别根据format指定的格式拉取数据,若是t则调用ReceiveTarFile接收tar文件,否则调用ReceiveAndUnpackTarFile接收tar文件并解压。这里接收的是数据文件;
接收日志和接收数据不在同一个进程中,为流复制单独创建一个接收日志子进程,子进程接收日志开始的命令是START_REPLICATION,然后开启COPY流;
数据的话应该是BASE_BACKUP,然后开启COPY流;
9)接着根据指定的参数决定是否打印进度;
10)获取wal结束位置xlogend;
11)根据指定的参数决定是否打印wal end point点;
12)调用waitpid等待子进程退出;
13)最后断开连接,释放内存等资源,并将数据全部sync。

Basebackup
|–CheckServerVersionForStreaming
|-- GenerateRecoveryConfig
|-- RunIdentifySystem
|-- PQescapeStringConn
|-- PQgetResult(conn)
|-- res = PQntuples(res)
|-- tablespacecount = PQntuples(res)
|-- StartLogStreamer
|-- ReceiveTarFile | ReceiveAndUnpackTarFile
|–PQgetResult
|-- destroyPQExpBuffer
|-- PQclear
|-- PQfinish

typedef struct
{
    PGconn	   *bgconn;XLogRecPtr	startptr;char		xlog[MAXPGPATH];	/* directory or tarfile depending on mode */char	   *sysidentifier;int			timeline;
} logstreamer_param;
/** Start a child process and tell it to start streaming. On Unix, this is* a fork(). On Windows, we create a thread.*/
#ifndef WIN32bgchild = fork();if (bgchild == 0){
    /* in child process */exit(LogStreamerMain(param));}else if (bgchild < 0){
    pg_log_error("could not create background process: %m");exit(1);}

可以看出,在进行数据传输时,会fork出一个后端进程来执行,执行函数入口为:LogStreamerMain
1 根据时间线,复制起始点和系统标识符初始化StreamCtl结构体;
2 调用ReceiveXlogStream从服务器上接收数据,执行流程:
1)首先判断系统标识符是否存在,存在的话通过向主发送TIMELINE_HISTORY命令获取主时间线和系统标识符,然后写到本地。
2)向主发送START_REPLICATION命令,开始复制,调用函数HandleCopyStream处理COPY流
3)如果当前时间线的日志接收完,那么从下一个时间线开始重新接收。下一个时间线及其起始位置会由HandleCopyStream返回res中记录。下个时间线流复制开始位置会对齐到文件头位置。(也就是说总是从文件头开始复制)
4)如果返回的结果状态时PGRES_COMMAND_OK表示复制结束
3 断开与服务器间的连接,释放此过程中所占用的内存资源

在这里插入图片描述
参考:https://blog.csdn.net/yanzongshuai/article/details/117376916
该文为本人原创,转载请表明出处。