MySQL的几种日志
每一个操作在真正写入数据库之前,都会先写入日志。MySQL的日志主要包括 错误日志、查询日志、慢查询日志、事务日志、二进制日志 等几大类。
二进制日志binlog
- binlog记录写入性操作(不包含查询)信息
- 以二进制形式保存在磁盘中
- binlog是由Server层进行记录的,使用任何存储引擎的MySQL数据库均会记录binlog日志
- binlog是以追加的方式进行写入的
- 可以通过设置max_binlog_size参数来设置每个binlog文件的大小
- binlog的三个主要使用场景:(1)主从复制(2)数据恢复(3)信息审计
- 对于InnoDB存储引擎来说,只有事务提交时才会记录binlog
- binlog的刷盘时机,通过sync_binlog参数来进行控制
- binlog的日志三种格式:statement、row(默认)和mixed,通过binlog-format参数指定。statement格式会记录修改sql语句, row格式会记录行的数据内容变更,记两条,更新前和更新后都有。
事务日志redo log和undo log
redo log
- redo log包含两部分,一个是内存中的日志缓冲(redo log buffer,临时的),另一个是磁盘上的日志文件(redo log file,持久的)
- mysql每执行一条DML语句,会先将记录写入redo log buffer,后续某个时间点再一次性将多个操作记录写到redo log file。这种先写日志再写磁盘的技术,就是MySQL里经常说到的WAL(Write-Ahead Logging)技术
- redo log buffer写入redo log file实际上是先写入OS Buffer,然后再通过系统调用fsync()将其刷到redo log file中
- mysql支持3种将redo log buffer写入redo log file的时机,可以通过innodb_flush_log_at_trx_commit参数进行配置
- redo log实现上采用了大小固定,循环写入的方式,当写到结尾时,会回到开头循环写日志。在系统启动的时候,就已经为redo log分配了一块连续的存储空间,以顺序追加的方式记录redo log,通过顺序IO来改善性能。所有的事务共享redo log的存储空间,它们的redo Log按语句的执行顺序,依次交替的记录在一起。
- 只依靠binlog是没有crash-safe能力的,只有redo log也不行。因为redo log是InnoDB特有的,且日志上的记录落盘后会被覆盖掉。因此需要binlog和redo log二者同时记录,才能保证当数据库发生宕机重启时,数据不会丢失
- 如果数据库崩溃或者宕机,那么当系统重启进行恢复时,可以根据redo log中记录的日志,把数据库恢复到崩溃前的一个状态。未完成的事务可以继续提交,也可以选择回滚,这基于恢复的策略而定。
- redo log是innodb独有的,binlog是所有引擎都可以使用的
- redo log是循环写的,空间会用完,binlog是可以追加写的,不会覆盖之前的日志信息
- binlog和redo log必须保持一致,不允许出现binlog有记录但redo log没有的情况,反之亦然
##undo log
- 数据库事务的原子性保证,底层就是通过undo log实现的,主要用作回滚
- undo log主要记录了数据的逻辑变化。比如一条INSERT语句,对应一条DELETE的undo log;对于每个UPDATE语句,对应一条相反的UPDATE的undo log。这样在发生错误时,就能回滚到事务之前的数据状态
- undo log也是MVCC(多版本并发控制)实现的关键
- Innodb通过force log at commit机制实现事务的持久性。即在事务提交的时候,必须先将该事务的所有事务日志写入到磁盘上的redo log file和undo log file中进行持久化。为了确保每次日志都能写入到事务日志文件中,在每次将log buffer中的日志写入日志文件的过程中都会调用一次操作系统的fsync操作(fsync函数同步内存中所有已修改的文件数据到储存设备)
- 单个事务的回滚,只会回滚当前事务做的操作,并不会影响到其他的事务做的操作。
- redo log保证的是事务的持久性和一致性,而undo log则保证了事务的原子性