在MySQL中有三个比较重要的日志:1. bin log(二进制日志) 2. redo log(重做日志) 3. undo log(回滚日志)。
Redo log(重做日志)
Redo log是InnoDB数据库引擎独有的一种日志,他可以让数据库拥有故障崩溃之后的恢复能力。mysql挂了或者宕机之后,innodb依赖redo log恢复数据,保证了数据的持久性。
在Mysql中的数据是以页为单位存储的。进行一次查询,会把一页的数据加载到内存中,放到buffer pool中。
接着后续的查询都是先从buffer pool中寻找,如果没有查询到,那么才从硬盘中IO加载。
更新数据的时候,如果buffer pool中有,那么也是先在buffer pool中更新。
在把数据的修改刷盘到redo log文件中之前,需要先把数据存到缓存里(redo log buffer)。
更新一条数据,如果存到redo log中:
1. 磁盘先加载数据页到buffer pool中。
2. 然后直接修改buffer pool中的数据。
3. 把更新的信息记录到redo log buffer中
4. 刷盘,存储到redo log文件中。
刷盘有三个参数:
0: 设置为0的时候,每次提交事务的时候不刷盘。(后台线程每1秒刷盘一次,如果mysql宕机,损失一秒的数据)。
1: 设置为1的时候,每次提交事务的时候都刷盘。(默认的参数)。
2: 设置为2的时候,每次提交事务的时候,都会把redo buffer 的数据写入page cache。(mysql挂了没有影响,但是如果宕机那么就损失一秒的数据)。
在后台,有一个线程,每过一秒都会把redo buffer中的数据写入到page cache(文件缓存系统),然后再调用fsync刷盘。
Bin Log:归档日志
Redo log 是物理日志,他主要记录了我们在某个数据页上做了什么操作。,属于InnoDB存储引擎。而bin log是逻辑日志,记录的是mysql语句的原始逻辑,属于mysql 的server层。
只要是数据表发生了数据的变化,都会记录到bin log中。Bin Log的作用是数据库之间的数据同步和保持数据一致性。像主从,主主,主备这些都离不开bin log。
Bin Log日志有三种格式:
1. statement
2. row
3. mixed
Statement:
直接记录mysql 原始语句,在同步数据的时候会执行mysql语句。但有个问题是有些语句会和当前的时间有关联,比如update time = now或获取当前的系统时间,在同步数据的时候会操成数据的不一致。为了应对这种情况,我们还有一种格式,就是row。
Row:
Row不仅记录mysql语句,还记录一些具体的数据,这样的话就解决了数据不一致性的问题。但是这些格式需要记录的信息太多,比较占用空间。
Mixed:
Mixed是statment和row的混合体。MySQL会判断,如果一条语句会造成数据不一致,那么就用row,如果没问题,就直接使用statment。
Bin log的写入机制非常简单,事务执行的过程中,先写到bin log的缓存中,然后在提交的时候,再把缓存中的数据一起写入打到bin log文件中去。
注意:这里的写入是指写入到系统的文件缓存(page cache),还需要调用fsync刷盘到bin log文件
写入和刷盘有一个参数可以控制(sync_binlog):
为0的时候,每次提交事务都只写入,系统自行判断什么时候刷盘。(机器宕机丢失page cache里的数据)
一般为了安全起见都会设置为1,每次提交事务都会执行刷盘,确保数据存放到bin log中。
还有一个折中的办法,可以把参数设置为N,N大于1,N表示累计几次事务之后再刷盘一次。
两段式提交:
试想一个问题:
如果系统成功的把数据成功的存储到了redo log中,然后再去存到bin log的时候发生了异常,那么就会造成数据的不一致性。
为了解决上述的问题,mysql采用两段式提交的方法,具体的方法是:
1.首先在写入到redo log的时候先进行一个prepare准备的阶段,还没有完全成功此时。
2. 然后再把数据写入到bin log中。
3. 最后再进行最后的确认,如果没有写入bin log没有问题,就commit,完成写入redo log的操作。
使用两阶段提交后,写入binlog
时发生异常也不会有影响,因为MySQL
根据redo log
日志恢复数据时,发现redo log
还处于prepare
阶段,并且没有对应binlog
日志,就会回滚该事务。
Undo Log:回滚日志
事务为了保证原子性,在其中执行失败的时候,就需要对已经进行的操作进行回滚,依赖的就是undo log。所有事务进行的修改都会先记录到这个回滚日志中,然后再执行相关的操作。如果执行过程中遇到异常的话,我们直接利用 回滚日志 中的信息将数据回滚到修改之前的样子即可!并且,回滚日志会先于数据持久化到磁盘上。这样就保证了即使遇到数据库突然宕机等情况,当用户再次启动数据库的时候,数据库还能够通过查询回滚日志来回滚将之前未完成的事务。