两阶段提交
在上图里,最后三步将redo log
的写入拆分成了两个步骤:prepaer和commit
,这就是两阶段提交。
为什么必须要这么进行呢?这是为了让两份日志之间的逻辑一致。思考一个问题:怎么让数据库恢复到半个月内任意一秒的状态。
- 首先找到最近的一次全量备份,从这个备份恢复到临时库
- 然后,从备份的时间点开始,将备份的binlog依次取出来,重放到需要的时刻。
反证法来解释为什么需要两阶段提交,如果先写redo log
再写binlog
,或者反过来,会有什么问题呢?
用前面的update语句来做例子,假设当前ID=2的行,字段c的值是0,再假设执行update语句过程中在写完第一个日志后,第二个日志还没有写完期间发生了crash,会出现什么情况?
- 先写
redo log
后写binlog
。假设在redo log
写完,binlog
还没有写完的时候,MySQL
进程异常重启。当redo log
写完后,系统即使崩溃,仍就能把数据恢复回来,所以这一行c
的值还是1。但是binlog
还没写完,所以里面没有这个语句,如果以后用这个binlog
来恢复临时库的话,由于这个语句的binlog
丢失,这个临时库就会少了一次更新,恢复出来c
的值是0 - 先写
binlog
后写redo log
。如果binlog
写完以后crash
,由于redo log
还没写,崩溃恢复以后这个事务无效,所以这一行c
的值是0。但是binlog
里已经记录了这个日志,所以恢复临时库的时候,就多了一个事务,恢复出来这一行c
的值是1
定期全量备份的周期“取决于系统重要性,有的是一天一备,有的是一周一备”。那么在什么场景下,一天一备会比一周一备更有优势呢?或者说,它影响了这个数据库系统的哪个指标?
一天一备会比一周一备好处是“最长恢复时间”更短。
在一天一备的模式里,最坏情况下需要应用一天的 binlog。比如,你每天 0 点做一次全量备份,而要恢复出一个到昨天晚上 23 点的备份。一周一备最坏情况就要应用一周的 binlog 了。
当然这个是有成本的,因为更频繁全量备份需要消耗更多存储空间,所以这个 RTO 是成本换来的,就需要你根据业务重要性来评估了。