当前位置: 首页 > news >正文

MySQL----BufferPool、redolog binlog两阶段提交

BufferPool的理解

由于BufferPool属于内存,在mysql中处于一个比较重要的角色,基本的操作其实都是基于BufferPool缓存进行的,而内存资源又是比较稀缺的所以对于BufferPool的内存管理是比较重要的,Mysql的内存管理主要如下

相当于对于bufferpool的管理主要有三个

  • 1、空闲链表法
  • 2、脏页链表管理
  • 3、改进后的LRU算法来将热点数据缓存在BufferPool中

一、关于 Buffer Pool 的产生原因

Buffer Pool 的产生确实是为了加快 MySQL 的查询和更新操作。由于从磁盘加载数据相对缓慢,开辟连续的内存空间作为 Buffer Pool,可以在访问数据时先查看内存中是否有对应的数据,若有则直接从内存操作,没有则从磁盘加载到 Buffer Pool 后再进行操作,从而提高执行速度。

二、关于 Buffer Pool 的管理

空闲区域管理:

采用空闲列表法是正确的,将所有空闲的页通过列表串起来,当从磁盘加载数据时,从空闲列表中取出一个或几个页进行填充数据,并从空闲列表中删除。

脏页管理:

当 Buffer Pool 中的数据和磁盘中的数据不一样时称为脏页,通过列表管理脏页也是正确的。当数据更新时,将该页设置为脏页并添加到脏页列表中,当脏页被刷盘到磁盘时,再从列表中移出。

热点数据管理:

采用改进的 LRU 算法是正确的。将模拟链表分为 young 区域和 old 区域,从磁盘加载数据时先记录在 old 区域,当访问对应的页时,该页移动到 old 区域头部,依次迭代淘汰未访问的页。当 old 区域的某些页停留一定时间后晋升到 young 区域,保证高频访问的数据留在 Buffer Pool 中,提高命中率,防止 Buffer Pool 被不常用数据污染。

两阶段的总结

为什么要有

在更新数据时涉及到 redo log 和 binlog 的刷盘,这两个操作的执行顺序不可控。如果在更新操作后 MySQL 宕机,可能出现 redo log 刷盘成功而 binlog 未刷盘,或者反之的情况。这会导致在故障恢复后,主节点和从节点的数据不一致,因为从节点是通过 binlog 来保持数据一致性的。为了解决这个问题,引入了两阶段提交。(一句话总结就是:两阶段提交主要是为了保证redolog和binlog的数据一致性的)

两阶段提交的过程(MySQL 内部)

在 MySQL 中,特别是 InnoDB 存储引擎和 binlog 日志结合使用时,两阶段提交的过程是这样的:


流程

第一阶段:准备阶段

  • 将XID(XA事务的ID)写入到redo log中,同时将redo log对应的事务状态设置为prepare准备状态,然后将redo log持久化刷盘到磁盘中(刷盘策略设置为1)。

第二阶段:提交阶段

  • 将XID写到binlog中,然后将binlog持久化到磁盘文件中,接着调用存储引擎层接口,将redo log中的状态设置为commit状态,此时状态并不需要持久化到磁盘中,只需要write到文件系统的page cache中就可以了,因为只要binlog写磁盘成功,就算redo log的状态是Prepare状态,一样会被认为是事务已经执行成功

从上面不难看出决定事务最后是成功还是需要回滚还是取决于binlog中是否有对应的XID来控制,redo log在两阶段中理论上是刷盘在binlog之前,所以只要binlog中有对应的XID就代表成功

因此其他现象也就解释的通了,比如我们在修改某条数据的时候首先会在buffer pool缓冲池中进行修改,修改之后对应的页就变成了脏页,然后此时修改的数据会被同步到redo buffer中,需要注意的是redo buffer中的数据在我们没有进行commit之前也可能进行刷盘(因为操作系统会以某个速率比如每秒刷盘),但是此时由于没有进行commit那么此时binlog中是一定没有这个数据的,根据两阶段提交,就算最后数据库宕机了重启时,由于binlog中没有对应数据的XID那么就会执行回滚策略。

故障恢复过程

在MySql宕机重启之后会先按照顺去去扫描Redo log文件,当碰到prepare准备阶段的redo log时,就会拿着redo log中的XID去binlog中去查看是否存在此XID

  • 如果binlog中没有当前内部XA事务的XID,那么说明redo log已经成功刷盘,但是binlog中还没进行刷盘,则回滚事务(对应时可A的宕机恢复)
  • 如果binlog中有当前内部XA事务的XID,说明redo log和binlog都已经完成了刷盘,那么就提交事务(对于时刻B的宕机恢复)

两阶段所带来的问题以及解决方案

带来的问题

  • 1、频繁的I/O操作(如果我们设置的刷盘策略都是每次commit都进行刷盘,那么两阶段对于每次事务都需要两次IO操作
  • 2、锁竞争频繁:在mysql5.7之前为了保证事务之间的提交顺序是需要使用到锁资源的,即进入prepare阶段需要先获取锁,commit阶段完成释放锁

解决方案:

在mysql5.7之后就引入了binlog的组提交的方案:当有多个事务提交的时候,会将binlog刷盘操作合并成一个,从而减少磁盘的I/O操作次数

引入组提交机制主要是影响两阶段的commit阶段,对于prepare阶段是不变的,组操作将commit阶段分为了三个过程:每个阶段都维护一个队列来保证事务的提交顺序

  • flush阶段:将多个事务按照顺序将binlog从binlog cache写入到page cache中(不刷盘),(可以理解为保存在flush阶段的队列中)
  • sync阶段:对binlog文件做fsync操作(多个事务的binlog合并在一起进行刷盘)(同样将其放入sync维护的队列中)
  • commit阶段:按照事务的提交顺序做InnoDB 的commit操作,即调用引擎层的提交事务接口,将redo log状态设置为commit状态

对于Sync阶段的图解流程:

执行一条更新操作的具体流程:

具体更新一条记录 UPDATE t_user SET name = 'xxx' WHERE id = 1; 的流程如下:

  1. 执行器负责具体执行,会调用存储引擎的接口,通过主键索引树搜索获取 id = 1 这一行记录:
    • 如果 id=1 这一行所在的数据页本来就在 buffer pool 中,就直接返回给执行器更新;
    • 如果记录不在 buffer pool,将数据页从磁盘读入到 buffer pool,返回记录给执行器。
  1. 执行器得到聚簇索引记录后,会看一下更新前的记录和更新后的记录是否一样:
    • 如果一样的话就不进行后续更新流程;
    • 如果不一样的话就把更新前的记录和更新后的记录都当作参数传给 InnoDB 层,让 InnoDB 真正的执行更新记录的操作;
  1. 开启事务, InnoDB 层更新记录前,首先要记录相应的 undo log,因为这是更新操作,需要把被更新的列的旧值记下来,也就是要生成一条 undo log,undo log 会写入 Buffer Pool 中的 Undo 页面,不过在内存修改该 Undo 页面后,需要记录对应的 redo log。
  2. InnoDB 层开始更新记录,会先更新内存(同时标记为脏页),然后将记录写到 redo log 里面,这个时候更新就算完成了。为了减少磁盘I/O,不会立即将脏页写入磁盘,后续由后台线程选择一个合适的时机将脏页写入到磁盘。这就是 WAL 技术,MySQL 的写操作并不是立刻写到磁盘上,而是先写 redo 日志,然后在合适的时间再将修改的行数据写到磁盘上。
  3. 至此,一条记录更新完了。
  4. 在一条更新语句执行完成后,然后开始记录该语句对应的 binlog,此时记录的 binlog 会被保存到 binlog cache,并没有刷新到硬盘上的 binlog 文件,在事务提交时才会统一将该事务运行过程中的所有 binlog 刷新到硬盘。
  5. 事务提交(为了方便说明,这里不说组提交的过程,只说两阶段提交):
    • prepare 阶段:将 redo log 对应的事务状态设置为 prepare,然后将 redo log 刷新到硬盘;
    • commit 阶段:将 binlog 刷新到磁盘,接着调用引擎的提交事务接口,将 redo log 状态设置为 commit(将事务设置为 commit 状态后,刷入到磁盘 redo log 文件);
    • 至此,一条更新语句执行完成。

本文主要参考MySQL 日志:undo log、redo log、binlog 有什么用? | 小林coding

目前已更新系列:

当前:MySQL----BufferPool、redolog binlog两阶段提交

实习期间git的分枝管理以及最常用的命令-CSDN博客

Redis高级-----持久化AOF、RDB原理

Redis高级---面试总结5种数据结构的底层实现

Redis高级----主从、哨兵、分片、脑裂原理-CSDN博客

Redis高级---面试总结内存过期策略及其淘汰策略

计算机网络--面试知识总结一

计算机网络-----面试知识总结二

计算机网络--面试总结三(Http与Https)

计算机网络--面试总结四(HTTP、RPC、WebSocket、SSE)-CSDN博客

计算机网络-------重传、TCP流量控制、拥塞控制_tcp拥塞控制,拥塞避免-CSDN博客

知识积累之ThreadLocal---InheritableThreadLocal总结

分布式ID多种生成方式-CSDN博客

并发编程之----线程池ThreadPoolExecutor,Excutors的使用及其工作原理


http://www.mrgr.cn/news/55190.html

相关文章:

  • Vue脚手架学习 vue脚手架配置代理、插槽、Vuex使用、路由、ElementUi插件库的使用
  • Java 当中使用 “google.zxing ”开源项目 和 “github 的 qrcode-plugin” 开源项目 生成二维码
  • nginx中的HTTP 负载均衡
  • Spring Boot 核心理解-自定义Starter
  • 动态规划-子数组系列——413.等差数列划分
  • 【CS常见问题】你用的是VS2019,最高支持.NET5.0,但是项目将.NET6.0设为目标无法运行,怎么办?
  • 音视频:安防监控
  • Docker 搭建mysql
  • MySQL 数据库的备份与恢复:最佳实践与深度探讨
  • es6 新增方法
  • CompletableFuture回调机制的设计与实现
  • 【最新华为OD机试E卷-支持在线评测】数字游戏(200分)多语言题解-(Python/C/JavaScript/Java/Cpp)
  • Linux进程间通信(二)——共享内存
  • 【STM32开发之寄存器版】(十二)-I2C基础知识详解
  • 前后端联调需要改ip联调多个后端,用nginx代理
  • QT5升级到QT6后遇到的问题
  • Bitmap 和 布隆过滤器傻傻分不清?你这不应该啊
  • 聚焦IOC容器刷新环节postProcessBeanFactory(BeanFactory后置处理)专项
  • SVN 小乌龟 下载地址
  • Git 基本配置
  • nodejs基础(2)
  • 同步和异步路由
  • 【网络安全的神秘世界】Python 3.7安装教程
  • C++实现简易JSON解析与转储
  • 电磁兼容(EMC):趋肤效应在PCB设计中的应用详解
  • DataGrip导出MySql提示无权限errno 13 - Permission denied问题