1、WAL预写日志机制
从图上看可知,mysql在更新数据时,不会立即更新到磁盘中,而是先写入日志,在合适的时候在写入磁盘。这主要是利用了磁盘顺序写和随机写的性能差异,磁盘顺序写少了寻找写入位置的时间,磁盘的写操作是随机IO,比较耗性能,所以如果把每一次的更新操作都先写入log中,那么就成了顺序写操作,实际更新操作由后台线程再根据log异步写入,这样就可以大幅度提升执行效率
redo log 写入磁盘过程分析:
redo log是从头开始写,写完一个文件,写下一个文件,写到最后一个文件,又会回到第一个文件开头
write pos 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。
checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件里。
write pos 和 checkpoint 之间的部分就是空着的可写部分,可以用来记录新的操作。如果 write pos 追上checkpoint,表示redo log写满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。
redo log 的刷盘条件
1.后台线程,每隔一秒将redo buffer中的数据写入 page cache,然后调用fsync持久化到redo log磁盘是数据
2.等redo log buffer 的大小到 innodb_log_buffer_size的一半的时候,后台线程会进行主动刷盘
3.innodb_flush_log_at_trx_commit:这个参数控制 redo log 的写入策略,它有三种可能取值:
设置为0:表示每次事务提交时都只是把 redo log 留在 redo log buffer 中,数据库宕机可能会丢失数据。
设置为1(默认值):表示每次事务提交时都将 redo log 直接持久化到磁盘,数据最安全,不会因为数据库宕机丢失数据,但是效率稍微差一点,线上系统推荐这个设置。
设置为2:表示每次事务提交时都只是把 redo log 写到操作系统的缓存page cache里,这种情况如果数据库宕机是不会丢失数据的,但是操作系统如果宕机了,page cache里的数据还没来得及写入磁盘文件的话就会丢失数据。
redo log 与 bin log 二阶段提交
更新操作会写入redo log日志,在事务提交时会先写bin log日志,才会更新redo log的commit标志
为什么要二阶段提交
如果不使用二阶段提交,那也只有两种情况,先写redo log后写bin log和 先写bin log,后写bin log
1、第一种情况先写redo log,如果在写完redo log日志之后,出现故障,导致bin log没有写入,数据有可能还没有持久化到磁盘,但是在修复重启之后,通过redo log会将数据恢复。看起来好像没啥问题,就算出现故障了,数据也可以恢复,但是如果之后你想通过bin log将数据恢复到某个时间点,就会出现问题。如果mysql做了主从同步,主库通过redo log,做到数据恢复,但是从库通过bin log同步数据的时候,就无法同步到这个数据,从而导致主从数据不一致,无法做到crash-safe
2.第二种情况先写bin log,向表中插入一条记录 R,先写 binlog 再写 redolog,当binlog写入完成,但是redolog还没写时,就出现了宕机,那么从机根据binlog进行主从同步时,从机是有数据R的。但是主机崩溃恢复时,redolog中是没有记录R的,所以就会出现主从数据不一致的问题。
binlog 的日志格式
用参数 binlog_format 可以设置binlog日志的记录格式,mysql支持三种格式类型:
STATEMENT:基于SQL语句的复制,每一条会修改数据的sql都会记录到master机器的bin-log中,这种方式日志量小,节约IO开销,提高性能,但是对于一些执行过程中才能确定结果的函数,比如UUID()、SYSDATE()等函数如果随sql同步到slave机器去执行,则结果跟master机器执行的不一样。
ROW:基于行的复制,日志中会记录成每一行数据被修改的形式,然后在slave端再对相同的数据进行修改记录下每一行数据修改的细节,可以解决函数、存储过程等在slave机器的复制问题,但这种方式日志量较大,性能不如Statement。举个例子,假设update语句更新10行数据,Statement方式就记录这条update语句,Row方式会记录被修改的10行数据。
MIXED:混合模式复制,实际就是前两种模式的结合,在Mixed模式下,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种,如果sql里有函数或一些在执行时才知道结果的情况,会选择Row,其它情况选择Statement,推荐使用这一种。
binlog写入磁盘机制
binlog写入磁盘机制主要通过 sync_binlog 参数控制,默认值是 0。
为0的时候,表示每次提交事务都只 write 到page cache,由系统自行判断什么时候执行 fsync 写入磁盘。虽然性能得到提升,但是机器宕机,page cache里面的 binlog 会丢失。
也可以设置为1,表示每次提交事务都会执行 fsync 写入磁盘,这种方式最安全。
还有一种折中方式,可以设置为N(N>1),表示每次提交事务都write 到page cache,但累积N个事务后才 fsync 写入磁盘,这种如果机器宕机会丢失N个事务的binlog。
发生以下任何事件时, binlog日志文件会重新生成:
服务器启动或重新启动
服务器刷新日志,执行命令flush logs
日志文件大小达到 max_binlog_size 值,默认值为 1GB