因为每次对磁盘随机读写影响性能,尤其是高并发的时候,所以引入了Buffer Pool, 即只要更新Buffer Pool中的记录,则算更新成功,那如果更新完了还没有flush到磁盘则宕机了,此时内存的这些修改后的记录就会丢失。所以引入了redo log,在写入内存的时候,同样写入到redo log。
如果在事务期间,需要执行多条SQL,如果更新某一条SQL失败,需要回滚,这时候前面的已经写入到内存了,怎么回滚呢? 所以引入了undo log, 在写入内存之前,记录修改数据之前的记录。
一 redo log
1.1 redo log 格式
MySQL记录修改后或者新增的数据,是直接把数据写入redo log吗?肯定不是,那么需要记录哪些内容呢?
#1 日志类型
#2 表空间ID(记录位于哪一个表空间,如果存在多个)
#3 数据页号(位于表空间中哪一个数据页)
#4 数据页中的偏移量
#5修改的数据的长度(可选,一般针对string类型,不知道修改了多少字节数据)
#6 具体修改的数据(修改的数据)
1.2 redo log buffer和redo log block
redo log是产生一条,写入一条到磁盘吗? 不是的,它是在数据库启动的时候,根据redo log buffer大小(innodb_log_file_size)分配内存空间,然后写入一个512字节大小日志块(redo log block), redo log block包括12字节的块头,496字节的body和4字节的尾部,如图所示:
如果redo log block写满了则在创建一个 redo log buffer继续写,当redo log buffer写满了则刷到磁盘。另外redo log block的header主要包括以下信息:
#1 block_no: 块号
#2 data_length: 当前写入了多少字节的数据
first_record_group: 一个事务可能有多个redo log, 一个事务就属于一个redo log分组,第一组redo log的偏移量
checkpoint_no: 检查点号
1.3 redo log buffer刷盘时机
#1 如果写入的redo log已经超过了redo log buffer的一半
#2 提交事务的时候会把redo log block写入磁盘
#3 有后台线程定时刷新
#4 MySQL实例停止
1.4 如果redo log file文件满了怎么办
redo log文件默认有2个文件,ib_logfile0和ib_logfile1,当ib_logfile0写满了则写入ib_logfile1,当ib_logfile1写满了则写入ib_logfile0,如此循环
二 undo log
2.1 undo log格式
2.2 undo log 回滚流程
#1 从undo log找到刚刚执行的操作
#2 如果是新增,则根据主键删除;如果是更新则根据id和旧值还原
三 binlog
binlog是归档日志,是MySQL服务器的通用日志,主要是记录的是偏逻辑性质的数据,而不是物理数据。在提交事务的时候,先把redo log刷盘之后,就把binlog cache刷盘,然后再确认对redo log的刷盘
3.1 binlog有哪些格式
3.1.1 statement
完全照搬执行的语句,不作任何压缩等,即SQL语句是什么,这里就记录什么,不会记录多余的元数据
优点:
#1 没有额外的信息,所以更加节省空间
#2 没有额外的信息,则在提交事务时候fsync刷盘的性能更好
缺点:
没有记录相对位置等元数据,很容易造成主从同步的时候主从不一致的情况,比如delete from test limit 10;时还会产生一个警告,大意就是使用statement格式时执行limit语句可能造成主从同步不一致。因为limit语句只是指定了删除10条记录,但没有指定具体是哪10条,当mysql在两次执行时选择了不同的索引进行操作时,删除的记录就是不同的。
3.1.2 row
对于DDL操作记录执行的SQL语句,但是对于DML语句则记录具体的数据行一般生产环境采用这种格式
优点:
可以屏蔽statement缺点,不会造成主从不一致
缺点:
#1 由于记录了每条数据的内容变更,导致了binlog日志占用了很大的空间,由于fsync时一次写入数据过多,在一定程度上影响了性能。
#2 另外,binlog 日志文件在写入日志的时候会被锁住,如果数据太多可能会导致性能问题。可以添加参数 binlog_row_image=minimal 来减少这个缺点
3.1.3 mixed
对于DDL,只记录SQL语句;对于DML,则根据判断是否有可能造成主从不一致,如果有可能则使用row这种格式,否则使用statement
优点:
相对节省空间,提高了性能;也可以避免主从同步不一致
3.2 binlog cache和临时文件
当执行增删改SQL语句时候,会为当前线程分配一块叫做binlog cache的内存块,用于缓存执行SQL语句产生的binlog event事件,大小由binlog_cache_size控制。如果binlog cache达到binlog_cache_size,则将binlog cache内容移到一个临时文件中保存,但是这个文件不能超过max_binlog_cache_size,如果超过则报错;客户端断开连接,binlog cache释放
3.3 binlog的刷盘时机和策略
binlog在事务提交的时候,且在redo log buffer里的数据刷到磁盘(prepare阶段),再将binlog刷入磁盘。
binlog的刷盘策略可以通过sync_binlog参数来控制:
sync_binlog = 0: 表示每次提交事务都只 write,不 fsync。即提交事务时候,将binlog写入磁盘并不是直接写入,而是写入操作系统缓存,即os cache中,当然如果这个时候宕机,os cache中的binlog会丢失
sync_binlog = 1: 表示每次提交事务都会执行 fsync。即此时会在提交事务的时候强制将binlog刷入磁盘文件,这样宕机了也不怕binlog丢失
sync_binlog = N: 表示累计N个事务后才会执行fsync,即刷入磁盘
四 redo log和binlog比较
#1 一个存储的是偏逻辑的日志;一个存储的是偏物理的日志
#2 binlog一般用于备份和同步;redo log一般用于数据重启恢复
#3 提交事务的时候一般是先写redo log,再写binlog
#4 binlog 和 redo log都有缓存,不同的是binlog是每一个线程或者事务都有自己的binlog cache,但是binlog 是共享缓存