MySql中的日志


binLog

binlog 是 MySQL 的 Server层实现的,所有引擎都可以使用。

Binlog日志最重要的两个使用场景如下:

  • 主从复制:在主库开启Binlog功能,使主库可以将Binlog传递给从库,从库获取Binlog并实现数据恢复,实现主从数据一致性。
  • 数据恢复:通过mysqlbinlog工具恢复数据.

三种格式

  • STATEMENT 记录SQL语句。日志文件小,节约IO,但是对一些系统函数不能准确复制或不能复制,如now()、uuid()等
  • ROW 记录表的行更改情况,可以为数据库的恢复、复制带来更好的可靠性,但是二进制文件的大小相较于STATEMENT会有所增加

  • MIXED STATEMENT和ROW模式的混合。默认采用STATEMENT格式进行二进制日志文件的记录,但是在一些情况下会使用ROW格式。

业内目前推荐使用的是ROW模式,准确性高,虽然说文件大,但是现在有SSD和万兆光纤网络,这些磁盘IO和网络IO都是可以接受的。

主从复制

主流程

  1. binlog dump线程: 主库中有数据更新时,根据设置的binlog格式,将更新的事件类型写入到主库的binlog文件中,并创建log dump线程通知slave有数据更新。当I/O线程请求日志内容时,将此时的binlog名称和当前更新的位置同时传给slave的I/O线程。
  2. I/O线程: 该线程会连接到master,向log dump线程请求一份指定binlog文件位置的副本,并将请求回来的binlog存到本地的relay log中。
  3. SQL线程: 该线程检测到relay log有更新后,会读取并在本地做redo操作,将发生在主库的事件在本地重新执行一遍,来保证主从数据同步。

复制过程:

  1. 主库写入数据并且生成binlog文件。该过程中MySQL将事务串行的写入二进制日志,即使事务中的语句都是交叉执行的。
  2. 在事件写入二进制日志完成后,master通知存储引擎提交事务。
  3. 从库服务器上的IO线程连接Master服务器,请求从执行binlog日志文件中的指定位置开始读取binlog至从库。
  4. 主库接收到从库的IO线程请求后,其上复制的IO线程会根据Slave的请求信息分批读取binlog文件然后返回给从库的IO线程。
  5. Slave服务器的IO线程获取到Master服务器上IO线程发送的日志内容、日志文件及位置点后,会将binlog日志内容依次写到Slave端自身的Relay Log(即中继日志)文件的最末端,并将新的binlog文件名和位置记录到master-info文件中,以便下一次读取master端新binlog日志时能告诉Master服务器从新binlog日志的指定文件及位置开始读取新的binlog日志内容。
  6. 从库服务器的SQL线程会实时监测到本地Relay Log中新增了日志内容,然后把RelayLog中的日志翻译成SQL并且按照顺序执行SQL来更新从库的数据。
  7. 从库在relay-log.info中记录当前应用中继日志的文件名和位置点以便下一次数据复制。

redoLog

redoLog 是InnoDB特有的

为什么要有redo log

一般当MySQL更新数据时,有两种情况,追加数据或定位到已经存在的一条数据进行修改。

然而磁盘随机读写速度很慢,无法满足高IO操作的场景。

为了提高写入效率,一般我们可以先将数据写入内存,空闲时再批量刷入磁盘。

但是这样就产生了一个问题:内存中的数据不是持久化的,如果掉电,数据就会丢失。

为了解决数据丢失的问题,MySQL引入了redo log来解决这个问题。

关于WAL(Write-Ahead Logging)

对于非内存数据库,磁盘I/O操作是导致数据库性能低下的主要原因。

在数据量相同的情况下,使用WAL日志的数据库系统,可以成倍减少磁盘写入操作,大大提高了数据库磁盘I/O操作的效率,从而提高了数据库性能。

WAL的优势

  • 读取和写入可以完全并发执行而不会相互阻塞(但写入仍然不能相互并发)。
  • WAL在大多数情况下具有更好的性能(因为不需要每次写入两个文件)。
  • 磁盘I/O行为更具可预测性。
  • 减少刷盘fsync()操作,提高系统健壮性。

当需要更新记录时,InnoDB引擎先写redo log并更新内存。在适当的时候,例如当磁盘空闲时,将redo log数据刷新到磁盘。

redo log的大小是固定的 类似环形队列

为什么有两个日志

MySQL一开始没有InnoDB引擎,MySQL自带的引擎是MyISAM,但是MyISAM没有处理崩溃恢复数据的能力,bin-log日志只是用来归档。

InnoDB后来作为插件添加,它实现了自己的日志系统来保护数据,防止崩溃丢失数据问题。

bin log和redo log的区别

  1. 内容不同:redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”

  2. 不同级别:redo log只能和InnoDB引擎一起使用,而bin-log位于MySQL服务器级别,可用于所有引擎。

  3. 磁盘存储形式不同:redo log循环写入,bin-log是累积追加的,所以可以用于数据恢复或者主备同步

  4. 写入的时间不同:bin-log通常在一个事务提交时写入,而redo log会在不同的时间点写入,如每次事务提交时,通过另一个线程事务执行,或在刷盘时写入。(注意:未提交的事务redo log也可能被刷新到磁盘)

  5. 作用不同:redo log用于crash恢复,保证MySQL宕机不丢失数据;bin-log用于指定时间点恢复数据,保证服务器可以根据时间点恢复数据,另外bin-log也用于主从复制。

两阶段提交

由于redo-log是在InnoDB层,而bin-log是在 Server 层,这样就引入了一个新的问题。

如果redo log写入成功,但是在bin-log写入磁盘之前,程序crash了,说明事务还没有提交,所以redo-log里写入的新数据是无效的。

重新启动数据库进行数据恢复会将redo-log数据恢复到磁盘,从而创建无效数据。

为了解决这个问题,引入了两阶段提交。

在第一阶段,redo-log写入并处于准备状态。Server层将bin-log数据保存到磁盘,然后执行器调用引擎的提交事务接口提交事务,把redo-log变更为已提交状态,更新完成。

通过两阶段提交协议保证了redo-log数据和bin-log数据的一致性。

update执行流程

  1. 执行器先找引擎取 ID=2 这一行。ID 是主键,引擎直接用树搜索找到这一行。如果 ID=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。
  2. 执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口写入这行新数据。
  3. 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。
  4. 然后告知执行器执行完成了,随时可以提交事务。执行器生成这个操作的 binlog,并把 binlog 写入磁盘。
  5. 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成。
  • 作者:低调做个路人 (扫码联系作者)
  • 发表时间:2022-04-20 13:23:40
  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 评论