如何保证数据不丢失?
保证redo log和binlog可以持久化到磁盘,就可以确保MySQL在异常重启后进行数据恢复。
binlog的写入机制
binlog的写入机制逻辑:
操作系统会给每个线程分配binlog cache,binlog cache的大小由binlog_cache_size参数控制,该参数控制的是单个线程内binlog cache的大小,如果超过了该参数的大小,就需要保存到磁盘。
show global variables like 'binlog_cache_size';
binlog cache如何写入binlog文件?
binlog cache何时write和fsync?
write和fsync是由参数sync_binlog进行控制:
show global variables like 'sync_binlog';
redo log写入机制
binlog cache是每一个线程一个,但是redo log buffer是所有线程共用一个。
redo log会在哪些地方存在?
redo log会在以下三个地方存在:
redo log的写入策略如何控制?
redo log写入策略由innodb_flush_log_at_trx_commit参数控制:
show global variables like 'innodb_flush_log_at_trx_commit';
InnoDB有一个后台线程,每隔1s,会把redo log buffer中的日志调用write写到page cache,然后调用fsync持久化到磁盘。
事务执行过程中redo log也是直接写入到redo log buffer中能够,这写redo log会因为后台线程会被一起持久化到磁盘(没有提交的事务也会被持久化到磁盘)。
除了后台线程每秒1次的轮询之外,还会有以下两种情况下会将redo log写入磁盘:
MySQL 双1配置是?
MySQL 双1配置指的就是sync_binlog和innodb_flush_log_at_trx_commit都设置成1,也就是说一个事务完整提交前,需要等待两次刷盘,一次是redo log(prepare阶段),一次是binlog。
什么是日志逻辑序列号(LSN)?
LSN是用来对应redo log的一个个写入点,是单调递增的,每次写入长度为length的redo log,LSN的值就会加上length。
LSN也会写到InnoDB的数据页中,来确保数据页不会被多次执行重复的redo log。
什么是组提交(Group Commit)?
一次组提交中,组员越多,越能节约磁盘IOPS。在多事务并发更新场景下,第一个事务写完redo log buffer以后,fsync越晚调用,组员就可能越多,节约IOPS效果越好。
binlog的组提交
上面的组提交是redo log组提交,MySQL为了充分提高性能,binlog也会进行组提交。
上图最后三个步骤是redo log和binlog的两阶段提交(该步骤的触发是事务提交的一个阶段,也就是说我们的客户端执行了MySQL的commit命令),在写binlog的时候实际需要两步操作:
上图是两阶段提交的细化,可以看出在执行第4步binlog fsync时,如果有多个事务的binlog已经写完,那么是可以一起持久化的,可以降低IOPS的消耗。
由于步骤3的执行较快,binlog write和fsync间隔时间段,所以binlog的组提交效果较差。
binlog组提交效果提升
如果需要提升binlog组提交的效果,可以通过设置binlog_group_commit_sync_delay和binlog_group_commit_sync_no_delay_count参数来实现:
show global variables like 'binlog_group_commit_sync_delay';
show global variables like 'binlog_group_commit_sync_no_delay_count';
上述两个条件是或关系,只要满足一个就会触发fsync。
redo log的commit阶段
根据两阶段提交的细化流程图,我们可以发现redo log的commit只写了page cache,并没有进行fsync,这是因为借助每秒1次的后台轮询刷盘,再加上崩溃恢复逻辑,InnoDB认为在redo log commit的时候就不需要fsync,只需要写到page cache即可。