持续创造,加快成长!这是我参加「日新计划 · 10 月更文应战」的第 9 天,点击检查活动概况
大家好,我是melo,一名大三后台操练生,最近断断续续冷面翻炒redis、MySQL、sso,知识大杂烩归于是hhh
-
MySQL高档篇专栏
-
SSO单点登录专栏
-
Redis入门与实战
🍳引言
日志日志,在咱们平时开发中首要的用处在于监控、备份,但在MySQL中,日志的功用远远不止这些,别离有用于记载的慢查询日志,回滚版别的undolog,宕机康复的redolog、全量备份的binlog等等,而这些日志,也刚好是咱们业务的原理
🎏本篇速览脑图
🎯undolog — 原子性
回滚日志,记载数据被修正前的信息,归于逻辑日志
- 什么是逻辑日志?
比方咱们履行一条delete句子,undolog里面记载的是相反的操作insert记载【相当于存放的是操作逻辑句子,而不是数据】
🤷♂️逻辑日志优点
- 比方全表更新,假如是物理日志,咱们需求把全表的数据都存下来
- 若是逻辑日志,只需求存放一条句子就能够康复了
undolog用处
回滚
一个业务在履行进程中,在还没有提交业务之前,假如MySQL 产生了溃散,要怎样回滚到业务之前的数据呢?
- 在业务没提交之前,MySQL 会先记载更新前的数据到 undo log 日志文件里面,当业务回滚时,能够利用 undo log 来进行回滚。
版别链
相似一个链表,经过回滚指针,串联起来
一条记载的每一次更新操作产生的 undo log 格局都有一个 roll_pointer 指针和一个 trx_id 业务id:
- 经过 trx_id 能够知道该记载是被哪个业务修正的;
- 经过 roll_pointer 指针能够将这些 undo log 串成一个链表,这个链表就被称为版别链;
MVCC
经过 ReadView + undo log 完成 MVCC
详细看我的另一篇博客MVCC
🎯redolog — 耐久性
重做日志,物理记载
redo log 是物理日志,记载内容是“在某个数据页上做了什么修正”,归于 InnoDB 存储引擎。
前置知识– Buffer Pool
Buffer Pool是很经典的缓存池,其间又以Page为单位
- 闲暇页
- 洁净页
- 脏页【相似操作体系中,修正位为1】
正常同步
首要咱们要知道,每次业务提交后,首要是跟 Buffer pool 打交道
- 若缓存中没有咱们要操作的数据【相似缺页中断,MySQL 中数据是以页为单位】,则会发动后台线程,去磁盘中拉取过来
- 之后就都是直接操作缓存了
- 现在缓存的内容更新好了,但磁盘的内容仍是旧的,何时更新到磁盘呢?
咱们或许会有如下计划:
- 每隔一段时刻,就同步到磁盘
弊端
每次更新都要写入磁盘,磁盘IO很高
假如每一次的更新操作都需求写进磁盘,然后磁盘也要找到对应的那条记载,然后再更新,整个进程 IO 本钱、查找本钱都很高。
不如先把更新的操作,记载在redolog日志里面,之后在恰当的时分,再一同刷盘!【而不是每次更新就一条一条的刷】
这便是MySQL的 WAL 技能,(Write-Ahead Logging) 先写进日志,再刷入磁盘
buffer挂掉
一般状况下都没什么问题,但或许在履行某次更新操作的时分,buffer挂掉了呢?此刻同步进程就GG了,导致缓存不一致
- 因而,为了双保险,咱们还会把数据相关的改变【物理修正】存到redolog里面,用来完成业务的耐久性【宕机后还能查询redolog,来进行康复】
redolog保险出场
当业务提交时,会把“在某个数据页上做了什么修正”记载到重做日志缓存(redo log buffer)里,接着刷盘到 redo log 文件里。
缓存redolog — Log Buffer
刷盘机遇
MySQL 正常关闭时
当 redo log buffer 中记载的写入量大于 redo log buffer 内存空间的一半时,会触发落盘
每次业务提交时【详细不同战略不一样】
一般状况下,业务一提交就会进行刷盘操作。
InnoDB 存储引擎为 redo log 的刷盘战略供给了 innodb_flush_log_at_trx_commit 参数,它支撑三种战略:
- 0 :设置为 0 的时分,表明每次业务提交时不进行刷盘操作
- 1 :设置为 1 的时分,表明每次业务提交时都将进行刷盘操作(默许值)
- 2 :设置为 2 的时分,表明每次业务提交时都只把 redo log buffer 内容写入 page cache
后台线程
InnoDB 存储引擎有一个后台线程,每隔1 秒,就会把 redo log buffer 中的内容写到文件体系缓存(page cache),然后调用 fsync 刷盘。
不同参数对应状况
innodb_flush_log_at_trx_commit 设置为不同值时,别离是什么时分将 redo log 写入磁盘?
- 参数0:业务提交时不刷盘,而是靠后台线程,把缓存在 redo log buffer 中的 redo log ,经过调用 write() 写到操作体系的 Page Cache,然后调用 fsync() 耐久化到磁盘。所以参数为 0 的战略,MySQL 进程的溃散会导致上一秒钟一切业务数据的丢掉;
- 参数1:只需业务提交成功,redo log记载就一定在硬盘里,不会有任何数据丢掉。
假如业务履行期间MySQL挂了或宕机,这部分日志丢了,可是业务并没有提交,所以日志丢了也不会有损失!!
- 参数2:只需业务提交成功,redo log buffer中的内容都会写入文件体系缓存(page cache)。调用 fsync,将缓存在**操作体系中 Page Cache **里的 redo log 耐久化到磁盘。
假如仅仅只是MySQL挂了不会有任何数据丢掉,只需操作体系溃散的状况下,上一秒钟一切业务数据才或许丢掉。
怎么选择参数
-
数据安全性:参数 1 > 参数 2 > 参数 0
-
写入功能:参数 0 > 参数 2> 参数 1
-
在一些对数据安全性要求比较高的场景中,显然 innodb_flush_log_at_trx_commit 参数需求设置为 1。
-
在一些能够容忍数据库溃散时丢掉 1s 数据的场景中,咱们能够将该值设置为 0,这样能够明显地减少日志同步到磁盘的 I/O 操作。
-
安全性和功能折中的计划便是参数 2,尽管参数 2 没有参数 0 的功能高,可是数据安全性方面比参数 0 强,因为参数 2 只需操作体系不宕机,即便数据库溃散了,也不会丢掉数据,一同功能方便比参数 1 高。
优点
- redolog是文件追加的方式,而缓存同步到磁盘是随机IO
能够说这是 WAL 技能的别的一个优点:MySQL 的写操作从磁盘的「随机写」变成了「次序写」
总结
redolog的用处:
- 完成业务的耐久性
- 将写操作从磁盘的「随机写」变成了「次序写」
🎈🎈redolog日志文件组 — 应对写满的状况
硬盘上存储的 redo log 日志文件不止一个,而是以一个日志文件组的方式呈现的,每个的redo日志文件巨细都是一样的。、、、间断这种做做做做做做做做做做做做做做做做做做做做做做做做做做做做错错错
比方能够装备为一组4个文件,每个文件的巨细是 1GB,整个 redo log 日志文件组能够记载4G的内容。
它选用的是环形数组方式,从头开端写,写到结尾又回到头循环写,如下图所示。
除了写入,咱们还需求擦除【redolog刷盘到磁盘后,就能够进行擦除了】,因而咱们用两个指针来表明:
- write pos:当时记载写到的方位
- checkpoint:当时要擦除的方位
跟循环队列的设计有些神似,保护两个指针,head跟tail一般
这两个指针把整个环形划成了几部分
- write pos – checkpoint:待写入的部分
- checkpoint – write pos:还未刷入磁盘的记载
若write pos追上了checkpoint,阐明没有空间写入了【跟咱们队列满了是一样的状况】,这时分不能再写入新的 redo log 记载,MySQL 得停下来,清空一些记载,把 checkpoint 推动一下。
🎯binlog
redo log 它是物理日志,记载内容是“在某个数据页上做了什么修正”,归于 InnoDB 存储引擎。
而 binlog 是逻辑日志,记载内容是句子的原始逻辑,相似于“给 ID=2 这一行的 c 字段加 1”,归于MySQL Server 层。
不管用什么存储引擎,只需产生了表数据更新,都会产生 binlog 日志。
与redolog差异
这两个日志有四个差异
1、适用目标不同:
- binlog 是 MySQL 的 **Server 层 **完成的日志,一切存储引擎都能够运用;
- redo log 是 Innodb 存储引擎完成的日志;
2、文件格局不同:
-
binlog 有 3 种格局类型,别离是 STATEMENT(默许格局)、ROW、 MIXED,差异如下:
- STATEMENT:每一条修正数据的 SQL 都会被记载到 binlog 中(相当于记载了逻辑操作,所以针对这种格局, binlog 能够称为逻辑日志),主从复制中 slave 端再依据 SQL 句子重现。
但 STATEMENT 有动态函数的问题
比方:
update_time=now()//这里会获取当时体系时刻
直接履行会导致与原库的数据不一致,因而咱们引进了row
- ROW:记载行数据终究被修正成什么样了(这种格局的日志,就不能称为逻辑日志了),不会呈现 STATEMENT 下动态函数的问题。
但也有缺陷
每行数据的改变结果都会被记载,比方:
update user set name ='melo';
更新多少行数据就会产生多少条记载,使 binlog 文件过大,而在 STATEMENT 格局下只会记载一个 update 句子而已;
- MIXED:这是现在MySQL默许的日志格局,即混合了STATEMENT 和 ROW两种格局。默许状况下选用STATEMENT,可是在一些特别状况下选用ROW来进行记载。MIXED 格局能尽量利用两种模式的优点,而避开他们的缺陷。
MySQL会判别这条SQL句子是否或许引起数据不一致,假如是,就用row格局,不然就用statement格局。
- redo log 是物理日志,记载的是在某个数据页做了什么修正。
3、写入方式不同:
- binlog 是追加写,写满一个文件,就创立一个新的文件继续写,不会掩盖曾经的日志,保存的是全量的日志。
- redo log 是循环写,日志空间巨细是固定的,悉数写满就从头开端,保存未被刷入磁盘的脏页日志。
4、用处不同:
- binlog 用于备份康复、主从复制;
- redo log 用于掉电等故障康复。
假如不小心整个数据库的数据被删除了,能运用 redo log 文件康复数据吗?
不能够运用 redo log 文件康复,只能运用 binlog 文件康复。
因为 redo log 文件是循环写,是会边写边擦除日志的,只记载未被刷入磁盘的数据的物理日志,现已刷入磁盘的数据都会从 redo log 文件里擦除。
binlog 文件保存的是全量的日志,也便是保存了一切数据改变的状况,理论上只需记载在 binlog 上的数据,都能够康复,所以假如不小心整个数据库的数据被删除了,得用 binlog 文件康复数据。
写入机遇
业务履行进程中,先把日志写到 binlog cache(Server 层的 cache),业务提交的时分,再把 binlog cache 写到 binlog 文件中。
因为一个业务的binlog不能被拆开,不管这个业务多大,也要确保一次性写入,所以体系会给每个线程分配一个块内存作为binlog cache。
参数 binlog_cache_size 用于操控单个线程内 binlog cache 所占内存的巨细。假如超越了这个参数规则的巨细,就要暂存到磁盘(Swap)。
什么时分 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。
在MySQL中体系默许的设置是 sync_binlog = 0,也便是不做任何强制性的磁盘刷新指令,这时分的功能是最好的,可是危险也是最大的。因为一旦主机【指的是操作体系】产生反常重启,还没耐久化到磁盘的数据就会丢掉。
而当 sync_binlog 设置为 1 的时分,是最安全可是功能损耗最大的设置。因为当设置为 1 的时分,即便主机产生反常重启,最多丢掉一个业务的 binlog,而现已耐久化到磁盘的数据就不会有影响,不过便是对写入功能影响太大。
假如能容许少数业务的 binlog 日志丢掉的危险,为了进步写入的功能,一般会 sync_binlog 设置为 100~1000 中的某个数值。
🎈两阶段提交
🎐为何需求两阶段提交
首要是因为:redolog影响的是主库,而binlog触及主从复制,影响的是从库??
也有说用binlog来作为备份康复,康复后的结果或许会跟主库不一样
履行一条更新句子时,此刻宕机了,有两种状况:
- redolog刷盘成功,但binlog没有
- 主库因为有redolog的存在,能够康复,而binlog中并没有相关的更新句子,导致从库中丢掉了本次更新
- binlog刷盘成功,但redolog没有
- 从库因为有binlog的存在,记载了更新,binlog 会被复制到从库,从库履行了这条更新句子,而主库的redolog还没刷盘成功,导致溃散后没法康复,主库丢掉了本次更新
XA业务、两阶段提交的详细流程
第一阶段
这里是业务管理器,相当于一个总的管理者,其担任管理参加业务的多个部分【比方这里的redolog,binlog】,放到分布式体系里面,或许是两个不同的体系
应用程序调用了业务管理器的提交办法,尔后第一阶段分为两个进程:
业务管理器通知参加该业务的各个资源管理器,通知他们开端预备业务。
资源管理器接收到消息后开端预备阶段,写好业务日志并履行业务,但不提交,然后将是否就绪的消息回来给业务管理器(此刻现已将业务的大部分事情做完,以后的内容耗时极小)。
第二阶段
第二阶段也分为两个进程:
业务管理器在接受各个消息后,开端剖析,假如有恣意其一失利,则发送回滚命令,不然发送提交命令。
各个资源管理器接收到命令后,履行(耗时很少),并将提交消息回来给业务管理器。
🍙内部XA业务
内部XA业务首要指单节点实例内部,一个业务跨多个存储引擎进行读写,那么就会产生内部XA业务
存储引擎与插件之间,存储引擎与存储引擎之间
提交进程
将 redo log 的写入拆成了两个进程:prepare 和 commit,中间再交叉写入binlog,详细如下:
-
prepare 阶段:将 XID(内部 XA 业务的 ID) 写入到 redo log,一同将 redo log 对应的业务状况设置为 prepare,然后将 redo log 刷新到硬盘;
- commit 阶段:把 XID 写入到 binlog,然后将 binlog 刷新到磁盘,接着调用引擎的提交业务接口,将 调用引擎的提交业务接口,将 redo log 状况设置为 commit(将业务设置为 commit 状况后,刷入到磁盘 redo log 文件,所以 commit 状况也是会刷盘的);
🎐呈现反常会怎样样?
总结
只需binlog也好了,就不需求回滚,binlog没好,就需求回滚
其实便是两个变成一个业务,redolog和binlog
写入binlog呈现反常
运用两阶段提交后,写入binlog时产生反常也不会有影响,因为MySQL依据redo log日志康复数据时,发现redo log还处于prepare阶段,而且没有对应binlog日志【binlog没有当时内部XA业务的XID】,就会回滚该业务。
设置commit反常
并不会回滚业务,它会履行上图框住的逻辑,尽管redo log是处于prepare阶段,可是能经过业务id找到对应的binlog日志【binlog有当时内部XA业务的XID】,所以MySQL认为是完好的,就会提交业务康复数据。
🎐疑问–好问题
在履行更新句子进程,会记载redo log与binlog两块日志,以基本的业务为单位,redo log在业务履行进程中能够不断写入,而binlog只需在提交业务时才写入,所以redo log与binlog的写入机遇不一样。
- 业务履行中间进程的 redo log 也是直接写在 redo log buffer 中的,这些缓存在 redo log buffer 里的 redo log 也会被「后台线程」每隔一秒一同耐久化到磁盘。
也便是说,业务没提交的时分,redo log 也是或许被耐久化到磁盘的。
那业务履行进程中不断写入,假如履行业务期间mysql宕机呢?
此刻重启后,mysql要利用redolog康复,有一部分操作redolog现已写入磁盘了,后续康复会不会呈现数据不一致的状况?【因为业务实际上还没有提交呢,是需求回滚的相当于呈现了反常】
此刻因为有两阶段提交,binlog必须在业务提交后才写入,所以此刻即便redolog写入了,但binlog还未写入,重启时读取到该redolog会发现没有对应的binlog,会放弃掉
🍿🍿🍿手撕面答环节 — 这是一条分割线
🍔MySQL 日志文件有哪些?别离介绍下作用?
别离有 undolog、redolog、 binlog。
- undolog用于完成原子性,记载版别链用于回滚,而且归于逻辑日志,记载操作便于康复
- redolog用于宕机后的数据康复,记载实际的数据,归于物理日志
- binlog首要用于主从复制,全量备份,比较redolog可存储的内容更多,既能够物理也能够逻辑存储,一般运用Mix
其间server层还有其他的日志,比方:
- 过错日志(error log):过错日志文件对 MySQL 的发动、运行、关闭进程进行了记载,能帮助定位 MySQL 问题。
- 慢查询日志(slow query log):慢查询日志是用来记载履行时刻超越 long_query_time 这个变量定义的时长的查询句子。经过慢查询日志,能够查找出哪些查询句子的履行功率很低,以便进行优化。
- 一般查询日志(general log):一般查询日志记载了一切对 MySQL 数据库恳求的信息,不管恳求是否正确履行。
🍔redolog怎么刷入磁盘的
有三种战略,参数不同的时分,对应的刷入机遇不同
首要都会先写到redolog的 buffer 区
参数为0:不写入,等待后台线程守时【每秒】将 buffer 区中的内容写入磁盘
若溃散,会丢掉上一秒中,buffer区里面一切的内容
参数为1:每次提交就写入,先写到 buffer 区,然后立马调用 fsync 写入磁盘
不会丢掉,能够看成业务提交和写入磁盘是一个原子性的操作?
参数为2:每次提交,先写到 buffer 区,然后写入到 pageCache 里面,由操作体系来决定何时写入磁盘
只需操作体系溃散了,才会丢掉上一秒中
要选择哪种战略呢?
考虑功能:0>2>1
考虑安全性:1>2>0
归纳:2
🍔为何要引进redolog来记载呢?
将磁盘的随机IO转换为追加写入
本来假如咱们每次都去更改磁盘里面的内容,则需求先随机IO找到,然后更改
有了写入的话,咱们每次都先追加写入到redolog,然后再一次性去磁盘里面找就好了,而不是每次都去磁盘找
🍔redolog 和 binlog 有什么差异
存储的容量不同
redolog以日志文件组作为存储的数据结构,容量是有限的,写满的时分会删除
undolog以追加文件的方式存储,理论上存储容量是无限的
🎈刷盘机遇不同
redolog有三种不同的刷盘战略
标答:binlog只在业务提交的时分才写入,而redolog因为有后台进程,业务期间也会写入
所属的范畴不同
redolog是 innoDB 特有的,而binlog是 server 层的
用处不同
redolog用于宕机后的数据康复
binlog首要用于主从复制,全量备份
🍔🎈为什么需求两阶段提交
- redolog提交成功,则binlog提交失利了
此刻主库没有影响,但从库因为binlog丢掉了,从库得不到复制
- binlog提交成功,但redolog提交失利了
从库因为有binlog的存在,记载了更新,binlog 会被复制到从库,从库履行了这条更新句子,而主库的redolog还没刷盘成功,导致溃散后没法康复,主库丢掉了本次更新
🍔两阶段提交进程中呈现反常了怎样办?
写入binlog的时分出反常
此刻redolog尽管预备好了,可是binlog还没写入,也就还没相关好binlog,宕机康复后扫描到这个redolog的时分发现其没有相关的binlog,认为是不完好的,会丢掉掉
commit阶段出反常
因为此刻redolog其实现已预备好了,而且binlog也现已写入了,相关好了XA业务的ID,也能够认定为这个业务是完好的了,宕机康复后,能找到该redolog对应的binlog
🍔redolog业务履行期间也写入,会不会有数据不一致的问题?
业务履行期间也会写入redolog,而binlog是业务提交后才写入,那这样宕机康复后会不会呈现不一致的状况呢?
- 其实是不会的,因为业务履行进程中宕机的话,binlog还没写呢,也就对应了咱们上文的:写binlog呈现反常的状况,宕机后康复,扫描的时分会丢掉
保藏 == 白嫖,点赞+重视才是真爱!!!本篇文章如有不对之处,还请在评论区指出,欢迎增加我的微信一同沟通:Melo__Jun
🧿友链
-
MySQL高档篇专栏
-
SSO单点登录专栏
-
Redis入门与实战
-
🎉我的一年后台操练生计
-
聊聊Java
-
分布式开发实战
-
数据结构与算法
参考
- Java-guide
- 小林coding