MySQL学习[5] ——MySQL日志

news2024/9/22 13:35:47

五、MySQL日志

5.1 MySQL中有哪些日志?

MySQL中主要有三种日志:undo log(回滚日志)、redo log(重做日志)、binlog(归档日志),简单介绍:

  • undo log(回滚日志):InnoDB存储引擎层生成的日志,保证事务中的原子性,用于事务回滚和MVCC
  • redo log(重做日志):InnoDB存储引擎层生成的日志,保证事务中的持久性,用于掉电等故障恢复
  • binlog(归档日志):Server层生成的日志,用于数据备份和主从复制

5.2 为什么需要undo log?

5.2.1 undo log是什么?

当事务对数据库进行更新(插入、修改、删除)时,MySQL会记录**更新前的数据到undo log文件中**,当事务回滚时,可以利用undo log来实现。如图:

每当 InnoDB 引擎对一条记录进行操作(修改、删除、新增)时,要把回滚时需要的信息都记录到 undo log 里,比如:

  • 插入一条记录时,要把这条记录的主键值记下来,这样之后回滚时只需要把这个主键值对应的记录删掉就好了;
  • 删除一条记录时,要把这条记录中的内容都记下来,这样之后回滚时再把由这些内容组成的记录插入到表中就好了;
  • 更新一条记录时,要把被更新的列的旧值记下来,这样之后回滚时再把这些列更新为旧值就好了。

不同的操作,需要记录的内容也是不同的,所以不同类型的操作(修改、删除、新增)产生的 undo log 的格式也是不同的。

5.2.2 undo log的两大作用?

除了事务回滚作用。前面提到,MySQL中一个记录的真实数据中有几个隐藏字段,包括 roll_pointer 指针和一个 trx_id 事务id。

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

通过trx_id 和版本链,利用**ReadView + undo log 可以实现MVCC(多版本并发控制)**。

「事务的 Read View 里的字段」和「记录中的两个隐藏列(trx_id 和 roll_pointer)」的比对,如果不满足可见性,就会**顺着 undo log 版本链里找到满足其可见性的记录**,从而控制并发事务访问同一个记录时的行为,这就叫 MVCC(多版本并发控制)。

因此,undo log 两大作用:

  • 实现事务回滚,保障事务的原子性。事务处理过程中,如果出现了错误或者用户执 行了 ROLLBACK 语句,MySQL 可以利用 undo log 中的历史数据将数据恢复到事务开始之前的状态。
  • 实现 MVCC(多版本并发控制)关键因素之一。MVCC 是通过 ReadView + undo log 实现的。undo log 为每条记录保存多份历史数据,MySQL 在执行快照读(普通 select 语句)的时候,会根据事务的 Read View 里的信息,顺着 undo log 的版本链找到满足其可见性的记录。

5.3 为什么需要redo log?

5.3.1 认识Buffer Pool

MySQL的数据是保存在磁盘的,但是频繁的进行磁盘I/O会影响性能。因此,InnoDB存储引擎设计了一个**缓冲池(Buffer Pool)**,提高数据库的读写性能。

有了 Buffer Poo 后:

  • 当读取数据时,如果数据存在于 Buffer Pool 中,客户端就会直接读取 Buffer Pool 中的数据,否则再去磁盘中读取。
  • 当修改数据时,如果数据存在于 Buffer Pool 中,那直接修改 Buffer Pool 中数据所在的页,然后将其页设置为**脏页(该页的内存数据和磁盘上的数据已经不一致),为了减少磁盘I/O,不会立即将脏页写入磁盘,后续由后台线程选择一个合适的时机将脏页写入到磁盘**。

这样可以显著提高数据库的性能。

5.3.2 Buffer Pool缓存什么?

由于InnoDB存储引擎中,使用**「页」作为磁盘与内存交互的基本单位**。因此Buffer Pool中也是由页组成的,在 MySQL 启动的时候,InnoDB 会为 Buffer Pool 申请一片连续的内存空间,然后按照默认的16KB的大小划分出一个个的页, Buffer Pool 中的页就叫做缓存页。初始时,这些缓存页都是空闲的,之后随着程序的运行,才会有磁盘上的页被缓存到 Buffer Pool 中。

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

数据库更新时,undo log 就是写入 Buffer Pool 中的 Undo 页面中的。

Buffer Pool 和磁盘交换的单位是页,当我们查询一条记录时,InnoDB 是会把整个页的数据加载到 Buffer Pool 中,将页加载到 Buffer Pool 后,再通过页里的「页目录」去定位到某条具体的记录。

5.3.3 redo log是什么?

Buffer Pool 是基于内存的,而内存总是不可靠,万一断电重启,还没来得及落盘的脏页数据就会丢失。因此,当有一条记录需要更新时,InnoDB首先更新内存,并将这个Buffer Pool页面标记为脏页,然后**把本次对这个页的修改以redo log的形式记录下来,此时已经算是完成更新了**(但实际上还没有存储到磁盘)。

后续,InnoDB 引擎会在适当的时候,由后台线程将缓存在 Buffer Pool 的脏页刷新到磁盘里,这就是 WAL (Write-Ahead Logging)技术: MySQL 的写操作并不是立刻写到磁盘上,而是先写日志,然后在合适的时间再写到磁盘上

redo log 是物理日志,记录了某个数据页做了什么修改,比如对 XXX 表空间中的 YYY 数据页 ZZZ 偏移量的地方做了AAA 更新,每当执行一个事务就会产生这样的一条或者多条物理日志。在事务提交时,只要**先将 redo log 持久化到磁盘即可**,可以不需要等到将缓存在 Buffer Pool 里的脏页数据持久化到磁盘。

当系统崩溃时,虽然脏页数据没有持久化,但是 redo log 已经持久化,接着 MySQL 重启后,可以根据 redo log 的内容,将所有数据恢复到最新的状态。

5.3.4 redo log和undo log的区别

这两种日志是属于 InnoDB 存储引擎的日志,它们的区别在于:

  • redo log 记录了此次事务「完成后」的数据状态,记录的是更新之后的值;
  • undo log 记录了此次事务「开始前」的数据状态,记录的是更新之前的值;

事实上,当InnoDB层更新记录时,会生成一条undo log,这个undo log会写入到Buffer Pool中的Undo页,此时这个写入过程也会被记录对应的redo log。所以,可以说:undo log 和数据页的刷盘(持久化到磁盘)策略是一样的,都需要通过 redo log 保证持久化。

5.3.5 redo log 要写到磁盘,数据也要写磁盘,为什么要多此一举?

写入 redo log 的方式使用了追加操作, 所以磁盘操作是**顺序写,而写入数据需要先找到写入位置,然后才写到磁盘,所以磁盘操作是随机写**。

磁盘的「顺序写 」比「随机写」 高效的多,因此 redo log 写入磁盘的开销更小。

至此, 针对为什么需要 redo log 这个问题我两个答案:

  • 实现事务的持久性,让 MySQL 有 crash-safe 的能力,能够保证 MySQL 在任何时间段突然崩溃,重启后之前已提交的记录都不会丢失;
  • 将写操作从「随机写」变成了「顺序写」,提升 MySQL 写入磁盘的性能。
5.3.6 redo log是怎么写入磁盘的? 是直接写入吗?

redo log也不是直接写入磁盘的,而是有自己的缓存:redo log buffer。每当产生一条 redo log 时,会先写入到 redo log buffer,后续在持久化到磁盘。redo log buffer 默认大小 16 MB,可以通过 innodb_log_Buffer_size 参数动态的调整大小,增大它的大小可以让 MySQL 处理「大事务」是不必写入磁盘,进而提升写 IO 性能。

缓存在 redo log buffer 里的 redo log 还是在内存中,它什么时候刷新到磁盘?

主要有下面几个时机:

  • MySQL 正常关闭时
  • 当 redo log buffer 中记录的写入量大于 redo log buffer 内存空间的一半时,会触发落盘;
  • InnoDB 的后台线程每隔 1 秒,将 redo log buffer 持久化到磁盘。
  • 每次事务提交时都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘(由参数 innodb_flush_log_at_trx_commit 参数控制)。
5.3.7 redo log文件写满了怎么办?

默认情况下, InnoDB 存储引擎有 1 个重做日志文件组( redo log Group),「重做日志文件组」由有 2 个 redo log 文件组成。在重做日志组中,每个 redo log File 的大小是固定且一致的,假设每个 redo log File 设置的上限是 1 GB,那么总共就可以记录 2GB 的操作。

重做日志文件组是以**循环写**的方式工作的,从头开始写,写到末尾就又回到开头,相当于一个环形。所以 InnoDB 存储引擎会先写 ib_logfile0 文件,当 ib_logfile0 文件被写满的时候,会切换至 ib_logfile1 文件,当 ib_logfile1 文件也被写满时,会切换回 ib_logfile0 文件。

redo log 是循环写的方式,相当于一个环形,InnoDB 用 write pos 表示 redo log 当前记录写到的位置,用 checkpoint 表示当前要擦除的位置,如下图:

write pos 追上了 checkpoint,就意味着 redo log 文件满了,这时 MySQL 不能再执行新的更新操作,也就是说 MySQL 会被阻塞

此时会停下来将 Buffer Pool 中的脏页刷新到磁盘中,然后标记 redo log 哪些记录可以被擦除,接着对旧的 redo log 记录进行擦除,等擦除完旧记录腾出了空间,checkpoint 就会往后移动(图中顺时针),然后 MySQL 恢复正常运行,继续执行新的更新操作。

5.4 为什么需要binlog?

5.4.1 什么是binlog?

除了InnoDB存储引擎层生成的undo log和redo log,MySQL在完成一条更新操作后,Server层还会生成一条binlog,事务提交时会将该事务执行过程中产生的binlog统一写入binlog 文件

最开始 MySQL 里并没有 InnoDB 引擎,MySQL 自带的引擎是 MyISAM,但是 MyISAM 没有 crash-safe 的能力,binlog 日志只能用于归档。InnoDB 是另一个公司以插件形式引入 MySQL 的,既然只依靠 binlog 是没有 crash-safe 能力的,所以 InnoDB 使用 redo log 来实现 crash-safe 能力。

5.4.2 redo log和binlog的区别?
  • 适用对象不同:binlog是Server层实现的,所以引擎都可以使用;redo log是InnoDB引擎实现的。

  • 文件格式不同:binlog有三种格式statementrowmixed,区别如下:

    • statement:记录修改数据的SQL语句,相当于记录了逻辑操作,因此binlog可以成为逻辑日志;
    • row:记录数据最终被修改成什么样了,此时就不是逻辑日志了;
    • mixed:根据不同情况自动选择使用statement模式或row模式。
  • 写入方式不同:binlog 是追加写,写满一个文件就新创建一个文件继续写;redo log是循环追加写,日志空间大小固定,写满了就从头开始。

  • 用途不同:binlog主要用于备份恢复(因为是全量记录的)、主从复制;redo log用于掉电等故障恢复(只能存一部分)

如果不小心整个数据库的数据被删除了,能使用 redo log 文件恢复数据吗?

不可以使用 redo log 文件恢复,只能使用 binlog 文件恢复。

因为 redo log 文件是循环写,是会边写边擦除日志的,只记录未被刷入磁盘的数据的物理日志,已经刷入磁盘的数据都会从 redo log 文件里擦除。

binlog 文件保存的是全量的日志,也就是保存了所有数据变更的情况,理论上只要记录在 binlog 上的数据,都可以恢复,所以如果不小心整个数据库的数据被删除了,得用 binlog 文件恢复数据。

5.4.3 binlog什么时候刷盘?

事务执行过程中,先把日志写到 binlog cache(Server 层的 cache),事务提交的时候,再把 binlog cache 写到 binlog 文件中。对于一个事务,无论这个事务有多大(比如有很多条语句),也要保证一次性写入。这是为了保证事务的原子性。

在事务提交的时候,执行器把 binlog cache 里的完整事务写入到 binlog 文件中,并清空 binlog cache。如下图:

虽然每个线程有自己 binlog cache,但是最终都写到同一个 binlog 文件

  • 图中的 write,指的就是指把日志写入到 binlog 文件,但是并没有把数据持久化到磁盘,因为数据还缓存在文件系统的 page cache 里,write 的写入速度还是比较快的,因为不涉及磁盘 I/O。
  • 图中的 fsync,才是将数据持久化到磁盘的操作(刷盘),这里就会涉及磁盘 I/O,所以频繁的 fsync 会导致磁盘的 I/O 升高。

MySQL提供一个 sync_binlog 参数来控制数据库的 binlog 刷到磁盘上的频率:

  • sync_binlog = 0 的时候,表示每次提交事务都只 write,不 fsync,后续交**由操作系统决定何时将数据持久化到磁盘**;
  • sync_binlog = 1 的时候,表示每次**提交事务都会 write,然后马上执行 fsync**;
  • sync_binlog =N(N>1) 的时候,表示每次提交事务都 write,但**累积 N 个事务后才 fsync**。

5.5 为什么需要两阶段提交?

5.5.1 为什么需要两阶段提交?

事务提交后,redo log和binlog都需要持久化到磁盘,但是它们是独立的逻辑,可能出现**半成功(只有一个成功持久化了)**的状态,于是两份日志之间的逻辑不一致,存在两种情况:

  • 如果在将 redo log 刷入到磁盘之后, MySQL 突然宕机了,而 binlog 还没有来得及写入
  • 如果在将 binlog 刷入到磁盘之后, MySQL 突然宕机了,而 redo log 还没有来得及写入

redo log 影响主库的数据,binlog 影响从库的数据,所以 redo log 和 binlog 不一致会导致**主从环境中的数据不一致性**。

MySQL 为了避免出现两份日志之间的逻辑不一致的问题,使用了「两阶段提交」来解决,两阶段提交其实是分布式事务一致性协议,它可以保证多个逻辑操作要不全部成功,要不全部失败,不会出现半成功的状态

5.5.2 两阶段提交的过程是怎样的?

两阶段提交把单个事务的提交拆分成了 2 个阶段,分别是「准备(Prepare)阶段」和「提交(Commit)阶段」,每个阶段都由协调者(Coordinator)和参与者(Participant)共同完成。在 MySQL 的 InnoDB 存储引擎中,开启 binlog 的情况下,MySQL 会同时维护 binlog 日志与 InnoDB 的 redo log,为了保证这两个日志的一致性,MySQL 使用了内部 XA 事务,内部 XA 事务由 binlog 作为协调者,存储引擎是参与者

当客户端执行 commit 语句或者在自动提交的情况下,MySQL 内部开启一个 XA 事务分两阶段来完成 XA 事务的提交,如下图:

事务的提交包含两个阶段,本质上就是**将 redo log 的写入拆成了两个步骤:prepare 和 commit,中间再穿插写入binlog**:

  • 准备阶段(prepare):将内部XA事务的ID写入到redo log,同时将redo log对应的事务状态设置为prepare,然后将redo log持久化到磁盘;
  • 提交阶段(commit):将内部XA事务的ID写入到binlog,然后将binlog持久化到磁盘。将redo log的状态设置为commit,此时该状态不需要立马持久化到磁盘中,写入到缓存区就够了。
5.5.3 两阶段提交如何保证数据一致的?

下图中有时刻 A 和时刻 B 都有可能发生崩溃,不管是时刻 A(redo log 已经写入磁盘, binlog 还没写入磁盘),还是时刻 B (redo log 和 binlog 都已经写入磁盘,还没写入 commit 标识)崩溃,此时的 redo log 都处于 prepare 状态

MySQL 重启后会按顺序扫描 redo log 文件,碰到处于 prepare 状态的 redo log,就拿着 redo log 中的 XID 去 binlog 查看是否存在此 XID:

  • 如果 binlog 中没有当前内部 XA 事务的 XID,说明 redolog 完成刷盘,但是 binlog 还没有刷盘,则回滚事务。对应时刻 A 崩溃恢复的情况。
  • 如果 binlog 中有当前内部 XA 事务的 XID,说明 redolog 和 binlog 都已经完成了刷盘,则提交事务。对应时刻 B 崩溃恢复的情况。

这样就可以保证 redo log 和 binlog 这两份日志的一致性了。

5.5.4 两阶段提交存在什么问题?

两阶段提交虽然保证了两个日志文件的数据一致性,但是性能很差,主要有两个方面的影响:

  • 磁盘I/O次数高:每个事务提交都会进行两次刷盘,redo log刷盘和binlog刷盘;
  • 锁竞争激烈:在「多事务」的情况下,两阶段提交不能保证两者的提交顺序一致,因此,在两阶段提交的流程基础上,还需要加一个锁来保证提交的原子性,从而保证多事务的情况下,两个日志的提交顺序一致。
5.5.5 MySQL 磁盘 I/O 很高,有什么优化的方法?

事务在提交的时候,需要将 binlog 和 redo log 持久化到磁盘,那么如果出现 MySQL 磁盘 I/O 很高的现象,我们可以通过**控制一些参数(主要是指定redo log和binlog何时进行刷盘的参数)**,来 “延迟” binlog 和 redo log 刷盘的时机,从而降低磁盘 I/O 的频率。

资料参考

内容大多参考自:图解MySQL介绍 | 小林coding (xiaolincoding.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2039114.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis 高级篇(分布式缓存)

一、Redis分布式缓存 单点Redis问题: 数据丢失(实现Redis数据持久化)并发能力(搭建主从集群,实现读写分离)存储能力(搭建分片集群,利用插槽机制实现动态扩容)故障恢复能…

张宇36讲重点勾划+30天保底120带刷计划

先说结论,张宇36讲不适合目标100分的同学去用! 张宇36讲,有一个问题,就是内容太多了: 页数达到了1200多页。这个恐怖的内容量,恐怕没有人可以看完。 但是张宇老师一开始说,不会删减任何内容&…

TinyWebserver的复现与改进(5):HTTP报文的解析与响应

GitHub - yzfzzz/MyWebServer: Linux高并发服务器项目,参考了TinyWebServer,将在此基础上进行性能改进与功能增加。为方便读者学习,附带详细注释和博客! TinyWebserver的复现与改进(1):服务器环…

模型训练与验证minicpm-v

minicpm-v 模型进行微调并进行验证 训练使用混合数据集进行训练,对minicpm-V进行lora微调,微调后使用llama3_1对输出结果与标签值进行比对,计算准确率。 验证代码为: # URL https://swift.readthedocs.io/zh-cn/latest/LLM/VLLM%E6%8E%A8%…

PMP到底有什么用?

PMP 就是项目管理证书,全称是项目管理专业人士资格认证,对于一个在项目管理岗位混迹五年的老油条来说,PMP 证书是敲开项目管理岗位的第一块砖,每年考 PMP 的人都很多,要是 PMP 证书没有价值,还会有那么多人…

Tomcat下载安装文档

简介 Tomcat服务器软件是一个免费的开源的web应用服务器。是Apache软件基金会的一个核心项目。由Apache,Sun和其他一些公司及个人共同开发而成。 由于Tomcat只支持Servlet/JSP少量JavaEE规范,所以是一个开源免费的轻量级Web服务器。 JavaEE规范&#x…

Java IO流使用方法 (常见方法)

Java系列文章目录 补充内容 Windows通过SSH连接Linux 第一章 Linux基本命令的学习与Linux历史 文章目录 Java系列文章目录一、前言二、学习内容:三、问题描述四、解决方案:4.1 File 的使用4.2 防止乱码问题 五、总结:5.1 学习总结&#xff1…

IPFS、IPNS 网站部署

目录 概念IPFS 网站IPNS 网站网站迁移到 IPFS/IPNS1. 连接 Github2. 选择仓库3. 配置 Build4. 绑定域名5. 绑定 IPNS 域名6. 检查 DNSLink概念 以 https://bhitdao.com/ 为例 IPFS 网站 链接为 Hash: ipfs://bafybeifxwlnnvuhbxiszvs2kkckxkxfy36chzoy2f7nrempkpznxrudbsm/…

开源AI智能名片微信小程序:以人性洞察与资源优化为驱动的社群营销新策略

摘要:随着科技的飞速发展,特别是人工智能(AI)技术的广泛应用,传统营销模式正经历着前所未有的变革。本文旨在探讨开源AI智能名片微信小程序如何凭借其独特的功能特性,结合人性洞察、需求解决、资源优化以及…

CLAMP-1

一、信息收集 1、主机发现 nmap 192.168.236.0/24 2、端口扫描 nmap 192.168.236.173 -p- -A 3、目录扫描 dirb http://192.168.236.173 二、漏洞探测 访问80端口 访问 /nt4stopc/ 下面有一些问题,提示必须收集答案 都是一些判断题,对与错对应1与0&…

SQL注入(原理、分类、union、POST注入)

目录 【学习目标、重难点知识】 【学习目标】 【重难点知识】 SQL注入简介 SQL注入原理 SQL注入类型 MySQL与SQL注入的相关知识 information_schema 数据库的结构 数据库查询语句 limit的用法 需要记住的几个函数 注释符号 SQL注入探测方法 SQL注入漏洞攻击流程…

gerrit的使用

配置SSH密钥 用记事本打开电脑里以下文件,复制内容 在gerrit代码库设置里找到菜单 SSH Keys,将以上复制的内容粘贴到New SSH Key处,点击ADD NEW SSH KEY即可。 克隆代码 git clone ssh://..... 下载commit-msg文件 复制代码下载地址里的…

java之校验QQ号是否正确以及如何用正则表达式进行优化

public class RegexDemo {public static void main(String[] args) {String qq"123456789";System.out.println(checkQQ(qq));}public static boolean checkQQ(String qq){//规则:6位到20位之内,0不能在开头,必须全部是数字//核心思想://先把异常数据过滤//下面的…

外部排序(败者树、置换-选择排序、最佳归并树)

外部排序可能会考查相关概念、方法和排序过程,外部排序的算法比较复杂,不会在算法设计上进行考查。 一、外部排序的基本概念与方法 外部排序指待排序文件较大,内存一次放不下,需存放在外存的文件的排序。 1. 基本概念 在许多应用…

python入门之命令提示符和文本创建.py文件

1.命令提示符 程序 快捷键:windowsR 在安装完python以后,可以直接在命令提示符程序上敲代码进行初步尝试。 python解释器 计算机是不认识python代码的,计算机只能识别0和1这个二进制的数,所以需要一个翻译官“python翻译器”。 …

【Linux系列】known_hosts详解

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【Linux网络(一)】Socket编程

文章目录 1. 预备知识1.1 认识端口号1.2 初识TCP协议1.3 初识UDP协议1.4 网络字节序1.5 socket编程接口1.5.1 套接字编程的种类1.5.2 sockaddr结构体1.5.3 socket 常见API1.5.4 地址转换函数 2. 编写UDP服务器与客户端2.1 UDP服务器的创建2.2 UDP服务器接收/发送数据2.3 补充知…

动态规划——背包问题(01背包、完全背包,分组背包与二进制优化)

本蒟蒻写二进制优化开始的时候写昏了,并且昏了一下午。但好在有神犇救命,这篇博客才得以面世——躲着人群 一、01背包 概述: 其常见的问题形式为:给出n个物品,每个物品有对应的价值和体积。给出背包容量后求不超过背…

硬件开发流程

1.看原理图找引脚 --开发板上找到LED,查看丝印 --在原理图中根据丝印找到对应的器件 --找到对应的引脚 2.配置引脚功能(对应硬件的工作原理) 3.控制对应的引脚(或控制器) volatile: 易失性修饰符

qtpdfium 多平台编译

源码下载地址:https://codeload.github.com/kkzi/qpdf/zip/2681018e300738d6da9a9f89f06c93fc3ef17831 参考:https://blog.51cto.com/u_2194662/5256871 开发环境:QT 5.15.2 1. windows下编译: 编译环境:vs2019qt5.15…