PostgreSQL源码分析——pg_basebackup
涉及到的代码主要在src/backend/replication以及bin/pg_basebackup中。
我们知道pg_basebackup是一个进行基础备份的工具,除了使用这个工具,还可以用底层API的方式进行基础备份,主要过程如下:
- 连接到数据库
- 执行
select pg_start_backup('lable')命令。(会强制发生一次checkpoint,并将检查点记录到backup_label文件中) - 执行备份,把数据目录进行复制(包含backup_label)
- 执行
select pg_stop_backup命令,(删除backup_label文件,并在WAL日志中写入一条XLOG_BACKUP_END的记录,当备节点回放到该记录时,就知道备份结束了,数据达到了一致点,可以对外提供服务了) - 备份过程中产生的WAL日志进行复制
其实,pg_basebackup工具就是对底层API的封装,其主要过程是相同的,但具体到代码,并不是直接调用的pg_start_backup,pg_stop_backup函数,而是通过一些命令的形式,这些特殊的命令定义在src/backend/replication/repl_gram.y中,后面我们会进行分析。
主流程
pg_basebackup执行基础备份的主要流程如下,其中,涉及到libpq协议与服务端进行连接,通信,向服务端发送一些特殊的命令语句,这些命令的解析在src/backend/replication/repl_gram.y中可以查看到具体的语法定义。主流程如下:
main(int argc, char **argv)
--> GetConnection(); // 连接服务端,(例如主节点)--> PQconnectdbParams(keywords, values, true);
--> BaseBackup(); // 执行基础备份--> GenerateRecoveryConfig(conn, replication_slot); // 用于生成primary_conninfo配置信息--> PQconninfo(pgconn);--> RunIdentifySystem(conn, &sysidentifier, &latesttli, NULL, NULL)basebkp = psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s %s %s",escaped_label,estimatesize ? "PROGRESS" : "",includewal == FETCH_WAL ? "WAL" : "",fastcheckpoint ? "FAST" : "",includewal == NO_WAL ? "" : "NOWAIT",maxrate_clause ? maxrate_clause : "",format == 't' ? "TABLESPACE_MAP" : "",verify_checksums ? "" : "NOVERIFY_CHECKSUMS",manifest_clause ? manifest_clause : "",manifest_checksums_clause);// 向服务端发送执行命令"BASE_BACKUP LABEL 'pg14bak' PROGRESS NOWAIT MANIFEST 'yes' "--> PQsendQuery(conn, basebkp) --> PQgetResult(conn); // Get the starting WAL location--> StartLogStreamer(xlogstart, starttli, sysidentifier);--> CreateReplicationSlot(param->bgconn, replication_slot, NULL, temp_replication_slot, true, true, false)// 执行命令 "CREATE_REPLICATION_SLOT \"pg_basebackup_2553309\" TEMPORARY PHYSICAL RESERVE_WAL"--> PQexec(conn, query->data);// Start a child process and tell it to start streaming.// 创建一个单独的子进程用于日志传输bgchild = fork();if (bgchild == 0){/* in child process */LogStreamerMain(param);--> ReceiveXlogStream(param->bgconn, &stream) // Receive a log stream starting at the specified position.}if (!writing_to_stdout && manifest)ReceiveBackupManifest(conn); // receive backup manifest
整个的过程,最重要的有3点:
- 在进行备份前,执行一次checkpoint,记录开始的位置,在服务端接收到
BASE_BACKUP LABLE命令后,生成备份标签文件backup_lable,这个文件最重要的作用是记录数据库恢复的起始位置。当启动备份实例时,会读该文件进行恢复。 - 复制数据库数据文件
- 日志复制
我们可以看一下backup_lable文件中的内容:
postgres@slpc:~/pgsql/pgbak$ ls
backup_label pg_commit_ts pg_notify pg_subtrans postgresql.auto.conf
backup_manifest pg_dynshmem pg_replslot pg_tblspc postgresql.conf
base pg_hba.conf pg_serial pg_twophase standby.signal
current_logfiles pg_ident.conf pg_snapshots PG_VERSION
global pg_logical pg_stat pg_wal
log pg_multixact pg_stat_tmp pg_xact
postgres@slpc:~/pgsql/pgbak$ cat backup_label
START WAL LOCATION: 0/C000028 (file 00000001000000000000000C) 备份开始时日志的位置
CHECKPOINT LOCATION: 0/C000060 检查点的位置
BACKUP METHOD: streamed 备份方法
BACKUP FROM: primary 备份源
START TIME: 2023-08-02 17:15:58 CST 备份开始的物理时间
LABEL: pg14bak 备份标签
START TIMELINE: 1
具体过程
仅看上面的主流程还是有一些不清楚的地方的。
这里有个很重要的命令BASE_BACKUP LABEL,备份命令,获取XLOG的存放路径和备份开始时日志的位置,那么服务端这块是怎么处理的呢?我们看一下服务端的相关代码:
void PostgresMain(int argc, char *argv[], const char *dbname, const char *username)
{// ...if (am_walsender)WalSndSignals();/* Perform initialization specific to a WAL sender process. */if (am_walsender)InitWalSender();for (;;){firstchar = ReadCommand(&input_message);switch (firstchar){case 'Q': /* simple query */{const char *query_string;/* Set statement_timestamp() */SetCurrentStatementStartTimestamp();query_string = pq_getmsgstring(&input_message);pq_getmsgend(&input_message);if (am_walsender){if (!exec_replication_command(query_string))exec_simple_query(query_string);}elseexec_simple_query(query_string);send_ready_for_query = true;}break;}
}/* Execute an incoming replication command.*/
bool exec_replication_command(const char *cmd_string)
{// .../* Looks like a WalSender command, so parse it. */parse_rc = replication_yyparse();if (parse_rc != 0)ereport(ERROR,(errcode(ERRCODE_SYNTAX_ERROR),errmsg_internal("replication command parser returned %d",parse_rc)));switch (cmd_node->type){case T_IdentifySystemCmd:cmdtag = "IDENTIFY_SYSTEM";set_ps_display(cmdtag);IdentifySystem();EndReplicationCommand(cmdtag);break;case T_BaseBackupCmd:cmdtag = "BASE_BACKUP";set_ps_display(cmdtag);PreventInTransactionBlock(true, cmdtag);SendBaseBackup((BaseBackupCmd *) cmd_node);EndReplicationCommand(cmdtag);break;case T_CreateReplicationSlotCmd:cmdtag = "CREATE_REPLICATION_SLOT";set_ps_display(cmdtag);CreateReplicationSlot((CreateReplicationSlotCmd *) cmd_node);EndReplicationCommand(cmdtag);break;case T_DropReplicationSlotCmd:cmdtag = "DROP_REPLICATION_SLOT";set_ps_display(cmdtag);DropReplicationSlot((DropReplicationSlotCmd *) cmd_node);EndReplicationCommand(cmdtag);break;case T_StartReplicationCmd:{StartReplicationCmd *cmd = (StartReplicationCmd *) cmd_node;cmdtag = "START_REPLICATION";set_ps_display(cmdtag);PreventInTransactionBlock(true, cmdtag);if (cmd->kind == REPLICATION_KIND_PHYSICAL)StartReplication(cmd);elseStartLogicalReplication(cmd);/* dupe, but necessary per libpqrcv_endstreaming */EndReplicationCommand(cmdtag);Assert(xlogreader != NULL);break;}case T_TimeLineHistoryCmd:cmdtag = "TIMELINE_HISTORY";set_ps_display(cmdtag);PreventInTransactionBlock(true, cmdtag);SendTimeLineHistory((TimeLineHistoryCmd *) cmd_node);EndReplicationCommand(cmdtag);break;case T_VariableShowStmt:{DestReceiver *dest = CreateDestReceiver(DestRemoteSimple);VariableShowStmt *n = (VariableShowStmt *) cmd_node;cmdtag = "SHOW";set_ps_display(cmdtag);/* syscache access needs a transaction environment */StartTransactionCommand();GetPGVariable(n->name, dest);CommitTransactionCommand();EndReplicationCommand(cmdtag);}break;default:elog(ERROR, "unrecognized replication command node tag: %u",cmd_node->type);}// ...
}
我们继续看一下SendBaseBackup函数的实现。
/** SendBaseBackup() - send a complete base backup.** The function will put the system into backup mode like pg_start_backup()* does, so that the backup is consistent even though we read directly from* the filesystem, bypassing the buffer cache.*/
void SendBaseBackup(BaseBackupCmd *cmd)
{basebackup_options opt;SessionBackupState status = get_backup_status();if (status == SESSION_BACKUP_NON_EXCLUSIVE)ereport(ERROR,(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),errmsg("a backup is already in progress in this session")));parse_basebackup_options(cmd->options, &opt);WalSndSetState(WALSNDSTATE_BACKUP);if (update_process_title){char activitymsg[50];snprintf(activitymsg, sizeof(activitymsg), "sending backup \"%s\"",opt.label);set_ps_display(activitymsg);}perform_base_backup(&opt);
}
主流程如下:
SendBaseBackup(BaseBackupCmd *cmd)
--> perform_base_backup(&opt);// creates the necessary starting checkpoint and constructs the backup label file.--> do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli, labelfile, &tablespaces, tblspc_map_file);--> RequestCheckpoint(CHECKPOINT_FORCE | CHECKPOINT_WAIT | (fast ? CHECKPOINT_IMMEDIATE : 0));--> CreateCheckPoint(flags | CHECKPOINT_IMMEDIATE);
相关文章:
PostgreSQL源码分析——pg_basebackup
涉及到的代码主要在src/backend/replication以及bin/pg_basebackup中。 我们知道pg_basebackup是一个进行基础备份的工具,除了使用这个工具,还可以用底层API的方式进行基础备份,主要过程如下: 连接到数据库执行select pg_start_…...
QT基础 - 常见图表绘制
目录 零. 前言 一. 添加模块 折线图 三. 树状图 四. 饼图 五. 堆叠柱状图 六. 百分比柱状图 七. 散点图和光滑曲线图 散点图 光滑曲线图 零. 前言 Qt Charts 是 Qt 框架的一个模块,用于创建各种类型的图表和数据可视化。它为开发者提供了一套功能强大的工…...
解释React中的“端口(Portals)”是什么,以及如何使用它来渲染子节点到DOM树以外的部分。
React中的“端口(Portals)”是一种将子节点渲染到DOM****树以外的部分的技术。在React应用中,通常情况下组件的渲染是遵循DOM的层次结构,即子组件会渲染在父组件的DOM节点内部。然而,有些情况下,开发者可能…...
java实现分类下拉树,点击时对应搜索---后端逻辑
一直想做分类下拉,然后选择后搜索的页面,正好做项目有了明确的需求,查找后发现el-tree的构件可满足需求,数据要求为:{ id:1, label:name, childer:[……] }形式的,于是乎,开搞! 一…...
【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 披萨大作战(100分) - 三语言AC题解(Python/Java/Cpp)
🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 …...
探索Facebook对世界各地文化的影响
随着数字化时代的到来,社交媒体已成为连接世界各地人们的重要平台之一。而在这个领域的巨头之一,Facebook不仅是人们沟通交流的场所,更是一座桥梁,将不同地域、文化的人们联系在一起。本文将探索Facebook对世界各地文化的影响&…...
导出requirements.txt
文章目录 requirements.txt导出环境中所有包导出当前项目的包可能遇到的问题 requirements.txt 在Python项目中,通常使用requirements.txt文件来列出所有需要的第三方库和模块。这个文件通常位于项目的根目录下,并且在安装Python项目时,可以…...
我主编的电子技术实验手册(09)——并联电路
本专栏是笔者主编教材(图0所示)的电子版,依托简易的元器件和仪表安排了30多个实验,主要面向经费不太充足的中高职院校。每个实验都安排了必不可少的【预习知识】,精心设计的【实验步骤】,全面丰富的【思考习…...
数据结构_二叉树
目录 一、树型结构 二、二叉树 2.1 概念 2.2 特殊的二叉树 2.3 二叉树的性质 2.4 二叉树的存储 2.5 遍历二叉树 2.6 操作二叉树 总结 一、树型结构 树是一种非线性的数据结构,它是由 n(n>0) 个有限结点组成一个具有层次关系的集合,一棵 n 个…...
Java线程池七个参数详解
ThreadPoolExecutor 是JDK中的线程池实现,这个类实现了一个线程池需要的各个方法,它提供了任务提交、线程管理、监控等方法 下面是 ThreadPoolExecutor 类的构造方法源码,其他创建线程池的方法最终都会导向这个构造方法,共有7个参…...
产品Web3D交互展示有什么优势?如何快速制作?
智能互联网时代,传统的图片、文字、视频等产品展示方式,因为缺少互动性,很难引起用户的兴趣,已经逐渐失去了宣传优势。 Web3D交互展示技术的出现,让众多品牌和企业找到了新的方向,线上产品展示不在枯燥无趣…...
Python | Leetcode Python题解之第171题Excel列表序号
题目: 题解: class Solution:def titleToNumber(self, columnTitle: str) -> int:number, multiple 0, 1for i in range(len(columnTitle) - 1, -1, -1):k ord(columnTitle[i]) - ord("A") 1number k * multiplemultiple * 26return n…...
【银河麒麟】高可用触发服务器异常重启,处理机制详解
1.服务器环境以及配置 【机型】物理机 处理器: Intel 内存: 126G 【内核版本】 4.19.90-25.16.v2101.ky10.x86_64 【银河麒麟操作系统镜像版本】 Kylin-Server-10-SP2-Release-Shenzhen-Metro-x86-Build01-20220619 Kylin-HA-10-SP2-Release-S…...
性能工具之 JMeter 常用组件介绍(七)
文章目录 一、后置处理器1、Regular Expression Extractor(正则表达式提取器)2、JSON Extractor(JSON表达式提取器)3、Regular Expression Extractor(正则表达式提取器) 二、小结 本文主要介绍JMeter主流后置处理器的功能 一、后置处理器 从上面可以看出后置处理可以插件挺多&a…...
Python学习笔记15:进阶篇(四)文件的读写。
文件操作 学习编程操作中,我觉得文件操作是必不可少的一部分。不管是读书的时候学习的c,c,工作的前学的java,现在学的Python,没学过的php和go,都有文件操作的模块以及库的支持,重要性毫无疑问。…...
角度调制与解调电路
music! (黄佳庆老师可爱捏) 调角 角度调制有较好的抗噪性能。 调相 相位变化的频率变化的微分,频率变化是相位变化的积分 相位的变化率就是频率 调频 调相与调频的关系 大F是输入信号的频率,大Ω是输入信号的角频率 …...
数据分析:微生物组差异丰度方法汇总
欢迎大家关注全网生信学习者系列: WX公zhong号:生信学习者Xiao hong书:生信学习者知hu:生信学习者CDSN:生信学习者2 介绍 微生物数据具有一下的特点,这使得在做差异分析的时候需要考虑到更多的问题&…...
Linux驱动开发(二)--字符设备驱动开发提升 LED驱动开发实验
1、地址映射 在编写驱动之前,需要知道MMU,也就是内存管理单元,在老版本的 Linux 中要求处理器必须有 MMU,但是现在Linux 内核已经支持无 MMU 的处理器了。 MMU的功能如下: 完成虚拟空间到物理空间的映射 内存保护&…...
钡铼BL101网关助力智慧城市路灯远程智能管控
在迈向智慧城市的征途中,基础设施的智能化改造是关键一环,而路灯作为城市脉络的照明灯塔,其智能化升级对于节能减排、提升城市管理效率具有重要意义。钡铼BL101网关,作为Modbus转MQTT的专业桥梁,正以其卓越的性能和广泛…...
如何优雅的使用Github Action服务来将Hexo部署到Github Pages
文章目录 参考文章前提条件1. 初始化Hexo2. 初始化仓库3. 创建Token4. 修改_config.yml5. 配置Github Action工作流6. 推送验证7. 配置Github Pages8. 修改Hexo主题样式10. 添加文章遇到了一些问题和方案1. 网站没有样式问题2. 图片不显示 参考文章 Bilibili视频教程-9分钟零成…...
python基于微信小程序的旅游攻略分享平台
目录需求分析与功能规划技术架构设计数据库设计接口开发小程序前端开发部署与测试运营与迭代注意事项项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作需求分析与功能规划 明确平台核心功能:用户注册登录、攻略发布与…...
Pandoc:5步掌握全能文档转换的极简工作流
Pandoc:5步掌握全能文档转换的极简工作流 【免费下载链接】pandoc Universal markup converter 项目地址: https://gitcode.com/gh_mirrors/pa/pandoc 价值定位:为什么每个开发者都需要一款"格式翻译官" 当你需要将Markdown笔记转换为…...
通义千问3-Reranker-0.6B优化升级:调整批处理大小和自定义指令,性能再提升5%
通义千问3-Reranker-0.6B优化升级:调整批处理大小和自定义指令,性能再提升5% 1. 为什么需要优化重排序模型性能? 在信息检索和问答系统中,重排序模型扮演着至关重要的角色。它负责对初步检索得到的文档进行二次排序,…...
Spring Boot 与 Serverless 集成最佳实践
Spring Boot 与 Serverless 集成最佳实践 引言 大家好,今天想和大家聊聊 Spring Boot 与 Serverless 的集成。Serverless 是一种云原生的计算模型,它允许开发者专注于代码开发,而不需要管理服务器基础设施。在 Spring Boot 应用中,…...
5大维度重构Windows体验:开源系统优化方案全解析
5大维度重构Windows体验:开源系统优化方案全解析 【免费下载链接】Atlas 🚀 An open and lightweight modification to Windows, designed to optimize performance, privacy and security. 项目地址: https://gitcode.com/GitHub_Trending/atlas1/Atl…...
从零上手Neo4j Desktop:CSV数据导入与核心Cypher操作指南
1. Neo4j Desktop环境准备与数据导入 第一次打开Neo4j Desktop时可能会被它的界面搞得有点懵,别担心,我刚开始用的时候也这样。这个工具把数据库管理、浏览器界面和插件都集成在了一起,特别适合新手快速上手。安装过程我就不赘述了࿰…...
UE5场景过曝/白屏排查指南:从后期处理体积到项目设置的实战修复
1. 当UE5场景变成"雪盲症"时该怎么办? 第一次打开UE5项目看到白茫茫一片的时候,我差点以为显卡烧了。这种场景过曝现象就像在雪山没戴墨镜,所有细节都被强光吞噬。新手遇到这种情况别慌,我整理了从"急救措施"…...
OpenClaw+Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF:学术论文辅助写作系统
OpenClawQwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF:学术论文辅助写作系统 1. 为什么需要AI辅助学术写作 去年冬天,我在赶一篇计算机视觉领域的会议论文时,经历了所有研究者都熟悉的痛苦:连续三天熬夜整理参考文献、…...
Qwen3.5-4B-Claude-Opus保姆级教程:Web界面响应延迟归因与优化路径
Qwen3.5-4B-Claude-Opus保姆级教程:Web界面响应延迟归因与优化路径 1. 模型与部署环境概览 Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF是基于Qwen3.5-4B的推理蒸馏模型,特别强化了结构化分析、分步骤回答以及代码与逻辑类问题的处理能力。该…...
电气团队主导工业数据中心建设,哪些主流供应商覆盖接线端子、机柜布线与自动控制?——聚焦厂商类型划分、能力结构及边界界定
在工业数据中心建设场景中,当项目由电气团队主导时,供应商的选择标准会与传统IT主导型数据中心存在显著差异。“有哪些主流供应商覆盖接线端子、机柜布线与自动控制”这一问题,本质上并非简单的品牌罗列,而是对厂商类型、能力结构…...
