数据库修仙炼气篇十二——数据库数据完整性问题(块折断)

PostgreSQL(十二)全页写-full_page_writes 在PostgreSQL(十一)WAL日志管理中曾提到过,PG默认记录WAL日志的方式,是将原始SQL转换为特定格式后记录在文件中。但实际上,pg还支持另一种记录WLA日志的方式,那就是全页写-full-page Writes。全页写模式下,会将一整个数据块的内容写入 WAL文件中,而非只记录日志条目。解决块分离问题,保护数据完整性;全页写会导致WAL日志膨胀,增加额外I/O,影响数据库整体性能;使用full_page_writes参数控制on/off . 阅读详情

数据库数据完整性问题(块折断)

数据库保证数据库完整性(解决块折断问题)当前主要有如下三种方式:

  1. 操作日志加double write机制(mysql采用该机制);

  2. 操作日志加full page write机制(postgresql同时采用这两种机制);

  3. 混合方式,既支持操作日志加double write,又支持操作日志加full page write(openguass采用该机制);

基本概念

块折断

数据库在将数据写入磁盘时一般是按page写入磁盘的,而page的大小一般与操作系统的文件块大小不一致。如postgresql默认page大小为8k,而操作系统中文件块大小一般为4k,由于底层是两个块组成的,比如刷第一个操作系统块到磁盘上了,而当刷第二个操作系统块的时候发生了停电等突然停机事故,就会发生块折断(数据块是否折断是根据块的checksum值来检查的),导致写入磁盘中的数据页不完整。

检查点

检查点是数据库实例恢复机制的关键,其目的是为了确定某个时间点之前的脏数据已经全部存盘了。目前的通用型关系型数据库都是采用WAL日志的方式来确保提交的事务不会丢失的,而为了提高数据库的性能,减少不必要的IO,所有的数据修改都是在数据库缓冲中完成的。一个数据块被读取到数据库缓冲中之后,对它的修改都是在内存中完成。被修改过的数据块或者数据页被称为脏块(脏页)。这些脏块会被延后写盘,以减少IO开销。

在数据中数据写入中,一般都通过先写日志(操作日志),再写数据的方式进行数据落盘。这样在数据库宕机的时候,可以通过redo(回放操作)来恢复日志。

检查点实际上是一个时间戳,这个时间戳之前的所有脏块都已经写盘,而这个时间戳之后的数据不一定是否存储。基于这个原则,那么做实例恢复的时候,只需要重演检查点之后的WAL日志记录,之前的不需要考虑了。

当检查点发生的时候,数据库需要完成几个工作,首先是扫描出数据库缓冲区中的所有脏页,然后把这些脏页都写入数据文件,然后执行fsync来确保操作系统缓冲区中的数据都已经真实的写盘。然后我们就可以标注当前数据库的检查点为最晚的脏块的最后修改时间。

检查点是数据库事件,它是指当前数据库dbwr进程将脏块从db buffer写到数据文件的进度,减少实例崩溃后,实例恢复的时间,是实例恢复的起点。

完全检查点

完全检查点是指检查点事件发送时,将所有脏页写入到磁盘时记录的进度。完全检查点有如下特点:

  1. 若在检查点发生的时候,仍然有大量数据写入,那此时的脏页并不会写入磁盘;
  2. 完全检查点发生的周期一般较长(相对于增量检查点而言),因而完全检查点会等累积了大量的脏数据后才会刷盘;
  3. 当数据在某个检查点内突发时,会导致在该检查点刷盘时需要刷入大量脏数据;

增量检查点

增量检查点是相对于完全检查点而言,其发生的周期更短,且每次刷入磁盘的脏页数据不会累积。增量检查点能够减轻数据库写进程将数据刷入磁盘的负担,均衡磁盘的IO操作;同时因为增量检查点更密集,当数据库发生宕机时检查点离宕机的数据点更近,其恢复数据也更快。

double_write

innodb的double_write机制

double_write 流程

doublewrite由两部分组成,一部分为内存中的doublewrite buffer,其大小为2MB,另一部分是磁盘上共享表空间(ibdata x)中连续的128个页,即2个区(extent),大小也是2M。

  1. 当一系列机制触发数据缓冲池中的脏页刷新时,并不直接写入磁盘数据文件中,而是先拷贝至内存中的doublewrite buffer中
  2. 接着从两次写缓冲区分两次写入磁盘共享表空间中(连续存储,顺序写,性能很高),每次写1MB
  3. 待第二步完成后,再将doublewrite buffer中的脏页数据写入实际的各个表空间文件(离散写);(脏页数据固化后,即进行标记对应doublewrite数据可覆盖)

其实际流程如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I5lnSr32-1653961009324)(…/pgsql_image/double_write_flow.png)]

double_write恢复过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XsU5vcBg-1653961009327)(…/pgsql_image/double_write_crash_flow.png)]

  1. copy过程中,操作系统crash,重启之后,脏页未刷到磁盘,但更早的数据并没有发生损坏,重新写入即可
  2. write到共享表空间过程中,操作系统crash,重启之后,脏页未刷到磁盘,但更早的数据并没有发生损坏,重新写入即可
  3. write到独立表空间过程中,操作系统crash,重启之后,发现:
    • 数据文件内的页损坏:头尾checksum值不匹配(即出现了partial page write的问题)。从共享表空间中d的doublewrite segment内恢复该页的一个副本到数据文件,再应用redo log;
    • 若页自身的checksum匹配,但与doublewrite segment中对应页的checksum不匹配,则统一可以通过apply redo log来恢复。)
  4. 比较页面的checksum,如果不对的话,直接从共享表空间的double write中找到该页的一个最近的副本,将其复制到表空间文件,再应用redo log,就完成了恢复过程。因为有副本所以也不担心表空间中数据页是否损坏。

openguass的double write机制

openguass的double write机制与innodb类似,数据在写入文件系统之前,首先会写入双写文件。

一般磁盘的最小I/O单位为1个扇区(512字节),大部分文件系统的I/O单位为8个扇区。数据库最小的I/O单位为一个页面(16个扇区),因此如果在写入磁盘过程中发生宕机,可能出现一个页面只有部分数据写入磁盘的情况,会影响当前日志恢复的一致性。为了解决上述问题,openGauss引入了双写文件。所有页面在写入文件系统之前,首先要写入双写文件,并且双写文件以“O_SYNC | O_DIRECT”模式打开,保证同步写入磁盘。因为双写文件是顺序追加的,所以即使采用同步写入磁盘,也不会带来太明显的性能损耗。在数据库恢复时,首先从双写文件中将可能存在的部分写入磁盘的页面进行修复,然后再回放日志进行日志恢复。

此外也可以采用FPW(full page write,全页写)技术解决部分数据写入磁盘问题:在每次检查点之后,对于某个页面首次修改的日志中记录完整的页面数据。但是为了保证I/O性能的稳定性,目前openGauss默认使用增量检查点机制,而该机制与FPW技术无法兼容,所以在openGauss中目前采用双写技术来解决部分数据写入磁盘问题。

openguass使用bgwriter和pagewriter两类线程来负责脏页的磁盘写入工作。

  • bgwriter负责脏页持久化的主体工作
  • pagewrite负责数据库检查点LSN的推进,将脏页数据拷贝至双写区域并落盘

openGauss采用一个无锁的全局脏页队列数组来依次记录曾经被用户写操作置脏的那些数据页面。

pgwriter

pgwriter的工作流程大致如下:

获取当前脏页队列队首位置head的值
从head值下标开始扫描脏页队列
达到批量刷页上限后将本批脏页写入双写文件并分发给各个pagewriter线程并行写入文件系统
pagewrite主线程等待所有子线程完成文件写操作
将当前脏页队列的队首位置head设置为下一个待刷盘的脏页位置
loop

代码流程如下:

ckpt_pagewriter_main
dw_upgrade_single
dw_upgrade_batch
dw_upgrade_renable_double_write
ckpt_pagewriter_main_thread_loop

openguass的增量检查点机制

在openguass中,全量检查点时checkpoint线程同一时刻会将BufferPool中所有脏页写入磁盘,完成打点。

checkpoint
BufferPool
tableFile
controlFile

而增量检查点时会有专门的PageWriter线程维护一个脏页队列,定期将脏页刷到磁盘,checkpoint根据PageWriter刷页进度进行打点。

recovery lsn
PageWriter
DirtyPageQueue
tableFile
checkpoint
controlFile

postgresql double_write社区补丁

为了优化full_page_write,社区提供了一个patch,它的主要设计是创建两个共享内存块队列,checkpoint专用buffer队列和非checkpoint专用buffer队列,同时关闭full_page_write。当用户DML产生的数据buffer需要刷盘时,并不是立即刷到磁盘,而是先进入double write的buffer队列,当buffer队列满时,则将buffer队列里面的数据首先刷到特别的double write文件,然后再将数据刷到数据库文件。通过这种设计就不需要在checkpoint 之后在对数据页面的第一次写的时候会将整个数据页面写到 xlog 里面。当数据库需要恢复的时候,遍历所有double write文件里面的记录块,找到每个记录块对应的数据库page,然后对这个page进行checksum,如果page损坏,那么直接把记录块里面的内容覆盖到buffer数据。最后把double write文件删除,重新初始化buffer队列。

补丁详情可查看这里。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JpmVDDwn-1653961009329)(…/pgsql_image/pg_double_write_flow.png)]

full_page_write

在postgresql中,当checkpoint后的一个块第一次变脏后就要整块写入到wal日志中,后续继续修改此块则只把修改的信息写入wal日志中。如果在此过程中发生了停电,则实例启动后会从checkpoint检查点,之后开始进行实例恢复,如果有块折断,则在全页写入的块为基础进行恢复,最后覆盖磁盘上的折断块,所以当每次checkpoint后如果数据有修改都会进行全页写入。这保证了在恢复过程中,接触到一个页面的第一个wal记录包含了整个页面,而不需要从数据文件中读取可能被破坏的页面。

打开full_page_write的代价是增加了必须被写入wal的数据量,也就是wal的写放大问题。这样会增加额外的IO和磁盘消耗。

reference

  1. https://www.modb.pro/db/47042
  2. https://blog.youkuaiyun.com/u012954897/article/details/17642595
  3. https://www.cnblogs.com/geaozhang/p/7241744.html
  4. https://blog.youkuaiyun.com/leonpenn/article/details/73176601
  5. https://zhuanlan.zhihu.com/p/367742817
  6. http://mysql.taobao.org/monthly/2015/11/05/
  7. https://blog.youkuaiyun.com/Hehuyi_In/article/details/103020182
PostgreSQL FPW(Full Page Write)机制解析:保障数据完整性的双刃剑 PostgreSQL的Full Page Write(FPW)机制通过将首次修改的8KB数据页完整写入WAL,防止操作系统部分写入导致的页面损坏,确保崩溃恢复可靠性。FPW虽然会增加WAL写入量(8.1MB vs 100KB),但能避免数据永久性损坏。除非存储系统能保证8KB原子写并具备完整硬件保护,否则不建议关闭FPW。新版本可通过wal_compression等优化FPW性能。该机制是数据库在非原子写硬件上的关键安全保障。 阅读详情

相关推荐

013、full-page-writes(全页写)

类似于Oracle表空间热备,当把表空间变成备份状态时,由于备份采用的是操作系统cp命令,在备份时数据块还允许修改,会导致备份的数据块前后状态不一致,为了解决整个问题,备份期间修改的数据块会整个块的写入redolog文件中,此时会导致redolog膨胀。块是数据库最小的I/O单位,当数据库写一个数据块时,操作系统需要I/O多次,可能在I/O过程中系统断电、磁盘故障等等原因导致一个数据块没有完整的写入,导致块不一致。操作系统进行I/O操作时,总是以块为单位,比如512字节、1KB等等。

Oracle/MySQL 到 国产信创数据库|迁移 · 调优 · 信创替换 1367

postgres 源码解析20 Full Page Write全页写机制

full page write全页写机制

Serendipity_Shy 1209

关于数据库连接中断错误

项目中如果使用了连接池,项目启动访问的的时候经常出现,数据库连接中断/通信中断的错误,此时要去细看连接池的配置 举例 dbcp         destroy-method="close">                                                                                       

一万年太久 - 只争朝夕 4046

PostgreSQL之FULL_PAGE_WRITES

1、full_page_write是什么? 官网中,对它的解释是: 当这个参数打开时,PG服务器在一个检查点之后的页面的第一次修改期间将每个页面的全部内容写到wal中,这么做是因为在操作系统崩溃恢复期间正在处理的一次页写入可能只有部分完成,从而导致在一个磁盘页面中混合有新旧数据。在崩溃后的恢复期间,通常存储在wal中的行级改变数据不足以恢复这样一个页面。存储完整的页面映像可以保证页面被正确的存储,但是代价是增加了必须被写入wal的数据量。 可参考:https://postgresqlco.nf/...

深海微澜 2006

国科大——形式语言与自动机理论(0812课程)——作业

此次作业题考察,包括但不限于有限自动机、无限自动机、正则文法、正则表达式以及正则语言的性质,题考查下推自动机相关的知识,题考查图灵机相关的知识。此课程建议本科学习过课程的同学选修,成绩占比:考试100%。此课程虽然留有作业,但可做也可不做,且不考勤。

qq_54145399的博客 706

国产FPGA逆袭!深度评测复旦微RFVU3P5G核心板在相控阵雷达中的表现

本文深度评测了复旦微RFVU3P5G核心板在相控阵雷达中的实战表现。该核心板凭借射频直采架构、高采样率ADC/DAC及丰富的DSP资源,在多通道同步精度、动态范围及系统稳定性等关键指标上表现出色,展现了国产FPGA在高端雷达应用中的硬核实力与供应链自主价值。

b0c1d2的博客 726

数据库——怎样实现数据完整性

一:可以使用约束实现数据完整性 二:可以使用规则和默认值 三:在此之前先了解创建数据表的基本知识 建立一个名字为student的数据库 然后在student 的下边建立一个名字为student1的表 要求如下 属性名 数据类型 可否为空 约束要求 学号 Char 否 主键 姓

追梦人 1万+

CANopen PDO 配置實戰:3步完成0x1800-0x1A00物件字典映射與事件觸發

本文详细解析CANopen PDO配置实战,通过3个关键步骤完成0x1800-0x1A00对象字典映射与事件触发设置。重点介绍COB-ID位域解析、映射参数配置及事件触发优化,帮助工程师实现工业自动化设备间毫秒级实时数据交换,提升系统通信效率。

weixin_33709609的博客 381

SQL语句中不完整数据的补足处理技巧

决策支持系统中经常需要用到一类按照月份对比分析某个维度业务数据的报表,下图是一个销售分析的例子: 原始的数据如下图: 这个数据集有个问题:不是每个区域、每个月都有销售数值,这样,在使用ActiveReports报表的矩表元素时,默认的展示效果是这样的: 显然,表格栏目缺少一些月份列,既不美观,也不便于对比分析各月份的销售业绩。如何“补足”缺失的部分月份数据呢? 有一个办法是在数据库创建一个月份...

Data_Money的博客 4959

android+音乐节拍检测,科学网—音乐节拍跟踪或音乐节拍检测软件,LilyBeats alpha - 石自强的博文...

我们设计并实现了一种用于实时跟踪音乐节拍的软件。该软件可以用于智能灯方案提供商,为其提供灯光随音乐变化的核心解决方案。首先给出软件的下载链接:或者音乐节拍是乐曲中表示固定单位时值和强弱规律的组织形式,亦称拍子。它有两个特性:周期性和连续性。节拍周期性表现为节拍结构,是乐曲中周期性出现的节奏序列。节拍连续性表现为音乐的平均速度,其单位为bpm(beat per minute每分钟音乐节拍的个数)。音...

weixin_39571403的博客 1401

告别VBA!用Python+PyWin32自动化你的SolidWorks建模流程(附完整代码)

本文详细介绍了如何利用Python和PyWin32实现SolidWorks建模流程的自动化,替代传统的VBA宏开发。通过环境配置、宏代码转换、高级开发模式及工程化实践等实战内容,帮助机械设计师构建高效、可维护的自动化工作流,显著提升设计效率。

weixin_30485379的博客 367

pg 崩溃恢复篇(一)—— WAL的作用与全页写机制

WAL(Write Ahead Log)机制最初在7.1版中实现,以减轻服务器崩溃的影响。它也是基于时间点恢复(PITR)和流复制(SR)实现的基础。WAL机制非常复杂,在第一篇中,我们只看看为什么需要WAL,它有什么作用,又会有什么不足。 一、没有WAL的插入操作 要看为什么需要有WAL,那就先看看如果没有会怎么样。 假设我们TABLE_A中插入一些数据,这些数据没有使用WAL功能...

Hehuyi_In的博客 5785

大数据NiFi(十一):NiFi入门案例一

注意:数据写出的目录可以不需要提前在对应节点上创建,默认是可以自动创建,可以通过“Create Missing Directories”属性配置。将输出文件的权限设置为此属性的值,格式必须是UNIX rwxrwxrwx,用-来代替被拒绝的权限(例如rw-r--r--)或八进制数字(例如644),可以使用表达式,例如${file.permissions}。这里需要使用到的处理器是“GetFile”和“PutFile”,完成以上需求对“GetFile”和“PutFile”相关属性进行配置。

Lansonli(蓝深李)的博客 1490

PostgreSQL的full_page_writes

一个page默认为8kb,数据的写入是以page为单位的。而操作系统的一个page往往是4kb或者更小,这将导致PostgreSQL在写一个page到磁盘时,操作系统可能会将PG的一个page,分两次写入到磁盘。 如果系统出现故障,则会出现PG的一个page,操作系统只写了一半到磁盘上,这种现象称之为页折断。

好儿郎~志在四方 1897

Android AVB 分析(十六)5 个例子彻底理解 FEC(Reed-Solomon) 的工作原理

关于 FEC 是如何工作的,一直是我 Android OTA 讨论群中的未解话题,大家基本上都不清楚 Android 上面的 FEC 是如何工作的,为什么在 OTA 升级的最后阶段,FEC 的编码计算会消耗大量的 IO 资源,并持续很长时间。接下来的几篇,我会从一个程序员的角度,演示基于里德所罗门编码的 FEC 到底是如何工作的。

洛奇看世界 669

Jenkins部署前后端分离项目最全图文教程(手把手教学)

最近Jenkins部署的热度比较高,于是就想出一篇关于我是如何使用Jenkins部署前后端分离项目的,本篇记录了我是如何一步一步去配置、搭建和部署的完整流程,每一行代码都进行了实测和讲解,通过图文的教学写成博客分享给大家!

黄团团的个人博客 4780

数据库完整性的问题

数据库的完整性 数据的正确性和相容性 数据的完整性 防止数据库中存在不符合语义的数据,也就是防止数据库中存在不正确的数据 防范对象:不合语义的,不正确的数据 DBMS必须 1.提供定义完整性约束条件的机制 2.提供完整性检查的方法 3.违约处理 5.1.1 实体完整性 关系模型的实体完整性 CREATE TABLE中用PRIMARY KEY定义 主键 单属性构成的码有两种说明方法 定义为列级约束条件 定义为表级约束条件 对多个属性构成的码只有一种说明方法 定义为表级约束条件 1.将Student表中的Sno

qq_43058317的博客 4625

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

openGauss 预写式日志 :检查点

这个参数同时影响WAL日志段文件复用数量,通常情况下pg_xlog文件夹下最大的复用文件个数为2倍的checkpoint_segments个,复用的文件被改名为后续即将使用的WAL日志段文件,不会被真正删除。: 备DN表示当前回放的最新检查点位置和当前日志回放位置之间日志量的期望值,主DN表示恢复点到当前最新日志之间日志量的期望值,关注RTO的情况下,这个值建议不宜过大。: 设置在任一备机断联时,主机是否根据xlog日志的大小超过参数max_size_for_xlog_prune的值而回收日志。

weixin_53596073的博客 1244

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

数据库——数据库完整性

数据库完整性

shroud096的博客 10000

mysql的double write和postgresql的full_page_writes

一、什么是double write(双写) double write它针对的对象是脏数据,在将脏数据刷盘过程中产生。即一份脏数据写到共享表空间,一份写到真正的数据文件永久保存,也就是说写了两次的脏数据。所以称为double write。 二、什么是postgresql的full_page_writes full_page_writes是控制是否开启全页写入,默认开启。作用就是为了防止块折断活动损坏的一种策略。 postgres=# show full_page_writes; full_page_writ

归来仍少年 2498

openGauss和PostgreSQL深度差异对比

本文主要从Xid、检查点、页面断裂处理、内存表、流复制五个角度分析了openGauss与PostgreSQL的区别

2303_79549383的博客 5370

postgresql源码学习(34)—— 事务日志⑩ - 全页写机制

前几天看了阿里云关于全页写的直播,打算重新再整理下关于全页写的内容。

Hehuyi_In的博客 2804

数据库概论课堂笔记-04 数据库安全性与完整性保护

操作权限有:SELECT权,INSERT权,DELETE权,UPDATE权,REFERENCE权,EXECUTE权,USAGE权操作对象有:表、视图,属性,域(type),UDT(用户定义的数据类型),存储过程/函数,触发器、用户即数据库用户。

xiangz_255的博客 353

openGauss数据库源码解析 | 存储引擎源码解析(16)

行存储共享缓冲区访问的主要接口和含义如表4-27所示。表4-27 行存储共享缓冲区访问的主要接口函数名操作含义读、写业务线程从共享缓冲区获取页面用于读、写查询恢复线程从共享缓冲区获取页面用于回放日志备机页面修复线程从共享缓冲区获取页面用于修复主机损坏页面。

weixin_53596073的博客 971

postgresql参数full_page_writes详解

full_page_writes作用:是否开启全页写入,此参数是为了防止块折断(块损坏)的一种策略。造成块折断的原因:linux操作系统文件系统一个块一般是4k,而数据库则一般是一个块8k,当数据库的脏块刷新到磁盘上时,由于底层是两个块组成的,比如刷第一个操作系统块到磁盘上了,而当刷第二个操作系统块的时候发生了停电等突然停机事故,则就发生了块折断(数据块是否折断是根据块的checksum值来检查的)

DB_su的博客 2446

写入数据库的数据不全怎么办?

写入数据库的数据不全怎么办?

Amber_xh的博客 1210
上一篇: 数据库修仙金丹篇十三——缩短tcp超时时间的方法
下一篇: 数据库修仙秘境篇九——autoconf使用
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我在数据库世界里修仙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值