当前位置: 首页 > 科技观察

必须了解的MySQL三大日志:binlog、redolog、undolog

时间:2023-03-19 14:04:47 科技观察

日志是mysql数据库的重要组成部分,记录了数据库运行过程中的各种状态信息。MySQL日志主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志。作为开发,我们需要重点关注二进制日志(binlog)和事务日志(包括redolog和undolog)。本文将详细介绍这三类日志。binlogbinlog用于记录数据库执行的写操作(不包括查询)信息,并以二进制形式保存在磁盘上。binlog是mysql的逻辑日志,由server层记录,使用任何存储引擎的mysql数据库都会记录binlog日志。逻辑日志:可以简单理解为记录的是SQL语句。物理日志:因为mysql的数据最终是存放在数据页中的,所以物理日志记录的是数据页的变化。binlog是通过append的方式写的。您可以通过max_binlog_size参数设置每个binlog文件的大小。当文件大小达到给定值时,将生成一个新文件来保存日志。Binlog使用场景在实际应用中,binlog主要有两种使用场景,分别是主从复制和数据恢复。Master-slavereplication:在Master端开启binlog,然后将binlog发送给各个Slave端,Slave端重放binlog,实现主从数据一致性。数据恢复:使用mysqlbinlog工具恢复数据。binlog刷盘时机对于InnoDB存储引擎来说,biglog只有在事务提交的时候才会被记录下来。此时记录还在内存中,那么biglog什么时候刷到磁盘呢?mysql通过sync_binlog参数控制biglogflush的时机,取值范围0-N:0:无强制要求,系统判断何时写入磁盘;1:每次commit时将binlog写入磁盘;N:每N个事务才会将binlog写入磁盘。从上面可以看出,sync_binlog最安全的设置是1,这也是MySQL5.7.7之后版本的默认值。但是设置较大的值可以提高数据库性能,所以在实际中也可以适当调整该值,牺牲一定的一致性来获得更好的性能。推荐阅读:Java面试题拆解binlog日志格式binlog日志有三种格式,分别是STATMENT、ROW和MIXED。MySQL5.7.7之前,默认格式为STATEMENT,MySQL5.7.7之后,默认为ROW。日志格式由binlog-format指定。STATMENT基于SQL语句复制(statement-basedreplication,SBR),每条修改数据的SQL语句都会记录在binlog中。优点:无需记录每一行的变化,减少binlog日志量,节省IO,从而提高性能;缺点:在某些情况下,会造成主从数据不一致,比如执行sysdate()、slepp()等。ROW基于行的复制(RBR)不记录每条SQL语句的上下文信息,只记录记录哪些数据被修改了。优点:不会出现某些情况下无法正确复制存储过程、函数或触发器的调用和触发器的问题;缺点:会产生大量日志,尤其是改表时会导致日志暴涨MIXED-basedMixed-basedreplication(MBR)ofSTATEMENTandROWmode。一般复制使用STATEMENT方式保存binlog。对于STATEMENT方式无法复制的操作,使用ROW方式保存binlog。我们都知道为什么redolog需要redolog。四个特征之一是持久性。具体来说,只要事务提交成功,对数据库所做的修改将被永久保存,无法以任何理由恢复到原来的状态。那么mysql是如何保证一致性的呢?最简单的方法是每次提交事务时,将事务涉及的所有数据页刷新到磁盘。但是这样做会造成严重的性能问题,主要体现在两个方面:因为Innodb是以页为单位与磁盘进行交互的,而一个事务可能只修改一个数据页中的几个字节,这时候就完全可以了将数据页刷新到磁盘会浪费资源!一个事务可能涉及修改多个数据页,而这些数据页在物理上并不连续,使用随机IO写入性能太差!因此mysql设计了redolog。具体来说,它只记录事务对数据页所做的更改,这样就可以完美解决性能问题(相对来说文件更小,而且是顺序IO)。搜索Java知音公众号,回复“后端面试”,送你Java面试题集重做日志基本概念重做日志由两部分组成:一个是内存中的日志缓冲区(redologbuffer),另一个是在磁盘上。日志文件(redologfile)。mysql每执行一条DML语句,先将记录写入redologbuffer,然后在某个时间点将多条操作记录写入redolog文件。这种先写入日志再写入磁盘的技术就是MySQL中经常提到的WAL(Write-AheadLogging)技术。在计算机操作系统中,用户空间(userspace)中的缓冲区数据一般不能直接写入磁盘,必须经过操作系统内核空间(kernelspace)缓冲区(OSBuffer)。因此,将redologbuffer写入redolog文件实际上是先写入OSBuffer,然后通过系统调用fsync()将其flush到redolog文件中。过程如下:mysql支持三种方式将redologbuffer写入redo日志文件的时机可以通过innodb_flush_log_at_trx_commit参数进行配置。各个参数值??的含义如下:redolog的记录形式前面说过,redolog实际上记录的是数据页的变化,并不需要保存所有这样的变化记录,所以redolog实现了above采用了固定大小和循环的书写方式。写到最后,会回到开头,循环写入日志。如下图所示:同时,我们可以很容易的知道,在InnoDB中,既需要刷新redolog,也需要刷新数据页。redolog存在的意义主要是减少对数据页刷新的要求。上图中writepos表示redolog当前记录的LSN(逻辑序号)位置,checkpoint表示数据页变化记录flush后对应redolog的LSN(逻辑序号)位置.writepos和checkpoint之间的部分是redolog的空部分,用来记录新的记录;checkpoint和writepos之间的部分是redolog要放到磁盘上的数据页变化记录。当writepos追上checkpoint时,会先把checkpoint往前推,为新的log腾出空间。在启动InnoDB时,不管上次是正常关机还是异常关机,都会一直执行恢复操作。因为重做日志记录的是数据页的物理变化,所以恢复速度比逻辑日志(如binlog)要快很多。重启InnoDB时,会先检查磁盘中数据页的LSN。如果数据页的LSN小于日志中的LSN,就会从检查点恢复。还有一种情况,在宕机前,checkpoint在刷盘过程中,datapage的刷盘进度超过了logpage的刷盘进度。此时数据页中记录的LSN大于日志中的LSN。超过日志进度的部分是不会重做的,因为这本身就意味着有些事情已经做了,没必要重做。从binlog和redolog的区别可以看出redolog和binlog的区别:binlog日志只是用来归档的,仅仅依赖binlog是没有crash-safe能力的。但是只有redolog是不行的,因为redolog是InnoDB特有的,log上的记录放到磁盘后会被覆盖。所以需要同时记录binlog和redolog,保证数据库宕机重启时不会丢失数据。undolog数据库事务的四个特征之一是原子性。具体来说,原子性是指对数据库的一系列操作,要么全部成功,要么全部失败,不可能部分成功。其实底层的原子性是通过undolog来实现的。undolog主要记录数据的逻辑变化。例如,一条INSERT语句对应一个DELETEundolog,而对于每条UPDATE语句,对应一个相反的UPDATEundolog,这样当出现错误时,可以回滚到事务数据之前的状态。推荐阅读:拆解Java面试题同时undolog也是实现MVCC(多版本并发控制)的关键。这部分内容是面试中最难的——mysql事务和锁。里面有介绍,不再赘述。