MySQL,在线热备的内核原理!

开发 开发工具 MySQL
这是一篇关于MySQL数据库,redo log,LSN,崩溃恢复,在线热备的长文,耐心读完,如果没有收获,可以捶我。

[[426354]]

研发的童鞋每次对MySQL库表做重大操作之前,例如:

  • 修改表结构;
  • 批量修改或者删除数据;

都会向DBA申请进行数据库的备份。

画外音:又或者说,不备份直接操作啦?

那DBA童鞋是怎么进行MySQL备份的呢?

调研了几十个RD和QA,基本是3种答案:

  • 不太清楚;
  • 在线逻辑备份,mysqldump;
  • 离线物理备份(冷备),拷贝从库库文件;

那实际上,DBA是如何对MySQL进行库备份的呢?

现在基本上使用的是PXB方案。

今天,和大家说说MySQL备份的来龙去脉,以及内核原理。

在线逻辑备份,mysqldump是咋回事?

mysqldump是MySQL工具集中的一个工具,可以用来导出或备份数据。

mysqldump的产出物是一个包含了建表,插入数据的SQL语句集合,类似于这样:

  1. -- MySQL dump 1.2.3 
  2. -- Host: localhost Database: test 
  3. -- Server version 4.5.6 
  4.  
  5. CREATE TABLE t_user ( 
  6.  id int(11)NOT NULL unique, 
  7.  name varchar(40) NOT NULL default '', 
  8.  PRIMARY KEY  (id) 
  9. ); 
  10.  
  11. INSERT INTO t_user VALUES (1,'shenjian'); 
  12. INSERT INTO t_user VALUES (2,'zhangsan'); 
  13. INSERT INTO t_user VALUES (3,'lisi'); 

因此,它才称为逻辑备份。

使用mysqldump进行备份的优点是:可以在线进行,不影响数据库对线上持续提供服务。

缺点也显而易见:相比物理备份拷贝库文件,备份和恢复都要慢非常多。

离线物理备份,拷贝从库库文件又是咋回事?

为了提高备份效率,缩短备份时间,这也就引发了第二种方案,直接物理备份库文件。

如上图所示,数据库集群设置为左侧的1主2从架构,离线物理备份是如何实施的呢?

  • 第一步,将一个从库从集群里摘下并下线,此时离线库文件不会再发生变化;
  • 第二步,scp拷贝库文件,即完成了库的物理备份;
  • 文件拷贝完成后,将从库挂回集群。

使用离线物理备份的优点是:备份和恢复都非常快。

缺点也显而易见:备份过程中从库无法对线上持续提供服务。

那么问题来了,有没有一种方案,又能够快速备份物理文件,又能够持续对线上提供服务呢?这就是如今MySQL备份最流行的PXB方案。

什么是PXB?

PXB的全称是,Percona XtraBackup,官网是这么吹的:PXB是全世界唯一一款开源免费的,支持MySQL热备的,非阻塞备份工具。

画外音:Percona XtraBackup is the world’s only open-source, free MySQL hotbackup software that performs non-blocking backups tool.

那么,PXB是如何实现:

  • 保持数据库持续提供线上服务,库文件不断变化时;
  • 通过MySQL文件;
  • 来进行库文件物理热备份的呢?

为了把问题讲透,这就要从redo log,从LSN,从MySQL的故障恢复(crash-recovery)机制聊起。

一、redo log

为什么要有redo log?

事务提交后,必须将事务对数据页的修改刷(fsync)到磁盘上,才能保证事务的ACID特性。

这个刷盘,是一个随机写,随机写性能较低,如果每次事务提交都刷盘,会极大影响数据库的性能。

随机写性能差,有什么优化方法呢?

架构设计中有两个常见的优化方法:

  • 先写日志(write log first),将随机写优化为顺序写;
  • 将每次写优化为批量写;

这两个优化,数据库都用上了。

第一个优化,将对数据的修改先顺序写到日志里,这个日志就是redo log。

第二个优化,就是redo log的三层架构:

 

  • log buffer:应用层缓冲;
  • OS cache:操作系统缓存;
  • redo log file:物理文件;画外音:此处不是本文的重点,不再展开详述。

假如某一时刻,数据库崩溃,还没来得及将数据页刷盘,数据库重启时,会重做redo log里的内容,以保证已提交事务对数据的影响被刷到磁盘上。

一句话,redo log是为了保证已提交事务的ACID特性,同时能够提高数据库性能的技术。

二、redo log的格式

逻辑上,MySQL以行(row)为单位管理数据;物理上,MySQL以页(page)为单位管理数据,MySQL的缓冲池(buffer)机制,也是以页为单位管理数据,事务提交之后,不用每次都随机写落盘刷新数据页,而是通过顺序写redo log来提高性能,那么redo log是直接保存等待刷盘的数据页吗?

如果redo log直接保存待刷盘的数据页,存在这样的问题,假如某个SQL语句只修改了一行记录里的一个属性,例如:

  1. update set sex=1 where name='shenjian' 

物理上,其实只修改了1个字节,难道redo log要将这个属性所在的一页数据(16K)全部保存下来吗?

完全不用,redo log只需要记录:

  • 某个数据页中(page num);
  • 某个某个偏移位置(offset);
  • 某个类型的数据(type);
  • 改成了什么值(value);

如此一来,redo log既能够实现以页为单位顺序刷盘数据,又极大缩小了日志大小,其性能又进一步的增加了。

  1. 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)的概念。

三、LSN

要聊redo log,要聊故障恢复,LSN是一个绕不开的概念。

什么是LSN?

LSN,Log Sequeue Number,直译过来叫日志序列号,是InnoDB中,随着日志的写入,一个只增不减的8字节序列号。

听上去叫日志序列号,但LSN并不只存在redo log中,它还存储在数据页里。

画外音:缓冲池中的数据页,磁盘上的数据页都存储了LSN。

数据页(page)里存储的LSN,可以用来标记数据页的“版本号”,记录该数据页最后一次被修改的日志序列的位置。

举个例子,假设逻辑上连续执行了两个事物,且都已经提交:

  1. trx1: 
  2. update set sex=0 where name='shenjian' 
  3.         redolog lsn=1000 
  4. trx2: 
  5. update set sex=1 where name='shenjian' 
  6.         redolog lsn=1001 

画外音:lsn增加了。

又假设,第一个事务trx1已经刷盘,而第二个事务trx2还没有刷盘,只写了redo log。画外音:最近一次刷盘的页,即最近一次检查点(checkpoint),也是通过LSN来记录的,它也会被写入redo log里。

这两个事务修改的是同一个数据页,很容易想到:磁盘数据页上的LSN=1000

而redo log里有两条记录:

  • 第一条,redo log lsn=1000
  • 第二条,redo log lsn=1001

为了提高数据库性能,数据库基本都是使用WAL(Write Ahead Log)的方式,先写日志再刷盘,所以很容易能够想到,磁盘数据页里的LSN,会小于最新redo log中的LSN。

画外音:此时,redo log中记录的checkpoint也是1000。

LSN有什么用呢?

它和MySQL的故障恢复(crash-recovery)机制紧密相关。

四、InnoDB故障恢复(crash-recovery)

这里的故障恢复,是指MySQL非正常退出,然后再次启动之前,要恢复数据一致性的操作。

画外音:可能直译叫崩溃恢复更准确一些。

InnoDB的崩溃恢复过程是怎么样的?

主要分为四个步骤:

第一步,redo log操作:保证已提交事务影响的最新数据刷到数据页里。

第二步,undo log操作:保证未提交事务影响的数据页回滚。

第三步,写缓冲(change buffer)合并。

画外音:不是今天的重点,关于写缓冲的概念,详见《写缓冲(change buffer),这次彻底懂了!》。

第四步,purge操作。

画外音: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的启动日志更形象的说明了这一点:

  • 先找到checkpoint;
  • 然后不断的扫描大于checkpoint的redo log,不断的恢复数据;

画外音:redo log的LSN可以看到恢复的进程。

多说一句,redo log还有两个特性:

  • 第一,幂等性,同一条redo log执行多次,不影响数据的恢复。
  • 第二,崩溃恢复时,从比checkpoint更早的LSN开始执行恢复,也不影响数据最终的一致性,因为一个数据页,最终一定会被更大值的LSN日志恢复到最新的数据上来。

五、PXB在线热备原理

不知不觉写了几千字,差点忘了缘起的问题。

PXB是如何实现:

  • 保持数据库持续提供线上服务,库文件不断变化时;
  • 通过MySQL文件;
  • 来进行库文件物理热备份的呢?

通过上面大把的铺垫,这个问题的回答就容易了。

首先,PXB启动一个线程,并不断监听并复制redo log的增量到另外的文件,不能直接备份redo log的原因是,redo log循环使用的,PXB则必须记录下checkpoint LSN之后的所有redo log。

然后,PXB启动另一个线程,然后开始复制数据文件,复制数据文件过程可能会比较长,整个过程中数据文件可能在不停的修改,导致数据不一致。但没有关系,所有的修改都已经记录在了第一步中,额外记录的redo log里。

画外音:务必注意,备份redo log的线程,必须在开始备份数据文件之前启动,之后结束。

最后,通过备份的数据文件,重放redo log,执行类似于MySQL崩溃恢复过程中的动作,就能够使得数据文件恢复到能保证一致性的checkpoint检查点。

画外音:PXB还可以对非MySQL,非InnoDB进行在线热备,这里就不展开了。

是不是很神奇啊!

【本文为51CTO专栏作者“58沈剑”原创稿件,转载请联系原作者】

戳这里,看该作者更多好文  

 

责任编辑:赵宁宁 来源: 51CTO专栏
相关推荐

2017-06-16 10:39:51

双机热备软件

2010-05-12 17:15:57

2020-09-10 16:50:32

mysqldump数据库热备

2010-05-14 16:49:43

MySQL 数据库

2009-01-09 22:37:43

服务器系统故障

2018-01-22 10:05:14

灾备

2010-04-14 16:37:12

Cisco路由器

2021-08-28 10:58:15

MySQL备份数据库

2009-11-17 10:16:45

2013-03-27 11:17:09

宝德虚拟化双机热备

2011-12-16 10:25:52

2024-01-25 10:20:40

防火墙网络 安全双机热备

2023-10-17 14:29:35

2011-11-28 13:03:29

网络热备网络设备热备设备热备

2021-04-19 10:45:52

Webpack热更新前端

2023-05-08 08:05:42

内核模块Linux

2022-03-09 12:26:04

MySQL高可用性主备延迟

2011-10-17 16:11:00

MySQL

2010-08-17 14:55:33

DB2离线

2009-02-27 17:13:00

宝德服务器双机热备校园一卡通
点赞
收藏

51CTO技术栈公众号