Non-FPW开发实战

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: 在阿里云开源的趋势下,如何做到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

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

 

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
4月前
|
Java 数据格式 微服务
2024最新首发,全网最全 Spring Boot 学习宝典(附思维导图)
📚 《滚雪球学Spring Boot》是由CSDN博主bug菌创作的全面Spring Boot教程。作者是全栈开发专家,在多个技术社区如CSDN、掘金、InfoQ、51CTO等担任博客专家,并拥有超过20万的全网粉丝。该教程分为入门篇和进阶篇,每篇包含详细的教学步骤,涵盖Spring Boot的基础和高级主题。
260 4
2024最新首发,全网最全 Spring Boot 学习宝典(附思维导图)
游戏开发实战教程系列
做一个不会过时的游戏。这个游戏的玩法很经典,经过市场的验证,如同俄罗斯方块一样不会过时。 做一个做完后不需要再去长期维护的游戏。做完了就是做完了,不需要再继续投入时间精力维护。 做一个精致的游戏。让人打开它后能够感受到这是一个精致的作品,会让人感觉到舒服。
102 0
|
存储
游戏开发实战教程(1)
现在学习编程似乎非常的热门,尤其是针对小孩子。各种培训机构教育机构都会有各种各样的编程课,宣传要尽早的培养孩子的编程思维,因为当前是互联网的时代,将来会编程可能会像每个人都会开车一样的成为一种必须的技能。
93 0
|
存储 前端开发 安全
云开发实战 | 学习笔记
简介:快速学习云开发实战
284 0
云开发实战 | 学习笔记
|
SQL 前端开发 Java
全栈开发实战|SSM框架整合开发
全栈开发实战|SSM框架整合开发
143 0
全栈开发实战|SSM框架整合开发
|
缓存 NoSQL Java
Spring Boot 2.5.x开发实战 | 开发者学堂课程干货总结合集
Spring Boot 2.5.x开发实战是学习Java Spring Cloud微服务架构的必经之路
2587 3
Spring Boot 2.5.x开发实战 | 开发者学堂课程干货总结合集
|
缓存 监控 安全
开发者学堂课程干货总结——Spring Boot 2.5.x开发实战(一)
Spring Boot 2.5.x开发实战课时1——Spring Boot2.5实战课程大纲与新特性介绍,Spring Boot 2.5.x开发实战是学习Java Spring Cloud微服务架构的必经之路。电子书+视频为同学带来最佳学习效果,文字、课程链接、图谱地址统统为大家放送了哦
开发者学堂课程干货总结——Spring Boot 2.5.x开发实战(一)
|
缓存 NoSQL 安全
开发者学堂课程干货总结——Spring Boot 2.5.x开发实战(六)
Spring Boot 2.5.x开发实战课时6——Spring Boot 2.5实战Redis分布式缓存6.0 ,Spring Boot 2.5.x开发实战是学习Java Spring Cloud微服务架构的必经之路。电子书+视频为同学带来最佳学习效果,文字、课程链接、图谱地址统统为大家放送了哦
开发者学堂课程干货总结——Spring Boot 2.5.x开发实战(六)
|
缓存 Prometheus 监控
开发者学堂课程干货总结——Spring Boot 2.5.x开发实战(九)
Spring Boot 2.5.x开发实战课时9——Spring Boot2.5实战 – 应用程序性能监控(Admin&Actuator),Spring Boot 2.5.x开发实战是学习Java Spring Cloud微服务架构的必经之路。电子书+视频为同学带来最佳学习效果,文字、课程链接、图谱地址统统为大家放送了哦
开发者学堂课程干货总结——Spring Boot 2.5.x开发实战(九)
|
监控 前端开发 Java
开发者学堂课程干货总结——Spring Boot 2.5.x开发实战(八)
Spring Boot 2.5.x开发实战课时8——Spring Boot 2.5实战API帮助文档Swagger,Spring Boot 2.5.x开发实战是学习Java Spring Cloud微服务架构的必经之路。电子书+视频为同学带来最佳学习效果,文字、课程链接、图谱地址统统为大家放送了哦
开发者学堂课程干货总结——Spring Boot 2.5.x开发实战(八)