1. 只要redo log和binlog保证持久化到磁盘,就能确保mysql异常重启后,数据可以恢复。
    2. binlog的写入机制
      1. 事务执行过程中,先把日志写到binlog cache,事务提交的时候,再把binlog cache写到binlog文件中,
      2. 一个事务的binlog是不能被拆开的,无论这个事务有多大,也要确保一次性写入。
      3. 系统给binlog cache分配了一片内存,每个线程一个,参数binlog_cache_size用于控制单个线程内binlog cache所占内存的大小。如果超过了这个参数规定的大小,就要暂存到磁盘。
      4. 事务提交的时候,执行器把binlog cache里的完整事务写入到binlog中,并清空binlog cache。
      5. image.png
        1. 每个线程有自己binlog cache,但是共用一份binlog文件。
        2. 图中的write,指的是把日志写入到文件系统的page cache,并没有吧数据持久化到磁盘,所以速度比较快。
        3. 图中的fsync,才是讲数据持久化到磁盘的操作。一般情况下,我们认为fnync才占磁盘的IOPS。
      6. write和fsync的时机,是由参数sync_binlog控制的
        1. sync_binlog=0,表示每次提交事务都只write,不fsync。
        2. sync_binlog=1,表示每次提交事务都会执行fsync。
        3. sync_binlog=N(N>1)的时候,表示每次提交事务到write,但累计N个事务后才fsync。
        4. 因此在出现IO瓶颈的场景里,将sync_binlog设置成一个比较大的值,可以提升性能。在实际的业务场景中,考虑到丢失日志量的可控性,一般不建议将这个参数设成0,比较常见的是将其设置为100-1000中的某个数值。
      7. 讲sync_binlog 设置为N,对应的风险是:如果主机发生异常重启,会丢失最近N个事务的binlog日志。
    3. rido log的写入机制
      1. 事务在执行过程中,生成的redo log是要先写到redo log buffer的。
      2. redo log buffer里面的内容,不是每次生成后都要直接持久化到磁盘的。
      3. 事务还没有提交的时候,redo log buffer中的部分日志有可能被持久化到磁盘的。
      4. redo log 存储状态
        1. image.png
        2. 存在redo log buffer中,物理上是在mysql进程内存中<对应红色部分>
        3. 写到磁盘(write),但是没有持久化(fsync),物理上是在文件系统的page cache里面<对应黄色部分>。
        4. 持久化到磁盘,对应的是hard disk<对应绿色部分>。
        5. 日志写到redo log buffer是很快的,write到page cache也差不多,但是持久化到磁盘的速度就慢多了。
      5. 为了控制redo log的写入策略,innodb提供了innodb_flush_log_at_trx_commit参数:
        1. 当设置为0时,表示每次事务提交时都只是把redo log留在redo log buffer中。
        2. 当设置为1时,表示每次事务提交时都将redo log buffer直接持久化到磁盘。
        3. 当设置为2时,表示每次事务提交都只是把redo log写到page cache。
      6. innodb有一个后台线程,每隔1s,就会把redo log buffer中的日志,调用write写到文件系统的page cachem然后调用fsync持久化到磁盘。
        1. 事务执行中间过程的redo log也是直接卸载redo log buffer中的,这些redo log也会被后台线程一起持久化到磁盘。也就是说,一个没有提交事务的redo log,也是可能已经持久化到磁盘的。
      7. 除了后台线程每秒一次的轮训操作外,还有两种场景会让一个没有提交的事务的redo log写入到磁盘中。
        1. redo log buffer占用的空间即将达到innodb_log_buffer_size一半的时候,后台线程会主动写盘。由于这个事务并没有提交,所以这个写盘动作只是write,而没有调用fsync,也就是只留在了文件系统的page cache。
        2. 并行的事务提交的时候,顺带讲这个事务的redo log buffer持久化到磁盘。假设一个事务A执行到一半,已经写了一些redo log到buffer中,这时候另外一个线程的事务B提交,如果innodb_flush_log_at_trx_commit设置的是1,那么按照这个参数的逻辑,事务B要把redo log buffer里的日子全部持久化到磁盘。这时候,就会带上事务A正在redo log buffer里的日志一起持久化到磁盘。
      8. 两阶段提交,时序上redo log先prepare,再写binlog,最后再把redo log commit。
      9. 组提交-group commit
      10. LSN-日志逻辑序列号(log sequence number)