PostgreSQL WAL 幂等性详解

1. WAL简介

WAL(Write-Ahead Logging)是PostgreSQL的核心机制之一。其基本理念是:在修改数据库数据页之前,必须先将这次修改操作写入到WAL日志中。
这确保了即使发生崩溃,数据库也可以根据WAL日志进行恢复。

恢复的核心流程就是不断**Replay(重做)**WAL记录,把数据库恢复到一致状态。

2. 为什么需要幂等性?

故障恢复可能发生在任意时刻,且可能反复进行。为了确保数据一致性,必须保证:

  • WAL重放(replay)是幂等的:即多次重做同样的WAL记录,最终结果与只做一次是一样的。
  • 防止重复执行逻辑修改,避免出现脏数据(如重复插入、更新错误等)。

没有幂等性,PostgreSQL的可靠性和数据完整性就无从谈起。

3. PostgreSQL 如何实现 WAL 的幂等性?

分情况讨论:

3.1 物理日志(Full Page Write, FPW)

  • 当首次修改某个page时,如果遇到检查点之后第一次修改,或者出现了部分写(partial write)风险时,PostgreSQL会将整个page的物理镜像写入WAL。
  • 恢复时直接拷贝覆盖,无需考虑page上的状态。
  • 因为是整页覆盖,所以天然是幂等的。重复应用多次,结果不会变。

注:FPW是恢复的"大杀器",确保即使发生中间页损坏,也能恢复。

3.2 逻辑日志(Insert/Update/Delete操作记录)

  • 日志并不是直接记录"修改了page的哪一块物理位置",而是记录在什么page上执行了什么逻辑操作。
  • 例如:在某个page上插入一条tuple "X",而不是"在page偏移offset=32的地方插入"。
  • 如果简单地无脑重做,恢复两遍就会出现重复记录。

为避免此问题,PostgreSQL每个page在物理结构中维护了一个字段:pd_lsn,即Page LSN。

  • 当一个page被修改时,它的pd_lsn被更新为当前WAL record的LSN。
  • 恢复时,每次要重放一个WAL record之前,PostgreSQL会先检查:
    只有当 WAL record 的 LSN > page 的 pd_lsn 时,才进行重做,否则跳过

3.3 流程示意图

恢复 -> 读取WAL record -> 找到要修改的Page ->

比较 (WAL record LSN vs Page pd_lsn)

   -> 如果 WAL LSN <= Page LSN, 说明已经做过,跳过

   -> 如果 WAL LSN > Page LSN, 执行修改,更新Page LSN

这种机制可以保证:即使崩溃后在同一个地方反复重做日志,也不会对数据造成破坏。

4. 实验验证 PostgreSQL WAL 幂等性

下面用一个小实验验证pg的WAL幂等性:

4.1 实验环境准备

initdb -D /tmp/pgwaltest

pg_ctl -D /tmp/pgwaltest -l logfile start

psql

4.2 创建表并插入数据

CREATE TABLE test_wal (id serial PRIMARY KEY, val text);

INSERT INTO test_wal(val) VALUES('first insert');

CHECKPOINT;  -- 强制生成检查点,防止混入无关WAL

这时test_wal表中有一条数据,系统生成了新的检查点。

4.3 查看Page LSN

PostgreSQL提供了扩展 pageinspect 来查看物理Page的信息。

安装并使用:

CREATE EXTENSION pageinspect;

-- 找出表的物理文件

SELECT relfilenode FROM pg_class WHERE relname = 'test_wal';

-- 假设relfilenode是 16384

-- 查看page的LSN(第一页)

SELECT * FROM page_header(get_raw_page('test_wal', 0));

会返回:

lsn  | checksum | flags | lower | upper | special | pagesize | version | prune_xid

------+----------+-------+-------+-------+---------+----------+---------+-----------

0/1500720 |    ...   |       |   ... |   ... |    ...   |    8192  |    4    |    ...

记录下当前Page的LSN,比如是0/1500720。

4.4 模拟崩溃后重复恢复

手动重放WAL当然很复杂,但可以模拟:

  1. 手动修改page LSN,使其低于WAL日志的LSN;
  2. 重启数据库,触发recovery。

不过这样太麻烦,我们可以简单理解为:

  • 如果page LSN已经大于WAL record的LSN,那么即使WAL被Replay,也不会改动页面。

4.5 直接实验重复写入一条相同数据:

-- 模拟意外重复插入

INSERT INTO test_wal(val) VALUES('first insert');

-- 应该报错,因为违反唯一约束(id列),而不是"无脑"插两遍

说明PostgreSQL在逻辑层也有幂等保护,比如:

  • 主键/唯一约束
  • page LSN校验
  • XID(事务ID)检测

5. 注意事项和补充

  • FPW(Full Page Writes)必须打开,否则遇到partial write会导致崩溃后无法恢复。
  • 极端情况下,日志丢失(比如WAL损坏)仍然会导致恢复失败,因此建议使用流复制+归档备份双保险。
  • WAL日志管理工具(如pg_waldump)可以辅助查看日志内容,帮助理解。

示例:

pg_waldump /tmp/pgwaltest/pg_wal/

可以看到诸如:

rmgr: Heap        len (rec/tot):  54/ 54, tx: 490, lsn: 0/01500280, desc: INSERT off 2

显示了一个Heap表上的insert动作及其LSN。

总结

  • PostgreSQL WAL重放过程是严格幂等的。
  • 物理日志天然幂等,逻辑日志依赖于Page LSN机制保证幂等。
  • 实现细节涵盖了page级别和事务级别的双重校验。
  • 实验验证了幂等机制的有效性。

PostgreSQL通过这些设计,确保即使在最坏情况下崩溃恢复,也能保证数据一致性和正确性。

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

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

相关文章

git提交规范记录,常见的提交类型及模板、示例

Git提交规范是一种约定俗成的提交信息编写标准&#xff0c;旨在使代码仓库的提交历史更加清晰、可读和有组织。以下是常见的Git提交类型及其对应的提交模板&#xff1a; 提交信息的基本结构 一个标准的Git提交信息通常包含以下三个主要部分&#xff1a; Header‌&#xff1a;描…

FastAPI系列06:FastAPI响应(Response)

FastAPI响应&#xff08;Response&#xff09; 1、Response入门2、Response基本操作设置响应体&#xff08;返回数据&#xff09;设置状态码设置响应头设置 Cookies 3、响应模型 response_model4、响应类型 response_classResponse派生类自定义response_class 在“FastAPI系列0…

每日一题(小白)模拟娱乐篇33

首先&#xff0c;理解题意是十分重要的&#xff0c;我们是要求最短路径&#xff0c;这道题可以用dfs&#xff0c;但是题目给出的数据是有规律的&#xff0c;我们可以尝试模拟的过程使用简单的方法做出来。每隔w数字就会向下转向&#xff0c;就比如题目上示例的w6&#xff0c;无…

哈希封装unordered_map和unordered_set的模拟实现

文章目录 &#xff08;一&#xff09;认识unordered_map和unordered_set&#xff08;二&#xff09;模拟实现unordered_map和unordered_set2.1 实现出复用哈希表的框架2.2 迭代器iterator的实现思路分析2.3 unordered_map支持[] &#xff08;三&#xff09;结束语 &#xff08;…

Java学习-Java基础

1.重写与重载的区别 重写发生在父子类之间,重载发生在同类之间构造方法不能重写,只能重载重写的方法返回值,参数列表,方法名必须相同重载的方法名相同,参数列表必须不同重写的方法的访问权限不能比父类方法的访问权限更低 2.接口和抽象类的区别 接口是interface,抽象类是abs…

BG开发者日志0427:故事的起点

1、4月26日晚上&#xff0c;BG项目的gameplay部分开发完毕&#xff0c;后续是细节以及试玩版优化。 开发重心转移到story部分&#xff0c;目前刚开始&#xff0c; 确切地说以前是长期搁置状态&#xff0c;因为过去的四个月中gameplay部分优先开发。 --- 2、BG这个项目的起点…

头歌实训之游标触发器

&#x1f31f; 各位看官好&#xff0c;我是maomi_9526&#xff01; &#x1f30d; 种一棵树最好是十年前&#xff0c;其次是现在&#xff01; &#x1f680; 今天来学习C语言的相关知识。 &#x1f44d; 如果觉得这篇文章有帮助&#xff0c;欢迎您一键三连&#xff0c;分享给更…

【深度学习】多头注意力机制的实现|pytorch

博主简介&#xff1a;努力学习的22级计算机科学与技术本科生一枚&#x1f338;博主主页&#xff1a; Yaoyao2024往期回顾&#xff1a;【深度学习】注意力机制| 基于“上下文”进行编码,用更聪明的矩阵乘法替代笨重的全连接每日一言&#x1f33c;: 路漫漫其修远兮&#xff0c;吾…

java16

1.API续集 可以导入别人写好的clone的jar包 注意&#xff1a;方法要有调用者&#xff0c;如果调用者是null就会报错 2.如何导入别人写好的jar包 复制jar包然后粘贴在lib里面&#xff0c;然后右键点击jar包再点击下面的add 3.关于打印java中的引用数据类型

PostgreSQL的扩展 credcheck

PostgreSQL的扩展 credcheck credcheck 是 PostgreSQL 的一个安全扩展&#xff0c;专门用于强制实施密码策略和凭证检查&#xff0c;特别适合需要符合安全合规要求的数据库环境。 一、扩展概述 1. 主要功能 强制密码复杂度要求防止使用常见弱密码密码过期策略实施密码重复使…

MyBatis中的@Param注解-如何传入多个不同类型的参数

mybatis中参数识别规则 默认情况下,MyBatis 会按照参数位置自动分配名称:param1, param2, param3, ...或者 arg0, arg1。 // Mapper 接口方法 User getUserByIdAndName(Integer id, String name); 以上接口在XML中只能通过param1或者arg0这样的方式来引用,可读性差。 &l…

DIFY教程第一集:安装Dify配置环境

一、Dify的介绍 https://dify.ai/ Dify 是一款创新的智能生活助手应用&#xff0c;旨在为您提供便捷、高效的服务。通过人工智能技术&#xff0c; Dify 可以实现语音 助手、智能家居控制、日程管理等功能&#xff0c;助您轻松应对生活琐事&#xff0c;享受智慧生活。简约的…

5、Rag基础:RAG 专题

RAG 简介 什么是检索增强生成? 检索增强生成(RAG)是指对大型语言模型输出进行优化,使其能够在生成响应之前引用训练数据来源之外的权威知识库。大型语言模型(LLM)用海量数据进行训练,使用数十亿个参数为回答问题、翻译语言和完成句子等任务生成原始输出。在 LLM 本就强…

GAMES202-高质量实时渲染(homework1)

目录 Homework1shadow MapPCF(Percentage Closer Filter)PCSS(Percentage Closer Soft Shadow) GitHub主页&#xff1a;https://github.com/sdpyy1 作业实现:https://github.com/sdpyy1/CppLearn/tree/main/games202 Homework1 shadow Map 首先需要完成MVP矩阵的构造&#xf…

JDK(Ubuntu 18.04.6 LTS)安装笔记

一、前言 本文与【MySQL 8&#xff08;Ubuntu 18.04.6 LTS&#xff09;安装笔记】同批次&#xff1a;先搭建数据库&#xff0c;再安装JDK&#xff0c;后面肯定就是部署Web应用&#xff1a;典型的单机部署。“麻雀虽小五脏俱全”&#xff0c;善始善终&#xff0c;还是记下来吧。…

软件测试之接口测试常见面试题

一、什么是(软件)接口测试? 接口测试&#xff1a;是测试系统组件间接口的一种测试方法 接口测试的重点&#xff1a;检查数据的交换&#xff0c;数据传递的正确性&#xff0c;以及接口间的逻辑依赖关系 接口测试的意义&#xff1a;在较早期开展&#xff0c;在软件开发的同时…

Lua 第11部分 小插曲:出现频率最高的单词

在本章中&#xff0c;我们要开发一个读取并输出一段文本中出现频率最高的单词的程序。像之前的小插曲一样&#xff0c;本章的程序也十分简单但是也使用了诸如迭代器和匿名函数这样的高级特性。 该程序的主要数据结构是一个记录文本中出现的每一个单词及其出现次数之间关系的表。…

软件项目进度管理活动详解

目录 1. 活动定义&#xff08;Activity Definition&#xff09; 2. 活动排序&#xff08;Activity Sequencing&#xff09; 3. 活动资源估算&#xff08;Activity Resource Estimating&#xff09; 4. 活动历时估算&#xff08;Activity Duration Estimating&#xff09; …

docker 国内源和常用命令

Ubuntu | Docker Docs 参考docker官方安装docker # Add Dockers official GPG key: sudo apt-get update sudo apt-get install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt…

身份与访问管理(IAM):零信任架构下的认证授权技术与实战

身份与访问管理&#xff08;IAM&#xff09;&#xff1a;零信任架构下的认证授权技术与实战 在网络安全防御体系中&#xff0c;身份与访问管理&#xff08;Identity and Access Management, IAM&#xff09;是守护数字资产的“数字门禁系统”。随着远程办公和多云架构的普及&a…