Non-FPW开发实战

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS AI 助手,专业版
简介: 在阿里云开源的趋势下,如何做到FPW的开发。

分享人:吕海波(VAGE)   杭州美创科技内核专家

正文:本文从八方面介绍了FPW的开发实例。


一、为什么要对FPW动手:性能测试


1)性能影响对比,PostgreSQL Full Page Writes性能影响:


image.png

先对比下性能,左侧是打开FPW,右边是关掉FPW,这个跟IO是强相关的,如果IO很快速,FPW的影响就越小,如果使用的是土豪级NVM1设备,FPW的影响可能就没有了,甚至观察不到有任何的影响。平均FPW性能的影响可以达到百分之值30以上。


2)性能影响对比,MySQL Double Write性能影响


image.png

对比下MySQL,FPW的功能主要针对在页分裂或者不分写,页破碎等,对应到MySQL里面针对页分裂不分写的特性是Double Right双写。在同一台机器上测试一边打开双写,另一边关闭双写,同一台机器上使用同样的压测软件的,可以看到MySQL双写对性能的影响是微乎其微的。


二、为什么要对FPW动手


image.png

PG的FPW影响也很巨大,所以对它动手可以最大程度提升性能,代码改动比较少,实现逻辑也很简单。


三、了解FPW


1)页裂


image.png

那要在对它动手之前,特性是针对页裂的,针对不分写或页破碎,数据库的页一般是4k的倍数,8k 、16k等,数据库下发一次写,可能操作系统前4k写成功后4k写失败,这就导致不分写或者页分裂,在对它动手之前要先了解一下赠分裂,了解它对数据库的影响,数据库是怎么解决的。

image.png


2)页裂的模拟


image.png

我们去制造一个页分裂,走两步看看数据库是怎么处理页分裂的,然后再对它动手。

制造一个叶分裂也简单,突然中断电源,内存里就页分裂,不分写、页分裂、破碎页等情况,这种方式可以实现但有点粗暴。直接中断电源不能针对某一个固定的页,比如想把某个页制造成页分裂是做不到的。如果脏页多又突然断电,这种情况可控性就比较差。如要去针对某个表、普通表、原数据表,针对某个固定的页去制造一个页分裂,可以拦截系统调用,再去修改传入OS内核参数拦截系统调用。比如在Linux里面这个systemtap就能做到,我之前有过关于这个systemtae的很多分享,就是用它去观察PG、,MySQL等,也比较简单。

 

3)从MySQL开始


image.png

主要思想是用它拦截IO,然后把IO的大小改一下,比如让操作系统写8k,把8k拦截后改成4k,就让前4k写成功,后4k不写,这就是页分裂。这种数据一致性让性能提升很诱人,但是做不好数据就不一致就没用了,那就没有任何意义了。

我们先从MySQL数据库开始,可以都比一遍,多借鉴各个主流数据库的经验,再决定如何对FPW动手。制作MySQL的页分裂,就要先去做IO函数,如果打开的话,它使用异步IO,如果关掉的话,使用同步IO,我们使用同步IO做测试,因为今天时间比较紧张,异步测试会比较复杂,讲起来又耗时多,但是总体思路是一样的。


4)从MySQL开始


image.png

因为要拦截系统,所以要先找到IO函数。这是测试表就不详细说了。

image.png

我让目标行MySQL的块是16k,让行呢处在靠下的位置,第三个4k的地方MySQL空间,它是从上往下使用的。我插入200行,以第200行作为目标,到时我去更新这个第200行。当我更新这个第200行的时候,MySQL更新这个4k外,第一个4k也会变,因为第一个4k前面管理性信息,这样第一个4k也变了,第三4k也变了。

image.png

我让目标行MySQL的块是16k,让行处在靠下的位置,第三个4k的地方。MySQL空间是从上往下使用的。我插入200行,以第200行作为目标。

image.png

到时我去更新这个第200行。当我更新这个第200行的时候,MySQL更新这个4k外,第一个4k也会变,因为第一个4k前面管理性信息,这样第一个4k也变了,第三4k也变了。

image.png

这是测试语句,是一条update更新第200行,中间还有个脚本,脚本上面是一个探针,探针就像数据库的触发器一样,先去做输出,输出是把函数的一些信息接过来,上图是输出的这个结果,那我做一个update,触发了MySQL的写操作,触发把内存改小一点,如果内存太大, update知道脏页要先修改一些参数。

image.png

 

image.png

制造了脏页后,让MySQL尽快去写这个页,在这儿就能看到输出的结果了,这个28就是写目标表的IO,这个文件号28十进制就是40。在目录下就能找到表对应的文件号,在这里就不详细说了。

image.png

它还写了0*b号文件,0*b号文件是第一次写18000的六个页,也是双写,待会儿我要让双写、四号文、日志log redo都成功,后面几个写有UNDO、系统表、28号写都失败。

image.png

观察过IO后,生成一个脚本进行破坏,就是对指定的进行破坏,让redo、双写都成功。因为双写失败了,还要靠再去恢复,看双写是如何恢复的。

image.png

这是最终运行效果。先运行脚本,再去执行update,执行完之后,IO被触发了,查询后发现MySQL已经宕机了,因为发现IO报错了,所以就宕库了,就启动不了,因为它检测到有页被写坏了。因为涉及到数据一致性的特性,我做过大量测试。

image.png

动手之前要做大量准备工作,如果这个制造的坏页,是对用户表的话大部分都能启动成功的,如果涉及到UNDO、系统表,用双写去恢复成功的概率那就很低了。

image.png

总体看双写不能对所有的页分裂和不分写发挥想象中的作用,它只能针对部分页分裂。如果出现这样的问题怎么办?就是做备份恢复,就能解决Partial Writes。对MySQL来说,就是you may have to recover from a backup,就是要靠备份恢复。


五、业内标杆,Oracle的页分裂解决方案


image.png

虽然说在国内Oracle的形势有点日落西山了,但是技术上仍然有它的先进性。下面观察Oracle,看它的页分裂的解决方式,跟MySQL步骤一样。首先找到IO的函数做拦截,Oracle的IO函数打开IO的时候是submit,跟MySQL是一样的。

image.png

准备测试数据的时候就简单了,建个表插一行就行,因为的空间是倒着来的,你插一行它就在第二个4k,然后你更新着Oracle第二个4k目标行,第一个4k也会改,因为块头有管理性信息,修改完目标行后,需要手动触发检查点。Oracle写是比较延迟的,PG也是一样。手动触发检查点,再触发它的写操作,再拦截系统调用,把8k改成前4k成功后4k失败。

image.png

再去看Oracle的处理过程,先观察Oracle的操作有哪些。

image.png

然后观察Oracle的结果,除了对我的目标表外,它还写了 UNDO等,我把这些都破坏掉变成坏页。

image.png

脚本是这样的,最主要就是中间这一行,把它改成改成1000,因为2000是16进制的,16进制2000就892是,把它变成1000,只要一改Oracle,IO就会报错了。MySQL脚本还比较复杂,最终要让IO报错,不能让IO成功。

image.png

先让脚本跑起来, update是成功的,cmmit也是成功的,执行检查点时报错了,因为这个写是Oracle的核心进程,核心进程出错之后它就直接down了。

image.png

Down后看如何去恢复。启动到这个地方,报错没有启动成功。

image.png

从日志里可以看到很多信息,在Oracle的告警日志里,发现数据库上次是异常宕机了。

image.png

找到了一个恢复点,从日志redo的地方去恢复,叫7112号redo文件的1736号块,它要从这个地方去恢复。

image.png

PG里面也有类似的东西,它如何恢复起始点呢?对所有数据库来说,只要保证数据一致性,比如不能因为断电数据就完了,只要能做到这一点的数据库都要有redo,redo对它来说是日志流。Record跟脏块是一一对应的,而且Record的顺序就代表了脏块的顺序, Record1:在Record2前,那Record1对应的脏块比Record2对应的脏块更早变脏。Redo从某种意义上来说相当于一种时间,这所有数据库都差不多,MySQL和Oracle都以redo为准。

image.png

检查点位置对开发很有意义的,它定期去执行检查点,检查点就是写脏块,数据库都有这样类似的机制,比如说这次检查点开始时写了四个脏块,还剩四个脏块,其中四个块已经落盘了,还有四个没有落盘。

image.png

第五脏块在redo里对应的位置就叫检查点位置,这个检查点位置就是我们在告警日志里面看到的恢复的起始点,7112号块的1736,因为已经落盘成功了,在这个位置之前的脏块都是不需要恢复的。

image.png

它落盘成功后才会把检查点位置寄到控制文件里面,Oracle和PG都有这样的机制,也是在检查点完成后把位置记到控制文件里面,这个位置之前的脏块儿都已经落盘成功了,恢复时就从这个地方开始往后去redo恢复就可以了。

image.png

Oracle检测到这个日这个检查点位置之后,检测到有74k的redo,74k的redo对应24个块需要恢复。

image.png

在恢复的时候没恢复成功,数据库不对坏页修复。

image.png

页坏了后有redo,页坏的可能性千奇百怪,数据库不会以有涯随无涯,它要在以前完好的数据的基础上做恢复。MySQL的双写和PG的FPW都是需要时不时的做个备份,把完好的一致的数据做个备份,以备将来在这个基础上做恢复,数据库不去做修复只去做恢复。

image.png

Oracle遇到坏页、页分裂、不分写、页破碎,它是如何做的。Oracle依赖检查,只要能检查出来页有问题就可以了,检查出来让DBA做恢复,你不恢复成功数据库我不启动,如果数据库启动了,就代表你已经恢复成功了,它的数据是一致的。

为了尽快完成恢复,它提供了快恢复的功能,比如说32G的文件夹有8k坏了,MySQL怎么做呢?如果双写没有搞定,那把以前备份的文件就一个表一个文件把这个表给恢复过来, 32G数据全部来一遍,就会比较慢。

Oracle有块恢复功能,如果只有一个块或者部分块坏了,只需要恢复问题块,而不需要32G全部来一遍,这是Oracle应对页分裂的方式、检查和介质恢复。


六、PG如何处理页分裂


image.png

PG的测试过程,PG的IO函数pwrite,测试过程跟oracle差不多,PG机制跟Oracle机制是更类似一些,行也是倒着用,MySQL的行是正着来的。

image.png

所以我要插200行,把这个目标行撑到第二个或第三个4k,Oracle和PG是插入一行就行了,间隔表插一行在最末尾,在这个页的第二个4k,更新第二个4k,第一个4k也会变,也要手动触发检查点拦截系统调用,改8k为4k,让前4k写成功,再让IO报错。

 

image.png

在测试之前我先用一个简单的小脚本看一下。

image.png

它的写没有Oracle那么多,比MySQL的也少,没有UNDO,所以写会少一点,第一次这个写是针对WAL日志的,第二次写也是针对WAL日志的。

image.png

这些都让它成功,日志不成功没法做恢复。

image.png

第三次写是针对目标表的,要让四号文件写是失败的,其它的都是成功的。

image.png

上图是脚本。针对某个固定的进程,16045就是checkpoint的进程,让四号文件满足条件后才去破坏,最终这个条件也是为了让IO报错的,不能让io成功。前4k的IO是成功的,后4k是失败的。

image.png

上图是脚本。针对某个固定的进程,16045就是checkpoint的进程,让四号文件满足条件后才去破坏,最终这个条件也是为了让IO报错的,不能让io成功。前4k的IO是成功的,后4k是失败的。

update执行是成功的,commit也是成功的,执行checkpoint是失败的。

image.png

目标就是让它是失败的。这个数据库并没有宕掉,PG还是比较坚强的,如果把IO破坏之后MySQL就直接down了,Oracle也直接down了。

为了模拟,把所有的PG进程一起宕掉,就像页分裂是断电分裂,其实只kill第一个主进程也是可以的,kill多点保险点,这样就能看到日志里面有大量的IO报错,再重新启动的时候,PG找到了恢复的位置,这个恢复位置跟Oracle机制一样,这个位置就是检查点位置。

image.png

从日志的这个地方恢复成功后,数据库最后的启动过程也是成功的,连上后查我目标表,这个目标表数据查出来后,触发语句大写转小写。最终看到数据就是小写,页分裂问题就搞定了,它是以巨大的性能的代价解决了这个问题,,最终问题解决了,就是性能下降确实有点大。

image.png

这个页分裂是偶尔出现的一个问题,偶尔出现荡机,还不是当库,所以操作系统宕机和断电这种情况是极其偶尔出现的,为了一个极其偶尔出现的情况,引入性能损耗比较大的特性值得吗?


七、PG如何处理页分裂 --- 关闭FPW时的测试


image.png

对比各个主流的数据库后,我们要对FPW动手了,今天先讲第一步,刚才是把FPW打开时的测试,那把FPW关掉再来一遍,看下页分裂是什么情况。

image.png

整个测试过程是一模一样的,唯一区别就是把FPW关掉了,关掉后update是成功的,提交也是成功的,因为是隐含提交的。

image.png

Checkpoint也是失败的。

image.png

整个测试过程是一模一样的,唯一区别就是把FPW关掉了,关掉后update是成功的,提交也是成功的,因为是隐含提交,Checkpoint失败,

重启数据库时候发现这个数据没报错,就是因为前面把它改成小写了,但是这个地方可以看到是大写的。如果关掉了FPW后,数据可能是不一致的,但是这是在没有打开Checksum的情况,如果打开了通常还是会报错的。这样测试我做了很多遍,这个测试结果我还不确定,因为时间比较紧,所以这个例子我没放上来。


八、Non-FPW的思路


image.png

MySQL双写不能解决所有的问题,那我就摸着Oracle过河,Oracle的解决方案是报出错误,能够检测块的问题,检测不出来数据就不一致了,我提供让DB恢复,为了更快的恢复,也可以提供一个像Oracle一样的块恢复功能。MySQL不支持这样的功能,它是逻辑日志,只能恢复数据,不能恢复某一个固定的页。PG和Oracle都是物理日志,他们可以有black recovery的功能。

image.png

最终我们的方式是摸着Oracle过河,因为Oracle跟PG备份恢复体系差不多,检查点位置、特性都差不多,唯一不同的是Oracle是增量检查点,PG没有增量检查点,这点对我们影响不大。

目标是让PG实现跟Oracle一样检查加块恢复的功能,实现快速的不分写的解决方式。实现之后就可以安全的关掉FPW,不用担心出现断电后数据不一致的问题。

image.png

MySQL的恢复功能在StartupXLOG函数里面,这个函数在这个Xlog.c里面,在此if之后,就是它的恢复流程。

image.png

下面是要对这一部分代码去精读熟读,搞清楚每一行的意义,每个变量的作用等。在这个基础上去做修改调整,把它复制出来再自己做一个模块,用它做检查块和级恢复。

 

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
机器学习/深度学习 计算机视觉
【YOLOv8改进】CoordAttention: 用于移动端的高效坐标注意力机制 (论文笔记+引入代码)
该专栏聚焦YOLO目标检测的创新改进与实战,介绍了一种新的移动网络注意力机制——坐标注意力。它将位置信息融入通道注意力,通过1D特征编码处理,捕获长距离依赖并保持位置精度。生成的注意力图能增强目标表示,适用于MobileNetV2、MobileNeXt和EfficientNet等网络,提高性能,且几乎不增加计算成本。在ImageNet分类和下游任务(目标检测、语义分割)中表现出色。YOLOv8中引入了CoordAtt模块,实现位置敏感的注意力。更多详情及配置见相关链接。
|
10月前
|
弹性计算 运维 关系型数据库
用 Patroni 搭建 PolarDB-PG 高可用集群
本文详细介绍了如何利用开源PolarDB-PG和Patroni搭建高可用集群。实验环境使用了三台ECS,内核版本为PolarDB-PG 15,Patroni版本为4.0.3,etcd版本为3.5.0。文章依次讲解了ETCD的安装与配置、PolarDB-PG 15的安装与初始化,以及Patroni的配置和启动过程。通过Patroni自动创建备库,实现高可用集群的搭建。最后总结指出,用户可根据需求调整配置,或选择线上PolarDB-PG产品以减少运维成本并提升稳定性。
|
Kubernetes 监控 数据安全/隐私保护
K8s好看的管理页面Rancher管理K8S
K8s好看的管理页面Rancher管理K8S
290 4
|
芯片
STM32-FreeRTOS源码下载及移植步骤(基于Keil)
STM32-FreeRTOS源码下载及移植步骤(基于Keil)
2070 0
STM32-FreeRTOS源码下载及移植步骤(基于Keil)
|
机器学习/深度学习 自然语言处理 搜索推荐
深度分析 | 2024主流的智能客服系统有哪些?他们是怎么实现的?
本文深入探讨了智能客服系统的使用方法和相关技术实现逻辑,涵盖前端交互、服务接入、逻辑处理、数据存储四大层面,以及自然语言处理、机器学习、语音识别与合成、数据分析与挖掘、知识库管理和智能推荐系统等核心技术,帮助企业更好地理解和应用智能客服系统,提升服务效率和客户满意度。
2020 1
|
10月前
|
存储 JSON 数据格式
什么情况,一夜之间冲上热搜,狂揽29.6k星,再见吧SQLite!这个嵌入式分析引擎实在太香了
DuckDB是一款嵌入式OLAP数据库,专为高效分析型查询设计,被誉为“分析型SQLite”。它采用列式存储和向量化查询引擎,显著提升分析任务性能。无需独立服务器,支持Python、R、Java等语言,安装简单,5分钟即可上手。DuckDB可直接查询CSV、JSON、Parquet文件,支持Pandas零拷贝交互,优化SQL语法简化复杂查询。适用于探索性数据分析、数据湖ETL流水线及边缘设备实时分析等场景,是数据科学家和开发者的理想工具。项目地址:https://github.com/duckdb/duckdb
1084 4
|
SQL 存储 关系型数据库
MySQL 回收表碎片实践教程
在 MySQL 数据库中,随着数据的增删改操作,表空间可能会出现碎片化,这不仅会占用额外的存储空间,还可能降低表的扫描效率,特别是一些大表,在进行数据清理后会产生大量的碎片。本篇文章我们一起来学习下如何进行碎片回收以及相关注意点。
477 1
MySQL 回收表碎片实践教程
|
传感器 人工智能 监控
《数据流驱动:C++构建 AI 模型持续学习新范式》
本文探讨了如何利用C++开发基于数据流的人工智能模型持续学习系统,覆盖了从数据接入、预处理、模型训练与更新、评估监控到输出应用的全流程。文章强调了C++在处理实时数据流、确保系统实时性和效率方面的独特优势,并讨论了其在物联网、金融、工业自动化等领域的应用前景,以及未来技术发展趋势。
570 9
|
存储 移动开发 API
HTML5的新特性
HTML5引入了众多新特性和增强功能,简化并强化了网页开发。新增结构元素如`<header>`、`<footer>`、`<article>`等使页面布局更清晰;表单增强支持更多输入类型及属性;内置音频视频播放无需插件;`<canvas>`与SVG支持提升了图形处理能力;Geolocation API和Web存储改善了用户体验;离线应用、拖放功能及Web Workers则进一步提升了网页应用的实用性和交互性。HTML5令网页开发更为现代化,为开发者提供了丰富的工具集。
|
Kubernetes Cloud Native 关系型数据库
云原生数据基础设施之kubeblocks
云原生数据基础设施之kubeblocks

热门文章

最新文章