美文网首页
MySQL-日志binlog、redolog、undolog

MySQL-日志binlog、redolog、undolog

作者: 想搞钱又搞不到钱 | 来源:发表于2023-06-18 15:53 被阅读0次

    原文地址:https://zhuanlan.zhihu.com/p/474218953

    MySQL日志分类

    一、binlogbinlog是 mysql server 层的一种二进制日志,用来记录数据库的写入操作,并以"事务"的形式保存在磁盘上,主要的使用场景有主从复制和数据恢复。

    日志格式

    statement:记录了SQL语句原文,但是类似 set update_time=now() 这种情况,可能会导致主从数据不一致row:记录SQL涉及到的每行数据的修改,缺点是会产生大量的日志,mysql 5.7.7之后默认 row 模式mixed:两种方案折中,MySQL会判断这条SQL语句是否会引起数据不一致,如果是,就用row模式,否则就用statement模式写入流程

    事务执行过程中,会先把日志写到binlog cache,事务提交的时候,再根据刷盘规则将binlog cache写入文件。

    系统会给每个线程分配一个 binlog cache ,可以通过 binlog_cache_size 参数控制单个线程 binlog cache 大小,如果存储内容超过了这个参数,就要暂存到磁盘。

    write:将 mysql 缓存写到文件系统的 page cache,并没有把数据持久化到磁盘,速度比较快

    fsync:文件系统的 page cache 持久化到磁盘

    刷盘时机

    0:每次提交只 write,由系统判断什么时候执行 fsync,如果宕机page cache里面的binlog会丢失

    1: 每次提交事务都会执行 write + fsync ,MySQL 5.7.7 之后默认为1

    N:每次提交事务都write,但累积N个事务后才fsync ,如果宕机会丢失N个事务的binlog

    主从复制

    salve的IO进程连接上master,并请求指定binlog文件指定位置之后的内容

    master接到请求后,负责复制的IO进程读取并返回指定的binlog内容,包括binlog文件名称和位置

    salve将binlog日志添加到relay-log文件,并记录日志文件名称和位置

    salvesql 进程检测到relay-log新增内容后,解析binlog并执行

    相关参数配置

    # 开启binlog 存放位置log-bin = mysql-bin# 最大的大小max_binlog_size = 1G# binlog的刷盘时机sync-binlog = 1# binlog的格式binlog-format = ROW# 保留七天的binlogexpire_logs_days = 7#查看binlogmysqlbinlog: /var/bin/mysqlbinlog mysql-bin.000001#数据恢复mysqlbinlog --start-position=10000 --stop-position=15000 mysql-bin.000001 > history.sql

    二、redo logredo log (重做日志)是InnoDB存储引擎产生的,记录事务对数据页的修改,如果mysql挂了,重启后InnoDB会使用redo log恢复数据,保证了数据的持久性。

    每条 redo 记录由“表空间号+数据页号+偏移量+修改数据长度+具体修改的数据”组成写入流程

    为了提高性能,mysql使用了buffer pool,查询数据时,先从buffer pool查,如果不存在,就会从磁盘读取数据页放到buffer pool,更新数据同样,直接更新buffer pool中的数据页,此时内存中的数据页和磁盘上的就不一致了,出现了脏页,mysql会在合适的时机将脏页刷到磁盘,但是万一脏页还没刷到磁盘,mysql宕机,此时buffer pool中还没来得及落盘的数据就丢失了,所以在更新buffer pool之前就会把 “事务在某个数据页上做了什么修改”记录到redo log,这就是WAL(Write Ahead Log)。

    刷盘时机

    redo log 为了提高性能也使用了缓存redo log buffer ,可以通过 innodb_flush_log_at_trx_commit 来配置刷盘策略,默认 = 1 ,不会丢数据。除了事务提交时刷盘,InnoDB存储引擎还有一个后台线程,每隔1秒,执行一次 write + fsync 刷盘。

    0 :每次事务提交时不进行刷盘操作,mysql挂了会丢失1秒数据1 :每次事务提交时都将进行刷盘操作 write + fsync,不会丢数据2 :每次事务提交时只执行write,mysql挂了不会丢数据,服务器挂了会丢失1秒数据还有一种情况,当redo log buffer占用的空间即将达到 innodb_log_buffer_size 一半的时候,后台线程会主动刷盘

    日志文件

    redo log默认情况下存储在data目录下ib_logfile0 、ib_logfile1,可以通过 innodb_log_file_size 设置大小, innodb_log_files_in_group 设置文件个数,比如可以配置为一组4个文件,每个文件的大小是 1GB,整个redo log 日志文件组可以记录4G的内容,

    redo log是循环写的,write pos是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头,checkpoint是当前要擦除的位置,也是往后推移并且循环的,脏页刷盘,checkponit往后移。

    每个数据页都有一个LSN,redo log 中也记录了LSN,当数据库异常重启时,系统读取redo log并定位到checkpoint位置,如果此时当redo log中的LSN大于数据页中的LSN,说明redo log中的数据未完全写入数据页中,那么将从数据页中记录的LSN开始,从redo log中恢复数据。比如redolog 的LSN 是 13000,数据库页的LSN是 10000,那么系统将会恢复redo log 中LSN从10000开始到13000的记录到数据页中。当redo log中的LSN小于数据页中的LSN时,说明数据页已经被刷到该位置,所以不需要进行恢复。

    二阶段提交

    InnoDB事务提交之前并不是直接写redo log,而是使用了二阶段提交,将redo log的写出拆成了两个步骤:prepare 和 commit,这就是"两阶段提交"。

    为什么要使用两阶段提交呢?假设没有redo log直接提交:

    1、先写binlog,mysql崩溃,事务回滚,但是binlog已经写入,同步到从库,最终导致主从不一致。2、先写redo log,mysql崩溃,重启,通过redo log恢复事务,但是binlog里并没有这个事务,主从不一致,如果通过binlog来恢复数据,也会丢失事务。

    再来看看两阶段提交:

    1、如果写入redo log prepare阶段之后,mysql崩溃,重启, redo log prepare+binlog不完整,回滚事务。2、如果在写入binlog之后,mysql崩溃,重启,redo log prepare + binlog完整,事务提交,恢复数据。

    可以看到 redo log prepare阶段+完整的binlog就能保证mysql的崩溃恢复了。

    崩溃恢复

    再来看看完整的崩溃恢复流程

    binlog能不能崩溃恢复?

    不可以,因为binlog是追加写入的,只要开启了binlog,所有的更新记录都会被写入,保存的是全量的日志, InnoDB不能区分出哪些数据已经刷盘,哪些还没有。而redo log是循环写的,checkpoint 和 write pos 之间的 redo log都是未刷入磁盘的日志。

    三、undo logInnoDB事务修改数据之前会记录undo log并且持久化,undo log通过回滚事务指针形成了链表。undo log 有三个使用场景 1.通过rollback主动回滚事务, 2:MVCC ,3.崩溃恢复未完成的事务通过undo log回滚。

    undo log 日志有两种 insert 类型 和 update 类型,insert 类型记录了主键id,update 类型记录了修改前的数据

    INSERT INTO t (id, a) VALUES (1, “A”); UPDATE t SET a=“B” WHERE id = 1; UPDATE t SET a=“C” WHERE id = 1;

    事务3 回滚 ,会将数据回滚到事务2修改后,而事务2想回滚它会将数据回滚到事务1插入后的状态,事务1回滚就会删除插入的记录。

    相关文章

      网友评论

          本文标题:MySQL-日志binlog、redolog、undolog

          本文链接:https://www.haomeiwen.com/subject/xvcsydtx.html