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

MySQL(日志)

日志

日志分为三种:
undo log (回滚日志):用于事务回滚和MVCC
redo log (重做日志):用于故障恢复
binlog (归档日志):用于数据备份和主从复制

undo log

undo : 撤销

undo log :在Innodb存储引擎层生成的日志

在这里插入图片描述

一条记录的每一次更新操作产生的undo log格式都有一个roll_pointer指针和一个trx_id事务id:

  1. 通过trx_id可以知道该记录是被哪个事务修改的;
  2. 通过roll_pointer指针可以将这些undo log 串成一个链表,这个链表可以称为版本链

undo log 通过ReadView + undo log 实现MVCC(多版本并发控制)

undo log 两大作用:

  1. 实现事务回滚,保障事务的原子性。
  2. 实现MVCC关键因素之一。

Buffer pool(缓冲池)

建立Buffer pool的目的:提高读写效率。

MySQL读取一条记录时,先从磁盘读取该记录,然后在内存中修改该记录。修改完不直接写回磁盘,而是缓存起来,下次命中,直接从缓存中拿

InnoDB设计了一个缓冲池(Buffer Pool),来提高数据库的读写性能。

  1. 当读取数据时,如果数据存在于Buffer pool中,那么直接从Buffer pool中拿,否则从磁盘中拿。
  2. 修改数据时,如果数据存在于Buffer pool中,那么直接修改Buffer pool中数据所在的页,然后将其页设置为脏页,为了减少磁盘IO,不会立即将脏页写入磁盘,后续由后台线程选择一个合适的时机将脏页写入磁盘。

Buffer pool中的数据存储,和磁盘一样,是以页为单位,与磁盘的数据交换也是以页为单位。一页默认为16KB。

Buffer pool 除了缓存【索引页】和【数据页】,还包括 Undo页,插入缓存、自适应哈希索引、锁信息等。

Buffer pool

redo log

断电丢失问题:Buffer pool是基于内存的,如果断电重启,还未来的及写入磁盘的脏页数据就会丢失

解决:
为了防止断电丢失的问题,当有一条记录需要更新时,InnoDB引擎就会先更新内存(同时标记为脏页),然后将本次对这个页的修改以redo log的形式记录下来,这个时候,更新就算完成。后续由后台线程选择一个合适的时机将脏页写入磁盘。
这就是:WAL(Write-Ahead Logging)技术:MySQL的写操作并不是立刻写在磁盘上,而是先写日志,然后在合适的时间再写入磁盘。

在这里插入图片描述
什是redo log?

redo log 是物理日志,记录了某个数据页做了什么修改。
在事务提交时,只要先将redo log持久化到磁盘即可,可以不需要等到将缓存在Buffer pool里的脏页数据持久化到磁盘。
当系统崩溃时,虽然脏页数据没有写入磁盘,但是redo log已经写入磁盘,MySQL重启后,可以根据redo log的内容,将所有数据恢复到最新的状态。

被需改Undo 页面,需要记录对应的redo log吗?

需要
开始事务后,InnoDB层更新记录前,首先要记录相应的undo log,如果是更新操作,需要把更新的列的旧值记录下来,也就是生成一条undo log,undo log会写入Buffer pool中的Undo页面中。
不过,在内存修改undo 页面后,需要记录对于的redo log

redo log 和 undo log 的区别在哪?

redo log 记录了此次事务完成后的数据状态,记录的的是更新之后的值
undo log 记录了此次事务开始前的数据状态,记录的是更新之前的值
事务提交之前发生崩溃,重启后通过undo log回滚事务
事务提交之后发生崩溃,重启后通过redo log恢复事务

redo log 有自己的缓存 redo log buffer,每产生一条redo log时,会先写到redo log buffer,后续再持久化到磁盘中。
redo log buffer 默认大小为16MB,可以动态调整。

在这里插入图片描述
redo log 什么时候刷盘?

主要有以下几个时机:

  1. MySQL正常关闭时
  2. 当redo log buffer被写满一半时
  3. InnoDB的后台线程每隔1秒,将redo log buffer写入磁盘
  4. 每次事务提交时都将redo log buffer中的redo log直接写入磁盘。(这里有一个参数可以控制innodb_flush_log_at_trx_commit

innodb_flush_log_at_trx_commit
0:事务提交后,redo log留在buffer
1:事务提交后,redo log直接写入磁盘
2:事务提交后,redo log写入操作系统的Cache中
数据安全性:1 > 2 > 0
写入性能:0 > 2 > 1
当其值为 0 和 2时,InnoDB的后台线程每隔1秒

  1. 针对参数0:调用write()写入Cache中,再调用 fsync()持久化磁盘中。如果MySQL进程崩溃,会导致上一秒钟所有事物数据丢失
  2. 调用fsync(),将Cache中的redo log写入磁盘。MySQL进程的崩溃不会丢失数据,只有OS崩溃或者系统断电的情况下,上一秒所有事物数据才会丢失

redo log 文件写满了怎么办?

redo log并不是无限大的,也就是说,redo log不会记录自数据库创建以来的所有redo操作。一条记录被更改,产生redo log,当buffer pool中的脏页持久化到磁盘,那么相应的redo log也就失去了作用。

默认情况下,InnoDB存储引擎有一个重做日志文件组(redo log group),其有两个redo log文件组成,大小一直。
重做日志文件组一循环写的方式工作的,从开头写到结尾,再从结尾写到开头。

在这里插入图片描述

binlog(归档日志)

undo log 和 redo log 是由InnoDB存储引擎产生的
binlog 是由Server层产生的

binlog 文件记录了所有数据库表结构变更和表数据修改,不会记录查询类操作。
binlog有三种格式类型

  1. STATEMENT(默认格式):记录SQL语句,但是存在动态函数的问题,比如获取当期时间、uuid
  2. ROW:记录行数据最终被修改成什么样了。如果批量执行update语句,那可能会导致binlog文件过大。
  3. MIXED:包含了上述两种模式,根据不同情况自动使用ROW和STATEMENT。

redo log 和 binlog 的区别

  1. 适用对象不同。
    binlog由Server层实现,所有引擎都可以使用,
    redo log是InnoDB存储引擎实现。
  2. 文件格式不同。
    binlog有三种格式类型。
    redo log是物理日志,记录的是某个数据页做了什么修改,比如对xxx表空间中的yyy数据页zzz偏移量的地方做了aaa更新。
  3. 写入方式不同。
    binlog是追加写,写满一个文件,就创建一个新的文件继续写,不会覆盖以前的,保存全量的日志。
    redo log 是循环写,日志空间大小是固定的。
  4. 用途不同。
    binlog用于备份恢复,主从复制。
    redo log 用于掉电故障恢复。

恢复整个数据库,应该用binlog

主从复制是怎么实现的?

主从复制的过程就是将binlog中的数据从主库传输到从库上。
这个过程一般是异步的,也就是主库上执行事务操作的线程不会等待复制binlog的线程同步完成。

在这里插入图片描述

MySQL集群的主从复制过程梳理成3个阶段

  • 写入binlog:主库写binlog日志,提交事务,并更新本地存储数据。
  • 同步binlog:把binlog复制到所有从库上,每个从库把binlog写到暂存日志中。
  • 回放binlog:回放binlog,并更新存储引擎中的数据。

主从复制模型

主要有三种:

  • 同步复制:MySQL主库提交事物的线程等待所有从库的复制成功响应,才返回客户端结果。
  • 异步复制(默认模型):MySQL主库提交事务的线程并不会等待binlog同步到个从库,就直接返回客户端结果。这种模式一旦主库宕机,数据就会发生丢失。
  • 半同步复制:介于两者之间,事务线程不用等待所有的从库复制成功响应,只要一部分复制成功响应回来就行。这种半同步复制的方式,兼顾两者的优点,即使主库宕机,至少还有个从库有最新的数据,不存在数据丢失的风险。

binlog什么时候刷盘?

  • 事务执行过程中,先把日志写到binlog cache(Server层的cache,MySQL给每个线程分配了一片内存空间用于缓存binlog,可以用binlog_cache_size参数控制大小),事务提交的时候,再把binlog cache写到binlog文件中。

  • 一个事务的binlog是不能被拆开的,无论这个事务有多大,也要要保证一次性写入。

  • 事务提交时,执行器把binlog cache里的完整事务写入到binlog文件中,并清空binlog cache
    在这里插入图片描述

  • 虽然每个线程都有自己的binlog cache,但最终都会写到一个binlog文件中。

  • 图中的write,指的就是把日志写入到binlog文件,但是并没有持久化到磁盘。这时,数据在OS的cache中。

  • 图中的fsync,才是将数据持久化到磁盘的操作,这里就会涉及磁盘I/O。
    MySQL提供一个sync_binlog参数来控制数据库的binlog刷到磁盘上的频率

  • sync_binlog = 0:表示每次提交事务都只write,不fsync,后续交由操作系统决定合适将数据持久化到磁盘。(MySQL系统默认为0)

  • sync_binlog = 1:表示每次事务都会write,然后马上fsync。

  • sync_binlog = N(N > 1):表示每次提交事务都会write,但累计N个事务后才会fsync

一条update语句执行流程

在这里插入图片描述

两阶段提交

事务提交后,redo log 和 binlog 都要持久化到磁盘中,但这是两个独立的逻辑,可能出现半成功的状态,造成主从数据不一致

解决:两阶段提交
两阶段提交把单个事务的提交拆分成2个阶段:**准备阶段(Prepare)**和 提交阶段(Commit)。
每个阶段都由 协调者参与者 共同完成

大致的思想是:把redo log的提交分成两个阶段,将binlog的提交插入其中

未来保证这两个日志的一致性,MySQL使用了内部XA事务,内部事务有binlog作为协调者,存储引擎为参与者。

两阶段提交过程

两阶段提交过程

  • prepare阶段将XID(内部事务的ID)写入到redo log, 同时将redo log对应的的事物状态设置为prepare,然后将redo log写入磁盘
  • commit阶段将XID写入binlog,然后将binlog写入磁盘,将redo log状态设置为commit。

两阶段提交是以binlog写成功作为事务成功的标识。

redo log 可以在事务没提交之前持久化到磁盘,但是binlog必须在事务提交之后,才可以持久化到磁盘。

异常崩溃会出现什么现象

在这里插入图片描述

  • 时刻A崩溃:redo log处于prepare状态,redo log完成刷盘,binlog没有刷盘。磁盘中的redo log中有XID,binlog没刷盘,没有XID,则回滚事务。
  • 时刻B崩溃:redo log处于prepare状态,redo log完成刷盘,binlog完成刷盘。磁盘中的redo log 和 binlog 都有XID,则提交事务。
两阶段提交存在的问题
  • 磁盘I/O次数高:每一次进行两阶段提交,都会进行两次磁盘IO。
  • 锁竞争激烈:在多事务的情况下,需要加一个锁来保证两阶段提交的原子性。锁的是整个两阶段提交过程。
组提交
MySQL引入了**binlog组提交**(group commit)机制,当多个事务提交的时候,会将多个binlog刷盘操作合并成一个,从而减少磁盘I/O次数。

组提交机制,prepare阶段没变,只针对commit阶段,将其分为了三个阶段:

  • flush阶段(不刷盘):多个事务按照进入的顺序将binlog从cache(这里的cache应该是MySQL Server层的binlogcache)写入文件。也就是把binlog写入OS的Cache,为刷盘做准备。
  • sync阶段(刷盘):对binlog文件做fsync操作(多个事务的binlog合并一次刷盘)
  • commit阶段(返回OK):各个事务按顺序做InnoDB commit操作
以上每个阶段都有一个队列,每个阶段都有锁进行保护,因此保证了事务写入的顺序。

锁的粒度减小了,这样就使得多个阶段可以并发执行,从而提升效率。

第一个进入队列的事物会成为leader,leader领导所在队列的所有事务,全权负责整队的操作,完成后通知其他事物操作结束。

有binlog组提交,redo log也有组提交(MySQL 5.7)
redo log的刷盘操作推迟到flush阶段,也就是说prepare阶段融合在flush阶段。

总结

在这里插入图片描述


http://www.kler.cn/news/314651.html

相关文章:

  • 未来视界,触手可及:bigmp4 引领 AI 视频处理新革命
  • pytorch的动态计算图机制
  • 华为HarmonyOS地图服务 4 - 通过“地图相机“控制地图的可见区域
  • C语言中易混淆概念的关键字
  • Vue+nodejs+express旅游景区门票预订网站的设计与实现 8caai前后端分离
  • MyBatis操作数据库-XML实现
  • MySQL5.7主从复制集群如何配置半同步复制
  • asp.net core调用wps实现word转pdf的方法
  • Python Selenium 自动化爬虫 + Charles Proxy 抓包
  • 十四,在Spring Boot当中对应“ Tomcat 服务器的相关配置”和“服务器的切换”的详细说明
  • 掌握 JavaScript 中的函数表达式
  • 页面布局实现-左侧横向滑动展示隐藏数据,右侧固定展示操作按钮。可上下滑动联动
  • 常用的图像增强的算法之间的联系和区别
  • Python3网络爬虫开发实战(17)爬虫的管理和部署(第一版)
  • Samba服务
  • 传统到AI 大数据分析的演变,颠覆智慧水电的未来?
  • 【JavaEE初阶】多线程(4)
  • 2024/9/21黑马头条跟学笔记(十)
  • Ubuntu 安装和使用 Fcitx 中文输入法;截图软件flameshot
  • 从零到一:打造安全高效敦煌测评自养号体系
  • 《C++高效字符串拼接之道:解锁性能与优雅的完美结合》
  • mac系统加密文件
  • Flutter Android Package调用python
  • 基于深度学习的因果推理与决策
  • 【JVM】运行时数据区
  • Ubuntu 20.04 内核升级后网络丢失问题的解决过程
  • 《DevOps实践指南》笔记-Part 3
  • Swift里的数值变量的最大值和最小值
  • 分布式光伏发电站数据采集设备管理硬件解决方案
  • 机器学习——Stacking