携程二面:讲讲 MySQL 中的 WAL 策略和 CheckPoint 技术
前段时间我在准备暑期实习嘛,这是当时面携程的时候二面的一道问题,我一脸懵逼,赶紧道歉,不好意思不知道没了解过,面试官又解释说 redo log,我寻思着 redo log 我知道啊,WAL 是啥?给面试官整无语了(滑稽),为我当时的无知道歉。后来回去百度了一下才知道,最近又在丁奇大佬的《MySQL 实战 45 讲》 中看到了 WAL,遂来写篇文章总结下。
InnoDB 体系架构
在说 WAL 之前,有必要简单介绍下 InnoDB 存储引擎的体系架构,方便我们理解下文,并且 redo log 也是 InnoDB 存储引擎所特有的。
如下图,InnoDB 存储引擎由内存池和一些后台线程组成:
内存池
先来解释下内存池。
首先,我们需要知道,InnoDB 存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可将其视为基于磁盘的数据库系统(Disk-base Database),在这样的系统中,众所周知,由于 CPU 速度与磁盘速度之间的不匹配,通常会使用缓冲池技术来提高数据库的整体性能。
所以这里的内存池也被称为缓冲池(简单理解为缓存就好了)。
具体来说,缓冲池其实就是一块内存区域,在 CPU 与磁盘之间加入内存访问,通过内存的速度来弥补磁盘速度较慢对数据库性能的影响。
拥有了缓冲池后,“读取页” 操作的具体步骤就是这样的:
- 首先将从磁盘读到的页存放在缓冲池中
- 下一次再读相同的页时,首先判断该页是否在缓冲池中。若在缓冲池中,称该页在缓冲池中被命中,直接读取该页。否则,读取磁盘上的页。
“修改页” 操作的具体步骤就是这样的:
- 首先修改在缓冲池中的页;然后再以一定的频率刷新到磁盘上。
所谓 ”脏页“ 就发生在修改这个操作中,如果缓冲池中的页已经被修改了,但是还没有刷新到磁盘上,那么我们就称缓冲池中的这页是 ”脏页“,即缓冲池中的页的版本要比磁盘的新。
至此,综上所述,我们可以得出这样的结论:缓冲池的大小直接影响着数据库的整体性能。
后台线程
后台线程其实最大的作用就是用来完成 “将从磁盘读到的页存放在缓冲池中” 以及 “将缓冲池中的数据以一定的频率刷新到磁盘上” 这俩个操作的,当然了,还有其他的作用。以下是《MySQL 技术内幕:InnoDB 存储引擎 - 第 2 版》对于后台线程的描述:
后台线程的主要作用就是刷新内存池中的数据,保证内存池中缓存的是最近的数据;此外将已修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常的情况下 InnoDB 能恢复到正常运行状态。
另外,InnoDB 存储引擎是多线程的模型,也就是说它拥有多个不同的后台线程,负责处理不同的任务。这里简单列举下几种不同的后台线程:
- Master Thread:主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性
- IO Thread:在 InnoDB 存储引擎中大量使用了 AIO(Async IO)来处理写 IO 请求,这样可以极大提高数据库的性能。IO Thread 的工作主要是负责这些 IO 请求的回调(call back)处理
- Purge Thread:回收已经使用并分配的 undo 页
- Page Cleaner Thread:将之前版本中脏页的刷新操作都放入到单独的线程中来完成。其目的是为了减轻原 Master Thread 的工作及对于用户查询线程的阻塞,进一步提高 InnoDB 存储引擎的性能
redo log 与 WAL 策略
上文我们提到,当缓冲池中的某页数据被修改后,该页就被标记为 ”脏页“,脏页的数据会被定期刷新到磁盘上。
倘若每次一个页发生变化,就将新页的版本刷新到磁盘,那么这个开销是非常大的。并且,如果热点数据都集中在某几个页中,那么数据库的性能将变得非常差。另外,如果在从缓冲池将页的新版本刷新到磁盘时发生了宕机,那么这个数据就不能恢复了。
所以,为了避免发生数据丢失的问题,当前事务数据库系统(并非 MySQL 所独有)普遍都采用了 WAL(Write Ahead Log
,预写日志)策略:即当事务提交时,先写重做日志(redo log),再修改页(先修改缓冲池,再刷新到磁盘);当由于发生宕机而导致数据丢失时,通过 redo log 来完成数据的恢复。这也是事务 ACID 中 D(Durability 持久性)的要求。
有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe。
举个简单的例子,假设你非常热心且 rich 的,借出去了很多钱,但是你非常 old school,不会使用电子设备并且记性不太好,所以你用一个小本本记下了所有欠你钱的人的名字和具体金额。这样,别人还你钱的时候,你就翻出你的小本本,一页页地找到他的名字然后把这次还的钱扣除掉。
但是呢,其实你平常是非常忙碌的,没办法随时随地翻小本本做记录,因此你就想出了一个主意:每当有人还你钱的时候,你就在一张白纸上记下来,然后挑个时间对照小本本把白纸上的账目都给清了。
这就是 WAL。白纸就是 redo log,小本本就是磁盘。
当然了,redo log 可不是白纸这么简单,一张用完了换一张就行了,这里有必要详细解释下。
每个 InnoDB 存储引擎至少有 1 个重做日志文件组( redo log group),每个文件组下至少有 2 个重做日志文件(redo log file),默认的话是一个 redo log group,其中包含 2 个 redo log file:ib_logfile0
和 ib_logfile1
。
一般来说,为了得到更高的可靠性,用户可以设置多个镜像日志组(mirrored log groups),将不同的文件组放在不同的磁盘上,以此提高 redo log 的高可用性。在日志组中每个 redo log file 的大小一致,并以循环写入的方式运行。
所谓循环写入,也就是为啥我们说 redo log 不像白纸那样用完一张换一张就行,举个例子,如下图,一个 redo log group,包含 3 个 redo log file:
InnoDB 存储引擎会先写 redo log file 0,当 file 0 被写满的时候,会切换至 redo log file 1,当 file 1 也被写满时,会切换到 redo log file 2 中,而当 file 2 也被写满时,会再切换到 file 0 中。
可以看出,redo log file 的大小设置对于 InnoDB 存储引擎的性能有着非常大的影响:
- redo log file 不能设置得太大,如果设置得很大,在恢复时可能需要很长的时间
- redo log file 又不能设置得太小了,否则可能导致一个事务的日志需要多次切换重做日志文件
CheckPoint 技术
有了 redo log 就可以高枕无忧了吗?显然不是这么简单,我们仍然面临这样 3 个问题:
1)缓冲池不是无限大的,也就是说不能没完没了的存储我们的数据等待一起刷新到磁盘
2)redo log 是循环使用而不是无限大的(也许可以,但是成本太高,同时不便于运维),那么当所有的 redo log file 都写满了怎么办?
3)当数据库运行了几个月甚至几年时,这时如果发生宕机,重新应用 redo log 的时间会非常久,此时恢复的代价将会非常大。
因此 Checkpoint 技术的目的就是解决上述问题:
- 缓冲池不够用时,将脏页刷新到磁盘
- redo log 不可用时,将脏页刷新到磁盘
- 缩短数据库的恢复时间
所谓 CheckPoint 技术简单来说其实就是在 redo log file 中找到一个位置,将这个位置前的页都刷新到磁盘中去,这个位置就称为 CheckPoint(检查点)。
针对上面这三点我们依次来解释下:
1)缩短数据库的恢复时间:当数据库发生宕机时,数据库不需要重做所有的日志,因为 Checkpoint 之前的页都已经刷新回磁盘。故数据库只需对 Checkpoint 后的 redo log 进行恢复就行了。这显然大大缩短了恢复的时间。
2)缓冲池不够用时,将脏页刷新到磁盘:所谓缓冲池不够用的意思就是缓冲池的空间无法存放新读取到的页,这个时候 InnoDB 引擎会怎么办呢?LRU 算法。 InnoDB 存储引擎对传统的 LRU 算法做了一些优化,用其来管理缓冲池这块空间。
总的思路还是传统 LRU 那套,具体的优化细节这里就不再赘述了:即最频繁使用的页在 LRU 列表(LRU List)的前端,最少使用的页在 LRU 列表的尾端;当缓冲池的空间无法存放新读取到的页时,将首先释放 LRU 列表中尾端的页。这个被释放出来(溢出)的页,如果是脏页,那么就需要强制执行 CheckPoint,将脏页刷新到磁盘中去。
3)redo log 不可用时,将脏页刷新到磁盘:
所谓 redo log 不可用就是所有的 redo log file 都写满了。但事实上,其实 redo log 中的数据并不是时时刻刻都是有用的,那些已经不再需要的部分就称为 ”可以被重用的部分“,即当数据库发生宕机时,数据库恢复操作不需要这部分的 redo log,因此这部分就可以被覆盖重用(或者说被擦除)。
举个例子来具体解释下:一组 4 个文件,每个文件的大小是 1GB,那么总共就有 4GB 的 redo log file 空间。write pos 是当前 redo log 记录的位置,随着不断地写入磁盘,write pos 也不断地往后移,就像我们上文说的,写到 file 3 末尾后就回到 file 0 开头。CheckPoint 是当前要擦除的位置(将 Checkpoint 之前的页刷新回磁盘),也是往后推移并且循环的:
write pos 和 CheckPoint 之间的就是 redo log file 上还空着的部分,可以用来记录新的操作。如果 write pos 追上 CheckPoint,就表示 redo log file 满了,这时候不能再执行新的更新,得停下来先覆盖(擦掉)一些 redo log,把 CheckPoint 推进一下。
综上所述,Checkpoint 所做的事情无外乎是将缓冲池中的脏页刷新到磁盘。不同之处在于每次刷新多少页到磁盘,每次从哪里取脏页,以及什么时间触发 Checkpoint。在 InnoDB 存储引擎内部,有两种 Checkpoint,分别为:
- Sharp Checkpoint:发生在数据库关闭时将所有的脏页都刷新回磁盘,这是默认的工作方式,参数
innodb_fast_shutdown=1
- Fuzzy Checkpoin:InnoDB 存储引擎内部使用这种模式,只刷新一部分脏页,而不是刷新所有的脏页回磁盘。关于 Fuzzy CheckPoint 具体的情况这里就不再赘述了。
有了 bin log 为什么还需要 redo log?
前文我们讲过,MySQL 架构可以分成俩层,一层是 Server 层,它主要做的是 MySQL 功能层面的事情;另一层就是存储引擎,负责存储与提取相关的具体事宜。
redo log 是 InnoDB 引擎特有的日志,而 Server 层也有自己的日志,包括错误日志(error log)、二进制日志(binlog)、慢查询日志(slow query log)、查询日志(log)。
其他三个日志顾明思意都挺好理解的,需要解释的就是 binlog(二进制日志,binary log),它记录了对 MySQL 数据库执行更改的所有操作,但是不包括 SELECT
和 SHOW
这类操作,因为这类操作对数据本身并没有修改。也就是说,binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如 “给 ID=1 这一行的 a 字段加 1”。
可以看出来,binlog 日志只能用于归档,因此 binlog 也被称为归档日志,显然如果 MySQL 只依靠 binlog 等这四种日志是没有 crash-safe 能力的,所以为了弥补这种先天的不足,得益于 MySQL 可插拔的存储引擎架构,InnoDB 开发了另外一套日志系统 — 也就是 redo log 来实现 crash-safe 能力。
这就是为什么有了 bin log 为什么还需要 redo log 的答案。
回顾下 redo log 存储的东西,可以发现 redo log 是物理日志,记录的是 “在某个数据页上做了什么修改”。
另外,还有一点不同的是:binlog 是追加写入的,就是说 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志;而 redo log 是循环写入的。
关注公众号 | 飞天小牛肉,即时获取更新
- 博主东南大学硕士在读,携程 Java 后台开发暑期实习生,利用课余时间运营一个公众号『 飞天小牛肉 』,2020/12/29 日开通,专注分享计算机基础(数据结构 + 算法 + 计算机网络 + 数据库 + 操作系统 + Linux)、Java 技术栈等相关原创技术好文。本公众号的目的就是让大家可以快速掌握重点知识,有的放矢。关注公众号第一时间获取文章更新,成长的路上我们一起进步
- 并推荐个人维护的开源教程类项目: CS-Wiki(Gitee 推荐项目,现已累计 1.8k+ star), 致力打造完善的后端知识体系,在技术的路上少走弯路,欢迎各位小伙伴前来交流学习 ~
- 如果各位小伙伴春招秋招没有拿得出手的项目的话,可以参考我写的一个项目「开源社区系统 Echo」Gitee 官方推荐项目,目前已累计 900+ star,基于 SpringBoot + MyBatis + MySQL + Redis + Kafka + Elasticsearch + Spring Security + ... 并提供详细的开发文档和配套教程。公众号后台回复 Echo 可以获取配套教程,目前尚在更新中。
携程二面:讲讲 MySQL 中的 WAL 策略和 CheckPoint 技术的更多相关文章
- 【MySQL】MySQL中针对大数据量常用技术_创建索引+缓存配置+分库分表+子查询优化(转载)
原文地址:http://blog.csdn.net/zwan0518/article/details/11972853 目录(?)[-] 一查询优化 1创建索引 2缓存的配置 3slow_query_ ...
- MySQL 中的WAL机制
本文主要概括的是 WAL 机制涉及的三种日志,具体与其他组件的联系.执行可查看 一条 sql 的执行过程详解 .MySQL中的事务原理和锁机制 . 是什么 WAL,全称是Write-Ahead Log ...
- 携程实时大数据平台演进:1/3 Storm应用已迁到JStorm
携程大数据平台负责人张翼分享携程的实时大数据平台的迭代,按照时间线介绍采用的技术以及踩过的坑.携程最初基于稳定和成熟度选择了Storm+Kafka,解决了数据共享.资源控制.监控告警.依赖管理等问题之 ...
- MySQL中如何查看“慢查询”,如何分析执行SQL的效率?
一.MySQL数据库有几个配置选项可以帮助我们及时捕获低效SQL语句 1,slow_query_log这个参数设置为ON,可以捕获执行时间超过一定数值的SQL语句. 2,long_query_time ...
- 如何查找MySQL中查询慢的SQL语句
如何查找MySQL中查询慢的SQL语句 更多 如何在mysql查找效率慢的SQL语句呢?这可能是困然很多人的一个问题,MySQL通过慢查询日志定位那些执行效率较低的SQL 语句,用--log-slow ...
- 如何查找MySQL中查询慢的SQL语句(转载)
转载自https://www.cnblogs.com/qmfsun/p/4844472.html 如何在mysql查找效率慢的SQL语句呢?这可能是困然很多人的一个问题,MySQL通过慢查询日志定位那 ...
- 景点API支持查询携程旅游门票景点详情
门票景点详情,景点api支持查询携程旅游门票景点详情. 接口名称:景点api 接口平台:开放api 接口地址:http://api2.juheapi.com/xiecheng/senicspot/ti ...
- 一、MySQL中的索引 二、MySQL中的函数 三、MySQL数据库的备份和恢复 四、数据库设计和优化(重点)
一.MySQL中的索引###<1>索引的概念 索引就是一种数据结构(高效获取数据),在mysql中以文件的方式存在.存储建立了索引列的地址或者指向. 文件 :(以某种数据 结构存放) 存放 ...
- 一、TCL事务控制语言 二、MySQL中的约束 三、多表查询(重点) 四、用户的创建和授权 五、MySQL中的索引
一.TCL事务控制语言###<1>事务的概念 事务是访问并可能更新数据库中各种数据项的执行单元. 事务是一条SQL语句,一组SQL语句,或者整个程序. 事务是恢复和并发控制的基本单位. 事 ...
随机推荐
- NIOSII IDE在WIN7下 couldn't allocate heap
首先,所有的文件夹都不能有空格和中文 其次,出现这些SB错误 make -s all includes 3 [main] ? (3732) c:\altera\91\quartus\bin\cygwi ...
- Let's go!
第一次开通博客 心情还是很激动的,而且做出了这么好看的页面虽然都是用的别人的组件,自己不是很知道原理但是也很开心,以后会将自己学习的东西写成笔记发在上面
- 佳能m62套机5500 佳能EOS M50 M6 MARK2 II二代 最低到过5800
佳能m62套机5500 佳能EOS M50 M6 MARK2 II二代
- 关于jmeter线程组和循环次数的设置
初始设置:设置线程数 n = 80,循环次数a = 1,ramp-up period=5 一 计算最后一个线程的生成时间(last) 总共生成80个线程,总共需要5秒,每秒钟会启动16个线程,所以,第 ...
- Scala 神奇的下划线 _
引言 在 Scala 中,下划线 _ 有很多种用法,作为 Scala 初学者也经常被下划线 _ 搞得晕头转向,下面是对 Scala 中下划线 _ 使用的简单总结~ 导包时, 下划线 _ 表示引用多个方 ...
- shell基础之更改IP
要求: 显示所有网卡及其对应的IP地址,并可更改IP相关内容使其生效. 1 #!/bin/bash 2 #获取本机网卡和IP 3 while : 4 do 5 network=$(ifconfig | ...
- Linux服务之DNS服务篇
一.DNS服务概述 DNS(Domain Name System)域名系统,在TCP/IP 网络中有非常重要的地位,能够提供域名与IP地址的解析服务. DNS 是一个分布式数据库,命名系统采用层次的逻 ...
- centos 7编译32位软件的问题
centos 7默认安装的gcc 为64位,所以在编译32位软件时需要用到32位的gcc库,于是可以增加glibc 32位库: sudo yum -y install glibc-bevel.i386
- 05丨实验:安装MongoDB
https://docs.mongodb.com/manual/tutorial/install-mongodb-on-red-hat/ 源码安装 export PATH=$PATH:/data/mo ...
- 安装T4环境
Install-Package Microsoft.VisualStudio.TextTemplating.14.0 -Version 14.3.25407