BinLog的基本原理

发布时间 2023-10-15 18:27:58作者: cs7

BinLog 记录模式与文件结构

 

BinLog基本概念

Binlog是记录所有MySQL表结构变更以及表数据发生变更的二进制日志。binlog中不会记录select、show等的查询操作,binlog是以事件形式记录相关的变更操作,并且还会包含语句执行所消耗的时间,它从整体上有两个最重要的场景:主从复制、数据恢复。

 

BinLog记录模式

总体上binlog有三种记录模式:

1.Row模式:binlog中记录每一行数据被修改的情况,在mysql中对相同数据做同样的修改。能够完全实现主从数据库的同步和恢复操作。缺点是大批量操作会产生大批量的操作日志 如:alter操作。二进制越来越多就会影响数据库的同步性能。

2.statement模式:binlog会记录修改语句的sql语句,mysql从库在复制sql语句的时候,会通过sql进程将binlog中的sql语句解析成和mysql主库上执行过的sql语句相同的sql语句,然后上从库上执行。优点在于产生少量的二进制文件,减少磁盘的io操作,提升数据存储和恢复的效率。缺点在于某些情况下导致主从数据库数据不一致,比如mysql主库中使用了last_insert_id()和now()这样的函数就会导致不一致。

3.mixed模式:row模式和statement模式混合,正常语句使用statement保存,last_insert_id()和now()使用raw。

 

Bin Log的文件结构

mysql的binlog文件中保存的是对数据库、数据表和数据表中数据的各项更新操作,用来表示修改操作的叫log event,不同的操作对应不同的log event,比较常用的log event有query event、row event、xid event,里面就是各种event的集合。

 

Bin Log的写入时机

Bin Log提交的时候,会记录事务日志和二进制日志。也就是redo log 和binlog,这里就存在一个问题,事务日志和二进制日志,MySQL先记录的是二进制日志。

 

Bin Log的写入规则:

1.触发event事件生成Log Event:主要是根据记录的模式,比如row、statement、mixed以及操作比如create、drop、alter、insert、update等触发event事件生成log event。也就是事件触发执行机制。

2.将事务执行过程中产生的日志事件(Log Event)写入相应的缓冲区:每个事务都有一个缓冲区,Log Event 保存在一个binlog_cache_mngr的数据结构中,这个数据结构有两个缓冲区,一个是stmt_cache用于不支持事务的信息,另一个是trx_cache用于存放支持事务的信息。

3.事务在提交阶段会将产生的日志事件(Log Event)写入磁盘的BinLog文件中:事务在提交阶段会将产生的日志事件写入磁盘的binlog文件中,不同的事务以穿行的方式将日志事件写入binlog文件中,所以一个事务中包含的log event信息在binlog文件中是连续的,中间不会插入其他事务的log event事件,一个事务的binlog是完整。

 

Bin Log组提交机制:

1.BinLog组提交机制:为了提高MySQL中日志刷盘效率,MySQL提供了组提交,group commit会调用fsync()函数将多个事务日志刷新到磁盘的日志文件中,而不是每次将每个事务的日志单独刷新到磁盘的日志文件。

在innodb存储引擎中,提交事务会进行两个阶段的操作:1.修改内存中事务对应的信息,并且会将日志写入相应的redo log buffer。2.调用fsync()函数将redo log buffer中的日志信息刷新到磁盘的redo log文件中。其中步骤2存在磁盘操作比较耗时,所以事务提交后,先将日志信息写入redo log buffer,最后调用fsync()函数将多个事务日志信息从内存的redo log buffer刷新到磁盘的redo log文件。为了保证binlog 和 事务日志的一致性,会在步骤1的prepare阶段会启用一个prepare_commit_mutex锁,这个时候会导致开启二进制后的group commit功能失效(5.6后,BLGC解决这个问题)。

BLGC

1.flush:将每个事务的binlog写入对应的内存缓冲区

2.sync:将内存缓冲区的binlog写入磁盘的binlog文件,如果存在多个事务,只执行一次刷盘

3.commit:leader事务根据队列中的事务顺序调用存储引擎层事务的提交,由于innodb存储引擎本身就支持group commit,所以解决了 prepare_commit_mutex锁导致的group commit失效的问题。

在flush阶段写入binlog到内存缓冲区时,不是写完就立即进入sync阶段,而是等待一定时间,多积累几个事务的binlog一起进入sync阶段,这个时间由binlog_max_flush_queue_time变量决定,默认值为0,除非由大量的事务不断写入和更新操作,否则不建议修改,不然会导致事务的响应速度变慢。当进入到sync阶段时,会将内存缓冲区多个事务的BinLog刷新到磁盘的BinLog文件中,和刷新一个事务的BinLog一样,都是由sync_binlog变量控制。如果一组事务正在执行commit阶段的操作时,其他新产生事务可以执行flush操作,commit阶段和flush阶段不会互相阻塞。这个时候group commit就会不断生效。group commit的性能与队列中的事务数量有关,如果队列只存在一个事务的话和单独提交一个事务差不多,甚至性能更差,提交的事务越多,group commit的性能就更明显。