欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

redo log和bin log

程序员文章站 2022-03-11 18:46:22
讲redolog和binlog之前,先要讲一下一条mysql语句的执行过程。 1、client的写请求到达连接器,连接器负责管理连接、验证权限; 2、然后是分析器,负责复习语法,如果这条语句有执行过,在缓存内,那么就从缓存去写; 3、缓存没有的话,那就到了优化器部分。负责优化sql读写,选择索引; ......

讲redolog和binlog之前,先要讲一下一条mysql语句的执行过程。

1、client的写请求到达连接器,连接器负责管理连接、验证权限;

2、然后是分析器,负责复习语法,如果这条语句有执行过,在缓存内,那么就从缓存去写;

3、缓存没有的话,那就到了优化器部分。负责优化sql读写,选择索引;

4、接下来是执行器,负责操作引擎,并返回结果。

redo log和bin log

 

 

 

接下来就要进入正题,说一下第四步是如何执行的。

redo log

与查询不一样的是,更新流程还涉及两个重要的日志模块,它们正是我们今天要讨论的主角:redo log(重做日志)和bin log(归档日志)。

innodb的更新操作不是直接写入磁盘的,而是先记录日志,也就是redo log,然后等到db没那么忙碌的时候刷到磁盘上。这样保证了mysql的高效写操作。为什么会这么设计呢?因为每次更新操作先要查询,这里有磁盘io,查到后修改数据,刷入磁盘,又是一次io,每次都这样做的话会非常慢,所以就先记录在内存中,然后记录在redo-log中,然后按照策略刷入磁盘。这个技术叫做wal技术。因为如果只记录在内存中的话,mysql崩溃会导致改动的数据丢失。所以redo log保证了innodb的crash-safe。(注意:mysql是没有redo log的,它是innodb特有的。不过现在mysql大部分情况下都会选用innnodb。)mysql crash后,故障恢复会从redo log中读取数据。

不过redo log是有大小限制的,比如设置了4个1g的redo log,那么第3个写满的时候会覆盖第0个的log文件。

bin log

redo log是在存储引擎层面的日志,负责存储和crash恢复。bin log 是server层的日志。

为什么会有两份日志呢?

因为只依靠bin log是没有crash safe能力的。而且redo log是有大小限制的。

redo log和bin log主要有如下几个区别:

1、所属层不一样,bin log是server层,redo log是存储层的日志,只有innodb才有。

2、redo log有大小限制,是循环写的,而binlog没有这样的限制;

3、redo log是物理日志,记录的是“在某个数据页上做了什么修改”,bin log是逻辑日志,记录的是语句的原始逻辑,比如给id=3的这一行的count做加一操作。

接下来看一下一条update语句的执行过程:

1、首先查到这一行或者多行数据;

2、然后修改数据,写入内存,并将修改写入redo log,此时redo log处于prepare阶段,并告诉执行器可以提交了;

3、返回ok给server的执行器,执行器收到ok后在binlog中记录原始语句,写入磁盘;

4、binlog记录完成后,执行器告诉引擎层,引擎层将对应的redo log从prepare状态改成commit状态。

这就是2pc。

如果我们要将数据库恢复到某一个时刻点,比如本周二,那么找到周二前最近的全量备份,然后执行备份时间到本周二的binlog,得到一个临时的数据库。

可不可以不要做两阶段提交,而改成把这两步操作独立做呢?可以考虑一下如下两个场景(把某一行的count列从0改成1):

1、先做redo log,后写bin log

如果先写redo log成功后,还没写binlog就崩了,此时count列已经变为1,而数据恢复时,用的是bin log,bin log里少了这一个操作,那么就出现用bin log恢复出来的db和当前的db比,出现了不一致。

2、如果先做bin log,然后写redo log

如果写完bin log后,redo log还没写,就崩了,也就是说崩溃时的db是没有count=1这个修改的。而用bin log恢复出来的db里是有这行记录的,那么也出现了不一致。

所以,update时针对redo log和bin log做2pc还是很有必要的。

 

此外。redo log有个配置项innodb_flush_log_at_trx_commit设置成1,保证每次事务后时redo log都能更新到磁盘。这样就不会出现丢失的现象。

innodb_flush_log_at_trx_commit=0表示每秒写入磁盘。这样有可能最多丢失1秒钟的数据。

设置为2时,表示每次事务后将redo log的缓存写入os buffer,然后是每秒调用fsync()将os buffer中的日志写入到log file on disk。这样的话,如果系统崩了会丢失一秒的数据,如果mysql崩了,则不会丢失数据。

sync_binlog也建议设置成1,表示每次事务后的binlog会持久化到磁盘,这样可以保证mysql异常重启后的binlog不会丢失记录。

 

最有有个问题,写日志也是写磁盘,直接更新数据也是写磁盘,都是写磁盘,效率不是一样的吗?这样innodb的redo log不是多此一举吗?因为redo log是追加的形式写磁盘,所以效率很高,而修改数据库的数据是随即写,效率就低了很多。