若有收获,请记得分享和转发哦
研发的童鞋每次对MySQL库表做重大操作之前,例如:
(1)修改表结构;
(2)批量修改或者删除数据;
都会向DBA申请进行数据库的备份。
那DBA童鞋是怎么进行MySQL备份的呢?
调研了几十个RD和QA,基本是3种答案:
(1)不太清楚;
(2)在线逻辑备份,mysqldump;
(3)离线物理备份(冷备),拷贝从库库文件;
那实际上,DBA是如何对MySQL进行库备份的呢?
现在基本上使用的是PXB方案。
今天,和大家说说MySQL备份的来龙去脉,以及内核原理。
离线物理备份,拷贝从库库文件又是咋回事?
为了提高备份效率,缩短备份时间,这也就引发了第二种方案,直接物理备份库文件。
那么,PXB是如何实现:
(1)保持数据库持续提供线上服务,库文件不断变化时;
(2)通过MySQL文件;
(3)来进行库文件物理热备份的呢?
为了把问题讲透,这就要从redo log,从LSN,从MySQL的故障恢复(crash-recovery)机制聊起。
一、redo log
(1)log buffer:应用层缓冲;
(2)OS cache:操作系统缓存;
(3)redo log file:物理文件;
完全不用,redo log只需要记录:
(1)某个数据页中(page num);
(2)某个某个偏移位置(offset);
(3)某个类型的数据(type);
(4)改成了什么值(value);
如此一来,redo log既能够实现以页为单位顺序刷盘数据,又极大缩小了日志大小,其性能又进一步的增加了。
update set sex=1 where name='shenjian'
仍以这个SQL为例,假设它修改了第1234页,偏移量为5678处,1个字节的数据,这个字节的sex由0改成了1,那么,很容易想到redo log是类似于这样的一个结构:
听上去叫日志序列号,但LSN并不只存在redo log中,它还存储在数据页里。
数据页(page)里存储的LSN,可以用来标记数据页的“版本号”,记录该数据页最后一次被修改的日志序列的位置。
举个例子,假设逻辑上连续执行了两个事物,且都已经提交:
trx1:
update set sex=0 where name='shenjian'
redolog lsn=1000
trx2:
update set sex=1 where name='shenjian'
redolog lsn=1001
又假设,第一个事务trx1已经刷盘,而第二个事务trx2还没有刷盘,只写了redo log。
LSN有什么用呢?
它和MySQL的故障恢复(crash-recovery)机制紧密相关。
四、InnoDB故障恢复(crash-recovery)
这里的故障恢复,是指MySQL非正常退出,然后再次启动之前,要恢复数据一致性的操作。
第四步,purge操作。
第一个步骤中,redo log操作是如何恢复最新的数据页的呢?
(1)从redo log中读取checkpoint lsn,它记录的是最后一次刷盘的页,对应日志的LSN;
(2)如果redo log中记录的日志LSN小于checkpoint,说明相关数据已经被刷盘,不用额外操作;
(3)如果redo log中记录的日志LSN大于checkpoint,说明相关数据只写了redo log,没来得及刷盘,就需要对相关数据页重做日志,例如:
崩溃恢复过程中,MySQL的启动日志更形象的说明了这一点:
(1)先找到checkpoint;
(2)然后不断的扫描大于checkpoint的redo log,不断的恢复数据;
最后,通过备份的数据文件,重放redo log,执行类似于MySQL崩溃恢复过程中的动作,就能够使得数据文件恢复到能保证一致性的checkpoint检查点。