参考博客:https://qimok.cn/584.html
重做日志(redo log)、回滚日志(undo log)、二进制日志(binlog),redo log 是物理日志,undo log 和 binlog 是逻辑日志,物理日志的恢复速度远快于逻辑日志,这时因为redo log利用了磁盘的顺序读写,mysql使用redo log提升了整体的io性能
redo log
参考博文:https://www.cnblogs.com/hapjin/archive/2019/09/28/11521506.html
概念
redo log在mysql中默认以ib_logfile0,ib_logfile1名称存在,可以手工修改参数,调节开启几组日志来服务于当前mysql数据库,mysql采用顺序,循环写方式,每开启一个事务时,会把一些相关信息记录事务日志中(记录对数据文件数据修改的物理位置或叫做偏移量);这个系列文件个数由参数innodb_log_files_in_group控制,若设置为4,则命名为ib_logfile0~3。这些文件的写入是顺序、循环写的,logfile0写完从logfile1继续,logfile3写完则logfile0继续。他们的作用是在系统崩溃重启时,作事务重做;在系统正常时,每次checkpoint时间点,会将之前写入事务应用到数据文件中。innodb 事务日志包括 redo log 和 undo log,redo log是物理日志,undo log 是逻辑日志,用来提供回滚操作,redo log保证事务的持久性,undo log保证事务的原子性,两者可以统称为事务日志。而binloh与redo log不同点是:redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。
生命周期:
事务开始之后就开始产生 redo log 日志了,在事务执行的过程中,当对应事务的脏页会被记录到redo log中,当 redo log file 大小已经达到某个域值快要"不可用"时(日志文件组轮流写文件),触发 checkpoint,及时将缓冲池的脏页刷新到磁盘,并同时将redo log buffer刷新到磁盘,redo log 的使命就完成了,它所占用的空间也就可以被覆盖了。
存储内容:
redo log 包括两部分:一是内存中的日志缓冲(redo log buffer),默认大小16MB,可经过参数innodb_log_buffer_size动态的调整它的大小,该部分日志是易失性的;二是磁盘上的重做日志文件(redo log file),该部分日志是持久的,redo log 存储的是物理格式的日志,记录的是物理数据页面的修改信息,即所有innodb表数据的变化,它是顺序写入 redo log file 中的。
持久化:
当事务要修改记录时,生成的日志都得先保存起来,但又不能在还没 commit 的时候就直接写到 redo log 文件里。所以,redo log buffer 就是一块内存,用以缓存事务执行过程中的数据,记录的物事务过程产生的修改,redo log buffer中同一个事务可能多次记录,最后一个提交的事务记录会覆盖所有未提交的事务记录。当向MySQL写数据时,先写日志缓冲的redo log,然后根据"某种方式"持久化到磁盘变成redo log file。如果发生宕机,则读取磁盘上的 redo log file 进行数据的恢复。从这个角度来说,MySQL 事务的持久性是通过 redo log 来实现的。
- 问:redo log buffer中的数据丢失了怎么办?毕竟没有写到磁盘上,MySQL重启后100%没办法将其恢复出来。
- 答:由于在MySQL的设定中,当你要Commit事务时,redo log才会持久化进磁盘,既然你没有commit,碰巧MySQL又宕机了。那让MySQL正常重启就行了啊,反正你没有commit,MySQL也也没有必要帮你恢复什么。
这三种状态分别是:
- 存在 redo log buffer 中,物理上是在 MySQL 进程内存中,就是图中的红色部分;
- 写到磁盘 (write),但是没有持久化(fsync),物理上是在文件系统的 page cache 里
面,也就是图中的黄色部分; - 持久化到磁盘,对应的是 hard disk,也就是图中的绿色部分。
innodb_flush_log_at_trx_commit 的值来决定以下行为:
- 设置为 0 的时候,表示每次事务提交时都只是把 redo log 留在 redo log buffer 中 ;
- 设置为 1 的时候,表示每次事务提交时都将 redo log 直接持久化到磁盘;
- 设置为 2 的时候,表示每次事务提交时都只是把 redo log 写到 page cache。InnoDB 有一个后台线程,每隔 1 秒,就会把 redo log buffer 中的日志,调用 write 写到文件系统的 page cache,然后调用 fsync 持久化到磁盘
redo日志的工作就是MySQL意外宕机重启时解析redo log中的事务后重放一遍,将Buffer Pool中的缓存页重作成脏页。后续再在合适的时机将该脏页刷入磁盘便可。redo log 值负责重做缓冲池的脏页数据,但是不参与数据库的落盘工作。数据库的落盘是将缓冲池中的脏页刷到硬盘,而这用到的就checkpoint技术
checkpoint分为两种:
第一种是sharp checkpoint,就是在数据库关闭时将缓冲池的脏页全部刷到硬盘
第二种是fuzzy checkpoint,fuzzy checkpoint又分为了好几种checkpoint,其中包括了master thread checkpoint,它会执行每秒和每十秒的任务按照一定的比例将脏页刷回磁盘中
重做日志缓冲池落盘方式:
1、MySQL master 线程周期性任务 每秒一次,将 redo log buffer 刷新到重作日志中(即使这个事务尚未提交)
2、MySQL master 线程周期性任务 每10秒一次,将 redo log buffer 刷新到重作日志中
3、每个事务提交时会将重做日志缓冲池中相应的数据刷到重作日志中
4、当redo log buffer size 剩余空间小于1/2时,将 redo log buffer 刷新到重作日志中
4、当 redo log file 大小已经达到某个域值快要"不可用"时(日志文件组轮流写文件),触发 async/sync flush checkpoint,及时将缓冲池的一些脏页刷新到磁盘,并同时将redo log buffer刷新到重作日志中。注意:最终落盘是由缓冲池刷到磁盘中,redo log file不参与落盘的工作。redo日志唯一的工作就是在崩溃恢复中,InnoDB 如果判断到一个数据页可能在崩溃恢复的时候丢失了更新,就会将它读到缓冲池,然后让 redo log 更新内存内容
脏页落盘
1、redo log满了
2、缓冲池不够用了,将对应淘汰的脏页写入硬盘
3、mysql在关闭时将脏页刷到磁盘
4、mysql在空闲时启动线程将部分脏页落盘
change buffer 和 redo log
当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InooDB 会将这些更新操作缓存在 change buffer 中,这样就不需要从磁盘中读入这个数据页了。在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行 change buffer 中与这个页有关的操作。change buffer提升了数据库修改操作的性能,但是在数据写入change buffer时,也需要往redo log中进行写入
为什么要使用redo log持久化,直接写入磁盘不行吗?
1、redo log在宕机时可以用来恢复数据
2、redo log持久化效率高。数据页、索引页的刷盘是不容易的,因为底层是一棵B+树结构。而redo log是顺序写,相比数据页、索引页的直接刷盘要效率高很多
undo log
参考博文:https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html#auto_id_11
概念:
undo用来回滚行记录到某个版本。undo log是逻辑日志,根据每行记录进行记录。undo log有两个作用:提供回滚和多个行版本控制(MVCC)。
生命周期:
事务开始之前,将当前事务版本生成 undo log,undo log 也会产生 redo log 来保证 undo log 的可靠性。当事务提交之后,undo log 并不能立马被删除,而是放入待清理的链表,由 purge 线程判断是否有其它事务在使用 undo 段中表的上一个事务之前的版本信息,从而决定是否可以清理 undo log 的日志空间。
存储内容:
undo log 存储的是逻辑格式的日志,保存了事务发生之前的上一个版本的数据,可以用于回滚。当一个旧的事务需要读取数据时,为了能读取到老版本的数据,需要顺着 undo 链找到满足其可见性的记录。
存储位置:
默认情况下,undo 文件是保存在共享表空间的,也即 ibdatafile 文件中,当数据库中发生一些大的事务性操作的时候,要生成大量的 undo log 信息,这些信息全部保存在共享表空间中,因此共享表空间可能会变得很大,默认情况下,也就是 undo log 使用共享表空间的时候,被“撑大”的共享表空间是不会、也不能自动收缩的。因此,MySQL5.7 之后的“独立 undo 表空间”的配置就显得很有必要了。binlog
概念:
MySQL 的二进制日志 binlog 可以说是 MySQL 最重要的日志,它记录了所有的 DDL 和 DML 语句(除了数据查询语句select、show等)。bin log 的主要目的是复制和恢复。binlog 用于主从复制中,从库利用主库上的 binlog 进行重播,实现主从同步。用于数据库的基于时间点、位点等的还原操作。binlog 的模式分三种:Statement、Row、Mixed。
binlog的执行过程:
事务执行过程中,先把日志写到 binlog cache,事务提交的时候,再把 binlog cache 写到 binlog 文件中。系统给 binlog cache 分配了一片内存,每个线程一个,参数 binlog_cache_size 用于控制单个线程内 binlog cache 所占内存的大小。如果超过了这个参数规定的大小,就要暂存到磁盘。事务提交的时候,执行器把 binlog cache 里的完整事务写入到 binlog 中,并清空 binlogcache
binlog存在write操作和fsync 操作。write操作是指的就是指把日志写入到文件系统的 page cache,并没有把数据持久化到磁盘,所以速度比较快。fsync 操作才是将数据持久化到磁盘的操作
write 和 fsync 的时机,是由参数 sync_binlog 控制的:
- sync_binlog=0 的时候,表示每次提交事务都只 write,不 fsync;
- sync_binlog=1 的时候,表示每次提交事务都会执行 fsync;
- sync_binlog=N(N>1) 的时候,表示每次提交事务都 write,但累积 N 个事务后才
fsync。
因此,在出现 IO 瓶颈的场景里,将 sync_binlog 设置成一个比较大的值,可以提升性能。
在实际的业务场景中,考虑到丢失日志量的可控性,一般不建议将这个参数设成 0,比较常
见的是将其设置为 100~1000 中的某个数值。
更新事务要写 binlog,而一旦 binlog 所在磁盘的空间占用率达到 100%,那么所有的更新语句和事务提交的 commit 语句就都会被堵住。但是,系统这时候还是可以正常读数据的
binlog的模式
Row 模式
记录的方式是行,即如果批量修改数据,记录的不是批量修改的SQL语句事件,而是每条记录被更改的SQL语句,因此,ROW模式的binlog日志文件会变得很“重”
优点:row 模式的binlog日志内容会非常清楚的记录下每一行数据被修改的细节。而且不会出现某些特定情况下存储过程或function,以及trigger的调用和触发器无法被正确复制的问题。
缺点:row 模式下,所有执行的语句当记录到日志中的时候,都以每行记录的修改来记录,这样可能会产生大量的日志内容,产生的binlog日志量是惊人的。
Statement 模式(默认)
记录每一条修改数据的SQL语句(批量修改时,记录的不是单条SQL语句,而是批量修改的SQL语句事件)。
优点:statement模式记录的更改的SQ语句事件,并非每条更改记录,所以大大减少了binlog日志量,节约磁盘IO,提高性能。
缺点:statement level下对一些特殊功能的复制效果不是很好,比如:函数、存储过程的复制。由于row level是基于每一行的变化来记录的,所以不会出现类似问题
Row 与Statement 的区别
Mixed 模式
实际上就是Statement与Row的结合。
在Mixed模式下,一般的语句修改使用statment格式保存binlog,如一些函数,statement无法完成主从复制的操作,则采用row格式保存binlog,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种。
如何选择binlog的模式
1、 如果生产中使用MySQL的特殊功能相对少(存储过程、触发器、函数)。选择默认的语句模式,Statement Level。
2、 如果生产中使用MySQL的特殊功能较多的,可以选择Mixed模式。
3、 如果生产中使用MySQL的特殊功能较多,又希望数据最大化一致,此时最好Row level模式;但是要注意,该模式的binlog非常“沉重”。
查看binlog模式
mysql> show global variables like "%binlog_format%";
+---------------+-----------+
| Variable_name | Value |
+---------------+-----------+
| binlog_format | STATEMENT |
+---------------+-----------+
配置binlog日志模式
vim my.cnf
log-bin = /data/3306/mysql-bin
binlog_format="STATEMENT"
#binlog_format="ROW"
#binlog_format="MIXED"
生命周期:
事务提交的时候,一次性将事务中的 sql 语句(一个事务可能对应多个 sql 语句)按照一定的格式记录到 binlog 中,这里与 redo log 很明显的差异就是 redo log 并不一定是在事务提交的时候才刷新到磁盘,而是在事务开始之后就开始逐步写入磁盘。binlog 的默认保存时间是由参数 expire_logs_days 配置的,对于非活动的日志文件,在生成时间超过 expire_logs_days 配置的天数之后,会被自动删除。
日志文件:
binlog日志包括两类文件:
1、二进制日志索引文件(文件名后缀为.index)用于记录所有有效的的二进制文件
网友评论