MySQL深入——14

Mysql是如何保证数据不全的,Mysql的数据写入是两阶段提交完成的,即为redo log的prepare阶段和bin log阶段还有redo log的commit阶段,那么数据就和redo log 和bin log 有关。

我们来看看bin log 和redo log的写入机制

bin log

bin log的写入逻辑较为简单

在事务执行过程当中,先将日志写入到binlog cache,事务commit时,再将binlog cache写入到bin log文件当中。

一个事务的bin log是不能被拆开的,无论其有多大,也要确保一次写入,因为bin log是由binlog cache一次写入的,这也就确保了binlog cache是不能被拆开的,这就涉及到了binlog cache的保存方式。

系统给binlog cache分配了一块内存,每个线程一个,参数bin_log_cache_size用于控制单个线程中的binlog cache所占内存的大小,如果超出范围,就会暂存于磁盘当中。

每个线程都有自己的binlog cache文件,但是共用一个bin log文件。binlog cache先write到bin log当中在fsync到disk中。write指将日志写入到系统文件的page cache当中,并没有把数据持久化到磁盘当中,fsync是将数据持久化到磁盘的操作,占磁盘的IOPS(IOPS主要衡量单位时间内系统能处理的I/O请求数量,而数据吞吐量则指单位时间内可以成功传输的数据数量。)。

write和fsync的时机由参数sync_binlog控制。

当这个参数等于0的时候,每次事务只会write不会fsync

等于1的时候都会fsync

等于N的时候都会write当事务数量达到N的时候会将其fsync到磁盘当中。

将sync_binlog设置为较大值的时候可以提示性能,因为一次写入了很多文件。但是坏处在于当机器异常重启的时候,会丢失最近N个事务的binlog。

Redo log

我们之前了解过redo log buffer,事务在执行过程当中,生成的redo log是要写入到redolog buffer中的,那么redo log buffer的内容是不是每次生成后都要持久化到磁盘当中呢?

不对,在这期间,如果Mysql发生了异常重启,这部分的日志就会丢失,但是由于事务没有commit,所以丢失了也不会有损失。那么没有提交事务的时候,redo log buffer的部分日志会持久化到磁盘当中吗,答案是会,这和redo log的三种状态有关,分别是redo log buffer,page cache,hard disk。

日志写入到redo log buffer当中是很快的,write到page cache中也差不多,但是持久化到磁盘当中就很慢了。为了控制其写入策略,InnoDB提供了innodb_flush_log_at_trx_commit的参数。当它等于0的时候只是将redo log留在redo log buffer当中,等于1的时候会直接持久化到磁盘当中,等于2的时候会write到page cache当中。

Innodb当中有一个线程,每隔一秒就会把redo log buffer当中的日志调用write写入到page cache当中,然后调用fsync持久化到磁盘中。

事务执行过程在的redo log也是写在redo log buffer当中的,这些redo log也会被后台线程一起持久化到磁盘当中,也就是说没有提交的redo log中的部分日志是会被写入到磁盘当中的。

事实上除了这种情况,还有两种情况导致这种情况

1.redo log buffer占用空间达到innodb_log_buffer_size一半的时候,会自动写盘。

2. 并行的事务提交的时候会写盘,比如将innodb_flush_log_at_trx_commit参数设计为1,B线程提交的时候,会顺带将A线程持久化就算它还没提交。

如果把参数设置为1,在两阶段提交当中,redo log在prepare阶段就会持久化一次,崩溃恢复机制是要依靠prepare的redo log再加上bin log来恢复的,每一秒的后台刷新再加上这个机制,Innodb就会认为redo log再commit阶段不需要fsync,只需要write即可。

Mysql的双1配置就是innodb_flush_log_at_trx_commit等于1和sync_binlog等于1,会有两次刷盘,一次是在redo log prepare阶段,一次是bin log阶段。

TPS(Transaction Per Second)事务数/秒

Mysql为了提供TPS做了一个优化,就是拖时间,为了让fsync一次持久化的数据更大,他进行了下面的操作

1. redo log prepare (write)

2. bin log (write)

3.redo log prepare(fsync)

4.bin log(fsync)

5.redo log commit(write)

这样处理下来再第三步的时候,就会fsync bin log 和redo log 的数据,那么到第四步的时候能持久化报错的bin log数据就很少了,所以bin log(fsync)的效果不如 redo log prepare(fsync)。

你如果要提高bin log(fsync)的能力,可以使用binlog_group_commit_sync_delay表示等待多少微秒后调用fsync。binlog_group_commit_sync_no_delay_commit表示在积累多少次后调用fsync。

那么在优化的时候就可以考虑sync_binlog设置为N,将binlog_group_commit_sync_delay和binlog_group_commit_sync_no_delay_commit调高。再或者将innodb_flush_log_at_trx_commit设置为2,因为它会每一秒自动写入磁盘的。

你可能感兴趣的:(Mysql数据库基础及深入理解,mysql,数据库)