pg_rewind实现原理简单分析

pg_rewind的功能是在主备切换后回退旧主库上多余的事务变更,以便可以作为新主的备机和新主建立复制关系。通过pg_rewind可以在故障切换后快速恢复旧主,避免整库重建。对于大库,整库重建会很耗时间。

如何识别旧主上多余的变更?

这就用到了PostgreSQL独有的时间线技术,数据库实例的初始时间线是1。以后每次主备切换时,需要提升备库为新主。提升操作会将新主的时间线加1,并且会记录提升时间线的WAL位置(LSN)。这个LSN位点我们称其为新主旧主在时间线上的分叉点。

我们只要扫描旧主上在分叉点之后的WAL记录,就能找到旧主上所有多余的变更。

如何回退旧主上多余的变更?

可能有人会想到可以通过解析分叉点以后的WAL,生成undo SQL,再逆序执行undo SQL实现事务回退。这也是mysql上常用的实现方式。 PG同样也有walminer插件可以支持WAL到undo SQL的解析。但是,这种方式存在很多限制,数据一致性也难以保证。

pg_rewind使用的是不同的方式,过程概述如下

  1. 解析旧主上分叉点后的WAL,记录这些事务修改了哪些数据块
  2. 对数据文件以外的文件,直接从新主上拉取后覆盖旧主上的文件
  3. 对于数据文件,只从新主拉取被旧主修改了的数据块,并覆盖旧主数据文件中对应的数据块
  4. 从新主上拉取最新的WAL,覆盖旧主的WAL
  5. 把旧主改成恢复模式,恢复的起点则设置为分叉点前的最近一次checkpoint
  6. 启动旧主,旧主进入宕机恢复过程,旧主应用完从新主拷贝来的所有WAL后,数据就和新主一致了。

如何保证主备一致?

分叉点之后,新主和旧主上可能有各种各样的变更。除了常规的数据的增删改,还有truncate,表结构变更,表的DROP和CREATE,数据库参数配置变更等等。如何保证pg_rewind之后这些都能一致呢?

下面我们重点看一下pg_rewind对数据文件的拷贝处理。

  1. 通过比较target和source节点的数据目录,构建filemap

    filemap中对每个文件记录了不同的处理方式(即action),对于数据文件,如下

    • 仅存在于新主:FILE_ACTION_COPY
    • 仅存在于旧主:FILE_ACTION_REMOVE
    • 新主文件size>旧主:FILE_ACTION_COPY_TAIL
    • 新主文件size<旧主:FILE_ACTION_TRUNCATE
    • 新主文件size=旧主:FILE_ACTION_NONE
  2. 读取旧主本地WAL,获取并记录影响的数据块到filemap中对应的file_entry中的pagemap

    pagemap属于块级别的拷贝。为了避免文件级别的拷贝做重复的事情,提取影响的块号是做了一些过滤,具体如下:

    • FILE_ACTION_NONE:只记录小于等于新主size的块
    • FILE_ACTION_TRUNCATE:只记录小于等于新主size的块
    • FILE_ACTION_COPY_TAIL:只记录小于等于旧主size的块
    • 其他:不记录
  3. 遍历filemap,对其中每个file_entry,从新主拷贝必要的数据

    • 从新主拷贝pagemap中记录的块覆盖旧主
    • 根据action,执行不同的文件拷贝操作
      • FILE_ACTION_NONE:无需处理
      • FILE_ACTION_COPY:从新主拷贝数据,只拷贝到生成action时看到的新主上的size
      • FILE_ACTION_TRUNCATE:旧主truncate到新主的size
      • FILE_ACTION_COPY_TAIL:从新主拷贝尾部数据,即新主size超出旧主的部分
      • FILE_ACTION_CREATE:创建目录
      • FILE_ACTION_REMOVE:删除文件(或目录)

上面的过程汇总后如下:

  • 仅存在于新主(FILE_ACTION_COPY)
    • 从新主拷贝数据,只拷贝到生成action时看到的新主上的size
  • 仅存在于旧主(FILE_ACTION_REMOVE)
    • 删除文件
  • 新主文件 size > 旧主(FILE_ACTION_COPY_TAIL)
    • 对偏移位置小于等于旧主文件 size 的块,从新主拷贝受旧主分叉后更新影响的块
    • 偏移位置为旧主文件 size ~ 新主文件 size 之间的块,从新主拷贝
  • 新主文件 size < 旧主(FILE_ACTION_TRUNCATE)
    • 对偏移位置小于等于新主文件 size 的块,从新主拷贝受旧主分叉后更新影响的块
    • 对偏移位置大于新主文件 size 的块,truncate 掉
  • 新主文件 size = 旧主(FILE_ACTION_NONE)
    • 对偏移位置小于等于新主文件 size 的块,从新主拷贝受旧主分叉后更新影响的块

针对上面的流程,现在回答几个关键的问题

pg_rewind拷贝数据时,新主还处于活动中,拷贝的这些数据块不在同一个事务一致点上,如何将不一致的数据状态变成一致的?

这里用到的技术,就是数据块最擅长的宕机恢复的技术。通过启动旧主后,回放WAL使数据库达到一致的状态。

我们以一个微观的数据块为例进行说明。

具体到某一个数据块,只有三种情况,我们分别讨论

  1. 需要从新主拷贝

    • 如果拷贝时发现新主上这个块所在的文件被删掉了,那么也会删掉旧主上的文件。

    • 如果拷贝时新主上这个块被 truncate 掉了,会忽略这个块的拷贝。

    • 如果拷贝时这个块正在被修改,可能导致pg_rewind读到了一个不一致的块。一半是修改前的,另一半是修改后的。

      这并没有关系,因为如果这个块被变更了,变更这个块的事务已经记录到WAL了,回放这个WAL时可以修复数据到一致状态。pg_rewind运行的前提条件时数据库必须开启 full_page_write,开启full_page_write后WAL中会记录每个checkpoint后第一次修改的page的完整镜像,宕机恢复时,使用这个镜像,就可以修复数据文件中损坏的数据块。

  2. 保留旧主

    • 如果后来新主上这个块变更了,回放WAL时自然可以追到一致的状态
  3. 需要从旧主删除

    • 如果后来新主上有新增了这个数据块,同样,回放WAL时自然可以追到一致的状态

如果一个表先被删了,之后又创建一个表结构不一样的同名的表,pg_rewind处理这个表时会不会有问题?

PostgreSQL中数据文件名是filenode,初始时它等于表的oid,当表被重写(比如执行truncate或vacuum full)后,会赋值为下一个oid。因此先后创建的同名表,它们对应的文件名是不一样的(MySQL采用表名作为数据文件名。虽然比较直观,但会有很多潜在的问题,比如特殊字符,PostgreSQL的filenode的方式要严谨得多)。

PostgreSQL回放WAL时如何保证可正常执行?

具体要回答几个问题

  1. 宕机恢复阶段,回放建表的WAL时,如果对应的文件已存在,结果如何?
  2. 宕机恢复阶段,回放删表的WAL时,如果对应的文件不存在,结果如何?
  3. 宕机恢复阶段,回放extend数据文件的WAL时,如果对应的块已存在,结果如何?
  4. 宕机恢复阶段,回放write数据文件的WAL时,如果对应的块或者文件不存在,结果如何?
  5. 宕机恢复阶段,回放truncate数据文件的WAL时,如果对应的块或者文件不存在,结果如何?

存储层的一些接口,已经考虑到REDO的使用场景,做了一些容错,支持幂等性。

  1. REDO中创建文件时,容忍文件已存在

    void
    mdcreate(SMgrRelation reln, ForkNumber forkNum, bool isRedo)
    {
    ...fd = PathNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);if (fd < 0){int			save_errno = errno;if (isRedo)fd = PathNameOpenFile(path, O_RDWR | PG_BINARY);
    ...
  2. 删除文件时,容忍文件不存在

    static void
    mdunlinkfork(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
    {
    ...ret = unlink(pcfile_path);if (ret < 0 && errno != ENOENT)ereport(WARNING,(errcode_for_file_access(),errmsg("could not remove file \"%s\": %m", pcfile_path)));
  3. REDO中打开文件时,都会带上 O_CREAT flag,文件不存在时会创建一个空的

    static MdfdVec *
    _mdfd_getseg(SMgrRelation reln, ForkNumber forknum, BlockNumber blkno,bool skipFsync, int behavior)
    {if ((behavior & EXTENSION_CREATE) ||(InRecovery && (behavior & EXTENSION_CREATE_RECOVERY))){...flags = O_CREAT;
    
  4. 读或写数据块时,可以 seek 到超出文件大小的位置

    void
    mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,char *buffer, bool skipFsync)
    {
    ...v = _mdfd_getseg(reln, forknum, blocknum, skipFsync,EXTENSION_FAIL | EXTENSION_CREATE_RECOVERY);
    ...nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ, seekpos, WAIT_EVENT_DATA_FILE_WRITE);
  5. REDO中 truncate 时,如果文件大小已小于 truncate 目标,无视

    void
    mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks)
    {
    ...curnblk = mdnblocks(reln, forknum);if (nblocks > curnblk){/* Bogus request ... but no complaint if InRecovery */if (InRecovery)return;
  6. 回放truncate记录时,先强制执行一次创建关系的操作

    void
    smgr_redo(XLogReaderState *record)
    {
    ...else if (info == XLOG_SMGR_TRUNCATE){.../** Forcibly create relation if it doesn't exist (which suggests that* it was dropped somewhere later in the WAL sequence).  As in* XLogReadBufferForRedo, we prefer to recreate the rel and replay the* log as best we can until the drop is seen.*/smgrcreate(reln, MAIN_FORKNUM, true);
    ...smgrtruncate(reln, forks, nforks, blocks);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/36868.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于51单片机的银行排队呼叫系统设计

一.硬件方案 本系统是以排队抽号顺序为核心&#xff0c;客户利用客户端抽号&#xff0c;工作人员利用叫号端叫号&#xff1b;通过显示器及时显示当前所叫号数&#xff0c;客户及时了解排队信息&#xff0c;通过合理的程序结构来执行排队抽号。电路主要由51单片机最小系统LCD12…

K8S Pod常见状态

这是自己所遇到 Pod 常见状态及可能原因&#xff0c;持续更新。 如有其他的错误状态&#xff0c;可私我更新 1. ImagePullBackOff 问题分析&#xff1a; 镜像拉取失败。 可能原因&#xff1a; 可能是网络问题导致&#xff0c;检查Pod所在节点是否能够正常访问网络; 镜…

Vue-cli项目及Element UI 环境搭建 保姆级教程

一、Vue-cli介绍及其作用 什么是Vue-cli手脚架 vue-cli 官方提供的一个脚手架&#xff0c;用于快速生成一个 vue 的项目模板&#xff1b;预先定义 好的目录结构及基础代码&#xff0c;就好比咱们在创建 Maven 项目时可以选择创建一个 骨架项目&#xff0c;这个骨架项目就是脚…

electron本地运行请求端口

本地运行&#xff1a; npm run electron:start 运行后项目请求地址为&#xff1a; http://localhost:5173/api/xxxx const {protocol } require(electron); app.commandLine.appendSwitch(--ignore-certificate-errors, true); // Scheme must be registered before the app…

手把手教你玩转AD9361数字调制解调系列(二) ----纯逻辑实现FSK信号的数字调制解调

因最近客户需求&#xff0c;用纯PL实现AD9361的数字信号调制解调&#xff0c;于是就把各种数字调制都在AD9361上都实现了一遍。优点就是&#xff1a;既可以在zynq系列上配置9361&#xff0c;也可以在纯FPGA系列配置9361。并且理解起来比较简单&#xff01;&#xff01;&#xf…

lidar3607.2 雷达点云数据处理软件功能介绍

LiDAR360 是北京数字绿土科技股份有限公司自主研发的点云后处理及行业应用软件。平台可处理 TB 级点云数据&#xff0c;并拥有 10 余种国际领先的点云处理及 AI 算法&#xff0c;推动激光雷达 的多行业应用。700 余项强大且灵活的功能&#xff0c;解决用户最后一公里的应用难题…

云仓是如何发展起来的?

1、电子商务的繁荣&#xff1a; 随着电商的兴起&#xff0c;对高效仓储和物流的需求越来越大。传统的仓储方式难以满足海量订单处理和快速配送的要求&#xff0c;因此需要一种更加灵活和高效的仓储解决方案。 ------------------------------------------------- 2、科技进步…

速盾:cdn动态加速上传

CDN&#xff08;Content Delivery Network&#xff0c;内容分发网络&#xff09;是一种通过在全球范围内分布的服务器群组来提供高速、可靠内容传递的技术。CDN在网络上广泛应用&#xff0c;可以加速网站中的静态内容和动态内容的传输&#xff0c;并提高用户的访问速度和体验。…

Nuxt 的路由结构系统(七)

基本路由配置 在 Nuxt.js 中&#xff0c;每个 .vue 文件在 pages/ 目录下都会自动成为一个路由。文件名决定了路由的路径。例如&#xff1a; pages/ |-- index.vue # 映射到根路径 / |-- about.vue # 映射到路径 /about |-- contact.vue # 映射到路径 /conta…

Git clone解释

git clone gitgithub.com:tancolo/MOOC.git 是一个 Git 命令&#xff0c;用于从远程 Git 仓库复制一个仓库到本地计算机。下面我将详细解释这个命令的各个部分及其作用&#xff1a; git clone&#xff1a; 这是一个 Git 命令&#xff0c;用于从远程仓库克隆&#xff08;复制&am…

罗盘复杂网络教程—3步轻松构建社团检测任务

作为复杂网络领域中重要的课题之一&#xff0c;社团检测有助于揭示网络中存在的功能性模块或群集&#xff0c;旨在于仅利用网络中蕴含的来识别模块&#xff0c;并可能进而识别它们的层次组织。社团检测在各个领域具有重要的应用&#xff0c;可以帮助深入理解复杂系统潜在的模式…

一键进阶ComfyUI!懂AI的设计师现在都在用的节点式Stable Diffusion

前言 _ 万字教程&#xff01;奶奶看了都会的 ComfyUI 入门教程 推荐阅读 一、川言川语 大家好&#xff0c;我是言川。 阅读文章 > ](https://www.uisdc.com/comfyui-3) 目前使用 Stable Diffusion 进行创作的工具主要有两个&#xff1a;WebUI 和 ComfyUI。而更晚出现的…

SceneXplain 图片叙事升级:如何让图片听得到

SceneXplain 是一个由多模态 AI 驱动的产品服务&#xff0c;它不仅 提供一流的图像和视频标注解决方案&#xff0c;还具备卓越的多模态视觉问答能力&#xff0c;为用户解锁视觉内容的全新维度。 在[《图像描述算法排位赛》中&#xff0c;我们探讨了图像描述&#xff08;Image …

GIS 已知当前经纬度,往东移动一公里,怎么计算移动后的经纬度

已知当前经纬度&#xff0c;往东移动一公里&#xff0c;怎么计算移动后的经纬度111km1 &#xff08;经纬度都适用&#xff09;不追求精度 1米等于0.00001

有兄弟对这类区域比较感兴趣,也引起我的好奇,我提取出来给大家看看

要说这类地区&#xff0c;亚洲泰国排第二估计没人敢说第一吧&#xff0c;所以我就提取泰国的数据给大家看看&#xff01; 如图&#xff1a;这些特殊服务地区主要集中在曼谷和芭提雅地区&#xff0c;芭提雅最多&#xff01;看来管理还是不错的&#xff0c;限制在一定范围&#x…

便携应急气象站设备—实时监测和记录气象数据

TH-BQX10便携应急气象站设备是一种高度集成、轻便易携的气象观测系统。它采用新型一体化结构设计&#xff0c;能够快速安装和拆卸&#xff0c;适用于各种复杂环境。通过集成多种气象传感器&#xff0c;该设备能够实时监测和记录温度、湿度、风向、风速、降雨量、气压等多种气象…

ruoyi-vue前后端分离版本使用心得

1.关于多数据源配置: 修改ruoyi-admin里的application-druid.yml&#xff1a; druid: # 主库数据源 master: url: jdbc:mysql://192.168.156.11:3306/ry-vue?useUnicodetrue&characterEncodingutf8&zeroDateTimeBehaviorcon…

AMEYA360:广和通发布LTE Cat.1 bis模组MC610-GL,赋能全球漫游追踪器

广和通LTE Cat.1 bis模组MC610-GL搭载展锐8910平台&#xff0c;覆盖全球主流LTE频段&#xff0c;下行峰值速率达10.3Mbps&#xff0c;上行速率达5.1Mbps&#xff0c;满足全球终端对4G速率连接的需求;同时支持LTE和GSM双模通信&#xff0c;便于用户灵活切换网络。在尺寸封装上&a…

开放式耳机怎么选?五大2024年口碑销量爆棚机型力荐!

作为一名数码测评up主&#xff0c;今天来测评市面上的开放式耳机。开放式耳机它的设计非常的新颖&#xff0c;不管是舒适的佩戴&#xff0c;还是可以边听音乐&#xff0c;边听到周围的声音&#xff0c;给人更加安全的听感体验。长时间佩戴&#xff0c;不仅舒适度进一步的提升&a…

【机器学习】高斯混合模型(Gaussian Mixture Models, GMM)深度解析

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 高斯混合模型&#xff08;Gaussian Mixture Models, GMM&#xff09;深度解析引…