这是一篇关于MySQL数据 库,redo log,LSN,崩溃恢复,在线热备的长文,耐心读完,如果没有收获,可以捶我。
研发的童鞋每次对MySQL库表做重大操作之前,例如:
那实际上,DBA是如何对MySQL进行库备份的呢?
今天,和大家说说MySQL备份的来龙去脉,以及内核原理。
mysqldump是MySQL工具 集中的一个工具,可以用来导出或备份数据。
mysqldump的产出物是一个包含了建表,插入数据的SQL语句集合,类似于这样:
-- MySQL dump 1.2.3
-- Host: localhost Database: test
-- Server version 4.5.6
CREATE TABLE t_user (
id int(11)NOT NULL unique,
name varchar(40) NOT NULL default '',
PRIMARY KEY (id)
);
INSERT INTO t_user VALUES (1,'shenjian');
INSERT INTO t_user VALUES (2,'zhangsan');
INSERT INTO t_user VALUES (3,'lisi');
使用mysqldump进行备份的优点 是:可以在线进行,不影响数据库 对线上持续提供服务。
缺点 也显而易见:相比物理备份拷贝库文件,备份和恢复都要慢非常多。
为了提高备份效率,缩短备份时间,这也就引发了第二种方案,直接物理备份库文件。
如上图所示,数据库集群设置为左侧的1主2从架构 ,离线物理备份是如何实施的呢?
(1)第一步,将一个从库从集群里摘下并下线,此时离线库文件不会再发生变化;
(2)第二步,scp拷贝库文件,即完成了库的物理备份;
缺点 也显而易见:备份过程中从库无法对线上持续提供服务。
那么问题来了,有没有一种方案,又能够快速备份物理文件,又能够持续对线上提供服务呢?
PXB的全称是, Percona XtraBackup ,官网是这么吹的:PXB是全世界唯一一款开源免费的,支持MySQL热备的,非阻塞备份工具。
画外音: Percona XtraBackup is the world’s only open-source, free MySQL hotbackup software that performs non-blocking backups tool.
(1)保持数据库持续提供线上服务,库文件不断变化时;
为了把问题讲透,这就要从redo log,从LSN,从MySQL的故障恢复 (crash-recovery) 机制聊起。
事务提交后,必须将事务对数据页的修改刷 (fsync) 到磁盘上,才能保证事务的ACID特性。
这个刷盘,是一个随机写,随机写性能较低,如果每次事务提交都刷盘,会极大影响数据库的性能。
(1)先写日志 (write log first) , 将随机写优化为顺序写 ;
第一个优化,将对数据的修改先顺序写到日志里,这个日志就是redo log。
假如某一时刻,数据库崩溃,还没来得及将数据页刷盘,数据库重启时,会重做redo log里的内容,以保证已提交事务对数据的影响被刷到磁盘上。
一句话, redo log是为了保证已提交事务的ACID特性,同时能够提高数据库性能的技术。
逻辑上,MySQL以行 (row) 为单位管理数据;物理上,MySQL以页 (page) 为单位管理数据,MySQL的缓冲池 (buffer) 机制,也是以页为单位管理数据,事务提交之后,不用每次都随机写落盘刷新数据页,而是通过顺序写redo log来提高性能,那么redo log是直接保存等待刷盘的数据页吗?
如果redo log直接保存待刷盘的数据页,存在这样的问题,假如某个SQL语句只修改了一行记录里的一个属性,例如:
update set sex=1 where name='shenjian'
物理上,其实只修改了1个字节,难道redo log要将这个属性所在的一页数据(16K)全部保存下来吗?
如此一来,redo log既能够实现以页为单位顺序刷盘数据,又极大缩小了日志大小,其性能又进一步的增加了。
update set sex=1 where name='shenjian'
仍以这个SQL为例,假设它修改了第1234页,偏移量为5678处,1个字节的数据,这个字节的sex由0改成了1,那么,很容易想到redo log是类似于这样的一个结构:
如此一来,当数据库崩溃的时候,如果缓冲池中的数据没有来得及刷盘,就可以通过redo log,把第1234页,偏移量为5678处的1个字节改为1,以此来恢复数据。
当然,MySQL会通过一系列的数据结构 对redo log来进行管理,最小单位的redo log是一个512字节的数据块 (block) ,这个数块由12字节的header,508字节的body,4字节的trailer组成,body里保存的就是上述数据页如何进行修改的记录。
记录redo log的文件有若干个,每个都固定大小,循环使用。
画外音:为了使得行文通俗易懂,本文尽量没有提及 Mini-Transaction(mtr) 的概念。
要聊redo log,要聊故障恢复,LSN是一个绕不开的概念。
LSN, Log Sequeue Number ,直译过来叫日志序列号 ,是InnoDB中,随着日志的写入,一个只增不减的8字节序列号。
听上去叫日志序列号,但LSN并不只存在redo log中,它还存储在数据页里。
画外音:缓冲池中的数据页,磁盘上的数据页都存储了LSN。
数据页(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。
画外音:最近一次刷盘的页,即最近一次检查点(checkpoint),也是通过LSN来记录的,它也会被写入redo log里。
为了提高数据库性能,数据库基本都是使用 WAL(Write Ahead Log) 的方式,先写日志再刷盘,所以很容易能够想到,磁盘数据页里的LSN,会小于最新redo log中的LSN。
画外音:此时,redo log中记录的checkpoint也是1000。
它和MySQL的故障恢复 (crash-recovery) 机制紧密相关。
四、InnoDB故障恢复 (crash-recovery)
这里的故障恢复,是指MySQL非正常退出,然后再次启动之前,要恢复数据一致性的操作。
第一步, redo log操作 :保证已提交事务影响的最新数据刷到数据页里。
第二步, undo log操作 :保证未提交事务影响的数据页回滚。
第三步, 写缓冲 (change buffer) 合并 。
画外音:InnoDB的一种垃圾收集机制,使用单独的后台线程周期性处理索引中标记删除的数据,也不是今天的重点,未来可以详细讲。
第一个步骤中,redo log操作是如何恢复最新的数据页的呢?
(1)从redo log中读取checkpoint lsn,它记录的是最后一次刷盘的页,对应日志的LSN;
(2)如果redo log中记录的日志LSN小于checkpoint,说明相关数据已经被刷盘,不用额外操作;
(3)如果redo log中记录的日志LSN大于checkpoint,说明相关数据只写了redo log,没来得及刷盘,就需要对相关数据页重做日志,例如:
将第1234页,偏移量为5678处的1个字节改为1,以此来恢复数据。
崩溃恢复过程中,MySQL的启动日志更形象的说明了这一点:
(2)然后不断的扫描大于checkpoint的redo log,不断的恢复数据;
画外音:redo log的LSN可以看到恢复的进程。
第一, 幂等性 ,同一条redo log执行多次,不影响数据的恢复。
第二,崩溃恢复时, 从比checkpoint更早的LSN开始执行恢复,也不影响数据最终的一致性 ,因为一个数据页,最终一定会被更大值的LSN日志恢复到最新的数据上来;
(1)保持数据库持续提供线上服务,库文件不断变化时;
首先 ,PXB启动一个线程,并不断监听并复制redo log的增量到另外的文件,不能直接备份redo log的原因是,redo log循环使用的,PXB则必须记录下checkpoint LSN之后的所有redo log。
然后 ,PXB启动另一个线程,然后开始复制数据文件,复制数据文件过程可能会比较长,整个过程中数据文件可能在不停的修改,导致数据不一致。但没有关系,所有的修改都已经记录在了第一步中,额外记录的redo log里。
画外音:务必注意,备份redo log的线程,必须在开始备份数据文件之前启动,之后结束。
最后 ,通过备份的数据文件,重放redo log,执行类似于MySQL崩溃恢复过程中的动作,就能够使得数据文件恢复到能保证一致性的checkpoint检查点。
画外音:PXB还可以对非MySQL,非InnoDB进行在线热备,这里就不展开了。
这是一篇关于MySQL数据库,redo log,LSN,崩溃恢复,在线热备的长文,耐心读完,如果没有收获,可以捶我。
MySQL内核相关文章 :
《缓冲池(buffer pool),这次彻底懂了! 》
《写缓冲(change buffer),这次彻底懂了! 》
《日志缓冲(log buffer),这次彻底懂了! 》
《double write buffer,这次彻底懂了! 》
都看到这里了,不来个三连吗? 谢转 !
发布者:糖太宗,转载请注明出处:https://www.qztxs.com/archives/science/technology/5939