大家都知道,数据库返回数据时都是按照最初设计的具有一定逻辑关联格式的形式逐条展现的,具有一定的商业逻辑属性。而在物理存储层面上的数据库软件却是按照数据库软件所设计的某种特定格式经过一定处理后存放的。
数据库逻辑备份就是备份软件按照最初设计的逻辑关系,以数据库的逻辑结构对象为单位,将数据库中的数据按照预定义的逻辑关联格式一条一条生成相关的文本文件,以达到备份的目的。
逻辑备份可以说是最简单,也是目前中小型系统最常使用的备份方式。在MySQL中常用的逻辑备份主要就是两种,一种是将数据生成为可以完全重现当前数据库中数据的INSERT语句,另外一种就是将数据通过逻辑备份软件,将数据库表的数据以特定分隔符进行分隔后记录在文本文件中。
生成INSERT语句备份
两种逻辑备份方式各有优劣,所针对的使用场景也会稍有差别,先来看生成INSERT语句的逻辑备份。
在MySQL数据库中,一般通过MySQL数据库软件自带工具程序中的mysqldump来生成INSERT语句的逻辑备份文件。其使用方法基本如下:
由于mysqldump的使用方法比较简单,大部分需要的信息都可以通过运行“mysqldump --help”获得。这里只想结合MySQL数据库的一些概念原理和大家探讨一下当使用mysqldump做数据库逻辑备份时有哪些技巧及注意事项。
我们都知道,对于大多数使用数据库的软件或者网站来说,都希望自己的数据库能够提供尽可能高的可用性,而不是时不时地就须要停机。因为一旦数据库无法提供服务,系统就无法再通过存取数据来提供一些动态功能。所以对于大多数系统来说,如果要让每次备份都停机可能是不可接受的,可是mysqldump程序的实现原理是通过我们给的参数信息加上数据库中的系统表信息来逐个表获取数据,然后生成INSERT语句再写入备份文件中的。这样就出现了一个问题,系统正常运行过程中,很可能会不断有数据变更的请求正在执行,这样就可能造成在mysqldump备份出来的数据不一致。也就是说备份数据很可能不是同一个时间点的数据,而且甚至可能都没办法满足完整性约束。这样的备份集对于有些系统来说也许并没有太大问题,但是对于那些对数据的一致性和完整性要求比较严格的系统来说问题就大了,它就是一个完全无效的备份集。
对于如此场景,该如何做?我们知道,想让数据库中的数据一致,只有在两种情况下可以做到。
对于第一种情况,大家肯定会想,这可能吗?只要有两个以上的表,不管怎样写程序,都不可能获得完全一致的取数时间点啊。是的,我们确实无法通过常规方法让取数的时间点完全一致,但是大家不要忘记,在同一个事务中,数据库是可以做到所读取的数据处于同一个时间点的。所以,对于事务支持的存储引擎,如InnoDB或BDB等,就可以通过将整个备份过程控制在同一个事务中,来达到备份数据的一致性和完整性,而且mysqldump程序也提供了相关的参数选项来支持该功能,就是通过“--single-transaction”选项,可以不影响数据库的任何正常服务。
对于第二种情况我想大家首先想到的肯定是将须要备份的表锁定,只允许读取而不允许写入。是的,确实只能这么做。我们只能通过一个折中的处理方式,让数据库在备份过程中仅提供数据的查询服务,锁定写入的服务,以使数据暂时处于一致的不会被修改的状态,等mysqldump完成备份后再取消写入锁定,重新开始提供完整的服务。mysqldump程序也提供了相关选项,如“--lock-tables”和“--lock-all-tables”,它们在执行之前会锁定表,执行结束后自动释放锁定。这里有一点须要注意的就是,“--lock-tables”并不是一次性将须要导出(dump)的所有表锁定,而是每次仅锁定一个数据库的表,如果你须要导出(dump)的表分别在多个不同的数据库中,一定要使用“--lock-all-tables”才能确保数据的一致完整性。
当通过mysqldump生成INSERT语句的逻辑备份文件的时候,有一个非常有用的选项供我们使用,那就是“--master-data[=value]”。当添加了“--master-data=1”时,mysqldump会将当前MySQL使用的binlog日志的名称和位置记录到dump文件中,并且是以CHANGE_MASTER语句的形式记录,如果仅仅是使用“--master-data”或“--master-data=2”,CHANGE_MASTER语句会以注释的形式存在。这个选项在实施slave的在线搭建时非常有用,即使不是进行在线搭建slave,也可以在某些恢复的过程中通过备份的binlog做进一步恢复操作。
在某些场景下,可能只须要将某些特殊的数据导出到其他数据库中,但不希望通过新建临时表的方式来实现,那么可以在通过mysqldump程序的“—where='where-condition'”来实现,但只能在仅导出(dump)一个表的情况下使用。
其实除了以上一些使用诀窍之外,mysqldump还提供了其他很多有用的选项供大家在不同的场景下使用,如通过“--no-data”仅仅dump数据库结构创建脚本,通过“--no-create-info”去掉dump文件中创建表结构的命令等,
生成特定格式的纯文本备份数据文件
除了通过生成INSERT命令来做逻辑备份之外,还有另外一种方式备份数据,即将数据库中的数据以特定分隔字符的形式分隔记录在文本文件中,以达到逻辑备份的效果。这样的备份数据与INSERT命令文件相比,须要使用的存储空间更小,数据格式更加清晰明确,编辑方便。但是缺点是在同一个备份文件中不能存在多个表的备份数据,没有数据库结构的重建命令。若备份集需要多个文件,产生的影响无非就是文件多了维护和恢复成本会增加,但这些基本上都可以通过编写一些简单的脚本来实现。
那我们一般可以使用什么方法来生成这样的备份集文件呢,其实MySQL也已经实现了相应的功能。
在MySQL中提供了一种SELECT语法,专供用户通过Query语句将某些特定数据以指定格式输出到文本文件中,同时也提供了实用工具和相关的命令,可以方便地将导出文件原样再导入到数据库中。这不正是我们做备份所需要的么?
该命令有几个要注意的参数,如下:
可能我们都知道mysqldump可以将数据库中的数据以INSERT语句的形式生成相关备份文件,其实除了生成INSERT语句之外,mysqldump还同样能实现“SELECT ... TO OUTFILE FROM ...”所实现的功能,而且还会生成一个与相关数据库结构对应的创建脚本。如示例代码2所示:
这样的输出结构对我们作为备份来说是非常合适的,当然如果一次有多个表须要被导出(dump),就会针对每个表生成两个相对应的文件。
仅仅有了备份还不够,得知道如何去使用这些备份,现在就看看上面所做的逻辑备份的恢复方法:
由于所有的备份数据都是以最初数据库结构的设计相关形式存储的,所以逻辑备份的恢复也相对比较简单。当然,针对两种不同的逻辑备份形式,恢复方法也稍有区别。下面就分别针对这两种逻辑备份文件的恢复方法做一个简单的介绍。
INSERT语句文件的恢复
对于INSERT语句形式的备份文件的恢复是最简单的,仅仅须要运行该备份文件中的所有(或者部分)Query命令。如果须要做完全恢复,那么可以通过使用“mysql < backup.sql”直接调用备份文件执行其中的所有命令,将数据完全恢复到备份时候的状态。如果已经使用mysql连接上了MySQL,那么也可以通过在mysql中执行“source pathbackup.sql”或“. pathbackup.sql”来进行恢复。
纯数据文本备份的恢复
如果是上面第二种形式的逻辑备份,恢复起来会稍微麻烦一点,需要一个表一个表通过相关命令来进行恢复,当然如果通过脚本来实现自动多表恢复也是比较方便的。恢复方法也有两个,一是通过MySQL的“LOAD DATA INFILE”命令来实现,另一种方法就是通过MySQL提供的使用工具mysqlimport来进行恢复。
逻辑备份能做什么?不能做什么?
在清楚了如何使用逻辑备份进行相应的恢复之后,须要知道可以利用这些逻辑备份做些什么。
在知道了逻辑备份能做什么之后,还必须清楚它不能做什么,这样才能清楚备份能否满足自己的预期,是否确实是自己想要的。
在了解MySQL的物理备份之前,我们须要先了解,什么是数据库物理备份。既然是物理备份,那么肯定和数据库的物理对象相对应。就如同逻辑备份是根据数据库逻辑对象所做的备份一样,数据库的物理备份就是对数据库的物理对象所做的备份。
数据库的物理对象主要由数据库的物理数据文件、日志文件及配置文件等组成。在MySQL数据库中,除了MySQL系统共有的一些日志文件和系统表的数据文件之外,每一种存储引擎还会有不太一样的物理对象,下面将详细列出几种常用的存储引擎各自所对应的物理对象(物理文件),以便大家清楚地知道各种存储引擎在做物理备份时到底有哪些文件需要备份,哪些不需要。
MyISAM存储引擎
MyISAM存储引擎的所有数据都存放在MySQL配置设定的“datadir”目录下。实际上不管使用的是MyISAM存储引擎还是其他任何存储引擎,每一个数据库都会在“datadir”目录下有一个文件夹(包括系统信息的数据库mysql也是一样)。在各个数据库中每一个MyISAM存储引擎表都会有三个文件存在,分别为记录表结构元数据的“.frm”文件、存储表数据的“.MYD”文件,以及存储索引数据的“.MYI”文件。由于MyISAM属于非事务性存储引擎,所以它没有自己的日志文件。所以MyISAM存储引擎在做物理备份时,除了备份MySQL系统共有的物理文件之外,就只须备份上面的三种文件。
InnoDB存储引擎
InnoDB存储引擎属于事务性存储引擎,而且存放数据的位置也可能与MyISAM存储引擎有所不同,这主要取决于我们对InnoDB的相关配置。决定InnoDB存放数据位置的配置为“innodb_data_home_dir”、“innodb_data_file_path”和“innodb_log_group_home_dir”这三个目录位置指定的参数,以及另外一个决定InnoDB的表空间存储方式的参数“innodb_file_per_table”。前面三个参数指定了数据和日志文件的存放位置,最后一个参数决定InnoDB是以共享表空间存放数据还是以独享表空间方式存储数据。
如果我们使用了共享表空间的存储方式,那么InnoDB须要备份“innodb_data_home_dir”和“innodb_data_file_path”参数所设定的所有数据文件,以及“datadir”中相应数据库目录下的所有InnoDB存储引擎表的“.frm”文件。
如果我们使用了独享表空间,那么除了备份上面共享表空间方式须要备份的所有文件之外,还须要备份“datadir”中相应数据库目录下的所有“.idb”文件,该文件中存放的才是独享表空间方式下InnoDB存储引擎表的数据。这里可能有人会问,既然是使用独享表空间,那为什么还要备份共享表空间“才使用到”的数据文件呢?其实这是很多人的一个共性误区,大家以为使用独享表空间的时候InnoDB的所有信息就都存放在“datadir”所设定数据库目录下的“.ibd”文件中,实际上并不是这样的。“.ibd”文件中所存放的仅仅只是表数据、索引数据以及UNDO信息,大家都很清楚,InnoDB是事务性存储引擎,它是需要REDO信息的而不管InnoDB使用的是共享还是独享表空间的方式来存储数据,各个表的元数据信息都是存放在“innodb_data_home_dir”和“innodb_data_file_path”这两个参数所设定的数据文件中的。所以要想InnoDB的物理备份有效,“innodb_data_home_dir”和“innodb_data_file_path”参数所设定的数据文件不管在什么情况下都必须备份。
此外,除了上面所说的数据文件之外,InnoDB还存放REDO信息和相关事务信息的日志文件在“innodb_log_group_home_dir”参数所设定的位置。所以要想InnoDB物理备份能够有效使用,还要备份“innodb_log_group_home_dir”参数设定位置的所有日志文件。
NDB Cluster存储引擎
NDB Cluster存储引擎(其实也可以说是MySQL Cluster)的物理备份文件主要有以下三类:
不论是通过停机冷备份,还是通过NDB Cluster自行提供的在线联机备份工具,或者是第三方备份软件来进行备份,都须要备份以上三种物理文件才能构成一个完整有效的备份集。当然,相关的配置文件,尤其是管理节点上面的配置信息,同样也须要备份。
由于不同存储引擎须要备份的物理对象(文件)并不一样,且每个存储引擎对数据文件的一致性要求也不一样,所以各个存储引擎在进行物理备份的时候使用的备份方法也有区别。当然,如果要做冷备份(停掉数据库之后的备份),要做的事情很简单,那就是直接复制所有数据文件和日志文件到备份集存放的位置即可,不管是何种存储引擎都可以这样做。由于冷备份方法简单,实现容易,所以这里就不详细说明了。
在实际的应用环境中,很少能够停机做日常备份的,我们只能在数据库提供服务的情况下来完成数据库备份,这也就是俗称的热物理备份,下面就针对各个存储引擎单独说明各自最常用的在线(热)物理备份方法。
MyISAM存储引擎
上面介绍了MyISAM存储引擎文件的物理文件比较集中,而且不支持事务没有REDO和UNDO日志,对数据一致性的要求也并不是特别高,所以MyISAM存储引擎表的物理备份也比较简单,只要将MyISAM的物理文件复制出来即可。虽然MyISAM存储引擎没有事务支持,对数据文件的一致性要求也没有InnoDB之类的存储引擎那么严格,但是MyISAM存储引擎的同一个表的数据文件和索引文件之间是有一致性要求的。当MyISAM存储引擎发现某个表的数据文件和索引文件不一致的时候,会标记该表处于不可用状态,并要求进行修复动作,当然,一般情况下的修复都会比较容易。不过,即使数据库存储引擎本身对数据文件的一致性要求并不是很苛刻,我们的应用也允许数据不一致吗?我想答案肯定是否定的,所以我们自己必须保证数据库在备份时候的数据至少是处于某一个时间点的,这样就必须做到在备份MyISAM数据库的物理文件的时候让MyISAM存储引擎停止写操作,仅仅提供读服务,其实质就是给数据库表加锁来阻止写操作。
MySQL提供了一个实用程序mysqlhotcopy,这个程序就是专门用来备份MyISAM存储引擎的。不过如果你有除了MyISAM之外的其他非事务性存储引擎,也可以通过合适的参数设置,或者微调该备份脚本,以通过mysqlhotcopy程序来完成相应的备份任务。
mysqlhotcopy除了可以备份整个数据库、指定的某个表,还可以通过正则表达式来匹配某些表名,以针对性地备份某些表。备份结果就是指定数据库的文件夹下包括所有指定表的相应物理文件。
mysqlhotcopy是一个用perl编写的使用程序,其主要实现原理实际上就是先锁住(LOCK)表,然后执行FLUSH TABLES动作,该正常关闭的表正常关闭,该进行flush同步的数据都进行同步,然后通过执行OS级别的复制(cp等)命令,将须要备份的表或数据库的所有物理文件都复制到指定的备份集位置。
此外,也可以通过登录数据库中手工加锁,然后通过操作系统的命令来复制相关文件执行热物理备份,且在完成文件复制(copy)之前,不能退出加锁的session(因为退出会自动解锁),示例如代码5所示:
不退出mysql,在新的终端下做如示例代码6所示的备份。
然后将之前锁定的session解锁,如示例代码7所示。
这样就完成了一次物理备份,而且大家也从文件列表中看到了,备份中还有CSV存储引擎的表。
InnoDB存储引擎
InnoDB存储引擎由于是事务性存储引擎,有REDO日志和相关的UNDO信息,而且对数据的一致性和完整性的要求也比MyISAM严格很多,所以InnoDB的在线(热)物理备份要比MyISAM复杂很多,一般很难简单地通过几个手工命令来完成,大都是通过专门的InnoDB在线物理备份软件来完成。
InnoDB存储引擎的开发者(Innobase公司)开发了一款名为ibbackup的商业备份软件,专门实现InnoDB存储引擎数据的在线物理备份功能。该软件可以在MySQL在线运行的状态下,对数据库中使用InnoDB存储引擎的表进行备份,不过仅限于使用InnoDB存储引擎的表。
NDB Cluster存储引擎
NDB Cluster存储引擎也是一款事务性存储引擎,和InnoDB一样也有REDO日志。NDB Cluter存储引擎提供了备份功能,可以通过相关的命令实现。当然,停机冷备份的方法也是有效的。
在线联机备份步骤如下:
由于NDB Cluster的备份指令是从管理节点发起的,且并不会等待备份完成就返回,所以也没办法直接通过快捷键“Ctrl+C”或其他方式来中断备份进程,所以NDB Cluster提供了相应的命令来中断当前正在进行的备份操作,步骤如下。
通过NDB Cluster存储引擎自己的备份命令进行备份之后,会将前面所提到的三种文件存放在参与备份的节点上面,且存放在三个不同的文件中,类似如下:
上面的备份文件命名规则中,backup_id是指备份号,不同的备份集会有不同的备份号,node_id则是指明该备份文件属于哪个数据节点,而在数据文件的备份文件中的n则指明片段号。
和之前逻辑备份一样,光有备份是没有意义的,还须要能够将备份有效地恢复才行。物理备份和逻辑备份相比最大的优势就是恢复速度快,因为主要是物理文件的复制,将备份文件复制到须要恢复的位置,然后进行简单的操作即可。
MyISAM存储引擎
MyISAM存储引擎由于其特性,物理备份的恢复也比较简单。
如果是通过停机冷备份或是在运行状态通过锁定写入操作后的备份集来恢复,仅仅须要通过操作系统的复制命令将备份集中相应的数据文件复制到对应位置,覆盖现有文件即可。
如果是通过mysqlhotcopy软件进行的在线热备份,而且相关的备份信息也记录了数据库中相应的表,其恢复操作可能会须要结合备份表信息来进行恢复。
InnoDB存储引擎
对于冷备份,InnoDB存储引擎进行恢复所需要的操作和其他存储引擎没有什么差别,同样是把备份集文件(包括数据文件和日志文件)复制到相应的目录即可。但是对于通过其他备份软件所进行的备份,就要根据备份软件本身的要求来进行了。比如通过ibbackup来进行的备份,同样也要通过它进行恢复才可以,具体的恢复方法请通过该软件的使用手册来进行,这里就不详细介绍了。
NDB Cluster存储引擎
对于停机冷备,恢复方法和其他存储引擎也没有太多区别,只不过有一点要特别注意的,就是在恢复的时候必须要将备份集中的文件恢复到对应的数据节点上,否则无法正确完成恢复过程。
而通过NDB Cluster所提供的备份命令生成的备份集,须要使用专用的备份恢复软件ndb_restore来进行。ndb_restore软件将从备份集中读取出备份相关的控制信息,而且它必须在单独的数据节点上面分别运行,这样才能完成所有数据节点的恢复。所以当初备份进行过程中有多少数据节点,现在就须要运行多少次ndb_restore。而且,首次通过ndb_restore来进行恢复的话,还必须恢复元数据,也就是重建所有的数据库和表。
备份是否完整,能否满足要求,关键还是要看所设计的备份策略是否合理,以及备份操作是否确实按照所设计的备份策略进行了。
针对不同的用途,所需要的备份类型是不一样的,备份策略也各有不同。如为了应对本章最开始所描述的在线应用的数据丢失问题,备份就须要快速恢复,而且最好是只须要增量恢复就能找回所需数据。对于这类需求,最好是有在线的,且部分延迟恢复的备用数据库。因为这样可以在最短时间内找回所需要的数据。甚至在某些硬件设备出现故障的时候,将备用库直接开放,对外提供服务都可以。当然,在资源缺乏的情况下,可能难以找到足够的备用硬件设备来承担这个备份责任,“也可以通过物理备份来解决,毕竟物理备份的恢复速度要比逻辑备份快很多。
而对于那些非数据丢失的应用场景,大多数时候恢复时间的要求并不是太高,只要能恢复出一个完整可用的数据库就可以了。所以不论是物理备份还是逻辑备份,影响都不是特别大。
从我的个人经验来看,可以根据不同的需求、不同的级别通过如下的几个思路来设计合理的备份策略: