mysql日志中最重要的3种为redo log(重做日志), binlog(归档日志) 和 undo log(回滚日志)
下面来详细介绍一下这3种日志
redo log
redo log是Innodb引擎特有的,记录了数据页上的改动,使数据库在宕机后有数据恢复的能力,保证数据的持久性
为什么需要redo log
- 使数据库在宕机或异常重启后有恢复数据的能力,保证数据持久性
- 配合mysql的WAL(Write-Ahead Logging)机制,mysql在更新操作时会只写内存就返回,然后异步去刷盘。这样就存在系统crash后内存中数据丢失的问题,而redo log 是crash safe的,可以利用redo log避免此情况
redo log的写入方式
redo log分为两部分,内存中的redo log buffer和磁盘中的redo log file
mysql每次执行一条DML语句时,会把记录写入redo log buffer中,后续某个时间点把redo log buffer中的内容写入到redo log file中,这种先写日志,再写磁盘的操作就是WAL
但是我们知道,在计算机操作系统中,用户空间的缓冲区数据是没办法直接写入磁盘的,需要经过内核的缓冲区OS buffer才能写入,所以redo log完整的写入过程如下:
- 写入用户空间的redo log buffer
- 将redo log buffer中内容保存到内核空间的os buffer
- 通过fsync()命令,将os buffer中内容保存到磁盘redo log file中
可以通过参数innodb_flush_log_at_trx_commit
来配置日志从redo log buffer到os buffer再到redo log file的时机
- 0:延时写,事务提交后不会直接写入os buffer,而是每隔1s写入os buffer并写入redo log file中
- 1:实时写、实时刷,事务提交后写入os buffer并写入redo log file中
- 2:实时写、延时刷,事务提交后写入os buffer,每隔1s将os buffer中内容写入redo log file
redo log如何保证crash safe
- 在每次更新操作后,事务提交前就会记录日志,如果记录失败那么该事务也不会提交
- redo log记录了页的数据变化,当系统crash后可以读取redo log进行重放,恢复数据
binlog
redo log是物理日志,记录了某个数据页中修改了什么内容,属于innodb存储引擎
而binlog是逻辑日志,它记录了语句的原始逻辑,属于server层,不管用什么存储引擎,是要发生了表内容修改就会产生binlog,用于数据库备份、主备、主从、主主来同步数据,保证数据一致性
binlog记录格式
- statement:基于sql语句的复制,记录原始sql语句,性能好但是
update_time=now()
此类语句会出问题 - row:基于行的复制,不记录sql语句上下文相关信息,仅保存哪条记录被修改,较为占用空间
- mixed:混合模式复制,Statement与Row的结合。一般的语句修改使用statment格式,如一些函数statement无法完成主从复制的操作,则采用row格式,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式
binlog写入方式
当事务执行时写入binlog cache(缓存大小由binlog_chache_size
控制),事务提交后从binlog cache写入binlog file。
binlog cache刷新到磁盘的时机由sync_binlog
控制:
- 0:mysql不管,由系统决定何时刷盘。若系统宕机,缓存中的binlog丢失
- 1:每次commit,进行刷盘
- N(大于1的整数):每N个事务进行一次刷盘
两阶段提交
为什么需要两阶段提交呢?
首先redo log的记录时机是在每一次数据修改时,而binlog只有在事务提交后才进行刷盘保存。因此,若系统在某条记录redo log成功,但事务未提交时宕机,那么就会造成redo log和binlog不一致的情况,原系统通过redo log恢复数据,从系统通过binlog恢复数据就会造成数据不一致。两阶段提交就是为了解决此类问题的。
两阶段提交就是把redo log的写入拆分为prepare和commit两个状态:
- redo log记录后进入prepare状态
- 执行器记录binlog
- 事务提交后进入commit状态
如此做,当mysql重启时便可保证数据的一致性
undo log
回滚日志,用于发生错误后的回滚操作,保证了事务的原子性。
所有事务进行的修改都会先记录到这个回滚日志中,然后再执行相关的操作。如果执行过程中遇到异常的话,直接利用回滚日志中的信息将数据回滚到修改之前的样子即可。
并且,回滚日志会先于数据持久化到磁盘上。这样就保证了即使遇到数据库突然宕机等情况,当用户再次启动数据库的时候,数据库还能够通过查询回滚日志来回滚之前未完成的事务。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。