小型网站MYSQL问题二:Percona Xtrabackup实现数据库备份和恢复

故事背景:前面大胆的选择了innodb,接下来就要考虑数据库的备份和恢复。俗话说“常在河边走,哪能不湿鞋“,自从接触数据这块,使我一直对它保持敬畏之心。在这里使用了percona公司的xtrabckup工具来实现数据库备份和恢复。操作步骤记录如下:

1、安装软件仓库(不要问我为什么不用源码安装,好吧,其实我懒。)

wget https://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm
rpm -ivh percona-release-0.1-3.noarch.rpm
rpm -ql percona-release
    /etc/pki/rpm-gpg/RPM-GPG-KEY-Percona
    /etc/yum.repos.d/percona-release.repo
    /usr/share/doc/percona-release-0.1
    /usr/share/doc/percona-release-0.1/RPM-GPG-KEY-Percona
yum -y install percona-xtrabackup

2、备份策略及准备测试数据

采用先全备份加增量备份的方案。在利用xtrabackup对innodb表做备份工作时,建议mysql启用“innodb_file_per_table=1”变量且同时启用innodb_file_per_table = 1 innodb_expand_import = 1

这样使每表都有一个自己的表空间,不然很难进行单表备份和还原。还有二进制日志文件就不要与数据文件放在同一个目录了,你不想当数据丢失时,二进制日志也一同丢了。

测试数据:

mysql> SELECT VERSION(); 
    +------------+ 
    | VERSION()  | 
    +------------+ 
    | 5.5.36-log | 
    +------------+ 
    1 row in set (0.00 sec) 
mysql> SHOW DATABASES; #创建了一个mydb1数据库 
    +--------------------+ 
    | Database          | 
    +--------------------+ 
    | information_schema | 
    | mydb1              | 
    | mysql              | 
    | performance_schema | 
    | test              | 
    +--------------------+ 
mysql> SELECT * FROM mydb1.tb1; #表中只有一条数据 
    +----+------+------+ 
    | id | name | age  | 
    +----+------+------+ 
    |  1 | tom  |  10 | 
    +----+------+------+

创建备份数据存放目录:

mkdir -pv /backup/{fullbackup,incremental} 
    #fullbackup  存放全备份数据 
    #incremental 存放增量备份数据

创建复制用户:

mysql> GRANT RELOAD,LOCK TABLES,REPLICATION CLIENT ON *.* TO 'bkuser'@'localhost' IDENTIFIED BY '123456'; 
mysql> FLUSH PRIVILEGES;

3、全备份数据

innobackupex --user=bkuser --password=123456 /backup/fullbackup/ 
    #最后出现“150415 16:30:23  innobackupex: completed OK!”这样的信息表示备份完成 
ls /backup/fullbackup/2015-04-15_16-30-19/ 
    backup-my.cnf  mysql              xtrabackup_binary      xtrabackup_logfile 
    ibdata1        performance_schema  xtrabackup_binlog_info 
    mydb1          test                xtrabackup_checkpoints 
cat /backup/fullbackup/2015-04-15_16-30-19/xtrabackup_checkpoints 
    backup_type = full-backuped 
    from_lsn = 0 
    to_lsn = 1644877 
    last_lsn = 1644877 
    compact = 0

4、增量备份数据

先做一些数据修改:

mysql> INSERT INTO mydb1.tb1 (name,age) VALUES ('jack',20); 
mysql> SELECT * FROM tb1;  #增加一条数据 
    +----+------+------+ 
    | id | name | age  | 
    +----+------+------+ 
    |  1 | tom  |  10 | 
    |  2 | jack |  20 | 
    +----+------+------+

做第一次增量备份:

innobackupex --user=bkuser --password=123456 --incremental /backup/incremental/ --incremental-basedir=/backup/fullbackup/2015-04-15_16-30-19/ 
ls /backup/incremental/2015-04-15_16-42-00/ 
    backup-my.cnf  mydb1              test                    xtrabackup_checkpoints 
    ibdata1.delta  mysql              xtrabackup_binary      xtrabackup_logfile 
    ibdata1.meta  performance_schema  xtrabackup_binlog_info 
cat /backup/incremental/2015-04-15_16-42-00/xtrabackup_checkpoints 
    backup_type = incremental 
    from_lsn = 1644877  #这是全备时的"to_lsn"值 
    to_lsn = 1645178 
    last_lsn = 1645178 
    compact = 0

再做数据修改:

mysql> INSERT INTO mydb1.tb1 (name,age) VALUES ('jason',30); 
mysql> SELECT * FROM tb1; 
    +----+-------+------+ 
    | id | name  | age  | 
    +----+-------+------+ 
    |  1 | tom  |  10 | 
    |  2 | jack  |  20 | 
    |  3 | jason |  30 | 
    +----+-------+------+

做第二次增量备份:

innobackupex --user=bkuser --password=123456 --incremental /backup/incremental/ --incremental-basedir=/backup/incremental/2015-04-15_16-42-00/ 
    #这里的"--incremental-basedir"是指向第一次增量备份的目录 
ls /backup/incremental/2015-04-15_16-49-07/ 
    backup-my.cnf  mydb1              test                    xtrabackup_checkpoints 
    ibdata1.delta  mysql              xtrabackup_binary      xtrabackup_logfile 
    ibdata1.meta  performance_schema  xtrabackup_binlog_info 
cat /backup/incremental/2015-04-15_16-49-07/xtrabackup_checkpoints 
    backup_type = incremental 
    from_lsn = 1645178 #这是第一次增量的"to_lsn"值 
    to_lsn = 1645463 
    last_lsn = 1645463 
    compact = 0

再来做一次数据修改,以便演示根据二进制日志做时间点的恢复:

mysql> INSERT INTO mydb1.tb1 (name,age) VALUES ('lucky',40); 
mysql> SELECT * FROM tb1; 
    +----+-------+------+ 
    | id | name  | age  | 
    +----+-------+------+ 
    |  1 | tom  |  10 | 
    |  2 | jack  |  20 | 
    |  3 | jason |  30 | 
    |  4 | lucky |  40 | 
    +----+-------+------+

5、恢复

5.1、数据破坏

service mysqld stop 
rm -rf /mnt/mydata/data/*  #把数据目录数据全部删除

对于xtrabackup做数据恢复的理解:

xtrabackup做数据恢复与mysqldump这样的逻辑备份工作的恢复有很大的区别,xtrabackup进行数据恢复时需要把各个增量的数据备份与全备份的数据进行合并,

对每次增量备份的合并只能将已提交的事务进行重放(redo),对合备份的数据恢复也只能做redo操作,把各个增量都合并完成后再把没有提交的事务进行回滚(undo)操作,

合并完增量备份后,全备份的“xtrabackup_checkpoints”文件中的“last_lsn”应该是最后一次增量备份时的值,这些合并做redo的过程就是恢复数据前的准备工作(prepare)。

而真正在做数据恢复,建议先把全备和增量备份的文件都copy一份为副本,避免操作失误导致备份文件的损坏。

5.2、数据恢复的准备(prepare)工作

#准备全备份的数据 
innobackupex --apply-log --redo-only /backup/fullbackup/2015-04-15_16-30-19/ 
#准备第一次增量数据 
innobackupex --apply-log --redo-only /backup/fullbackup/2015-04-15_16-30-19/ --incremental-dir=/backup/incremental/2015-04-15_16-42-00/ 
#准备第二次增量数据 
innobackupex --apply-log --redo-only /backup/fullbackup/2015-04-15_16-30-19/ --incremental-dir=/backup/incremental/2015-04-15_16-49-07/
cat /backup/fullbackup/2015-04-15_16-30-19/xtrabackup_checkpoints 
    backup_type = full-prepared 
    from_lsn = 0 
    to_lsn = 1645463 #这是最后一次增量备份的位置,到此数据已全部合并 
    last_lsn = 1645463 
    compact = 0

5.3、真正数据恢复

innobackupex --copy-back /backup/fullbackup/2015-04-15_16-30-19/  #仅一个“--copy-back”选项 
ls /mnt/mydata/data/ 
    ibdata1  mydb1  mysql  performance_schema  test
chown -R mysql.mysql /mnt/mydata/data/  #修改恢复数据的属主与属组 
service mysqld start 
    Starting MySQL.. SUCCESS! 
mysql> SELECT * FROM mydb1.tb1;  #检查数据 
    +----+-------+------+ 
    | id | name  | age  | 
    +----+-------+------+ 
    |  1 | tom  |  10 | 
    |  2 | jack  |  20 | 
    |  3 | jason |  30 | 
    +----+-------+------+ 
#lucky信息还没有恢复

5.4、利用二进制日志文件基于时间点恢复

查看最后一次增量备份时的二进制日志文件及position信息:
cat /backup/incremental/2015-04-15_16-49-07/xtrabackup_binlog_info 
    mysql-bin.000031    1665  
mysqlbinlog --start-position=1665 /var/log/mysql_log/mysql-bin.000031 > /tmp/position.sql 
    #用mysqlbinlog工具导出最后一次增量备份后的sql操作
导入数据:
mysql> source /tmp/position.sql 
mysql> SELECT * FROM mydb1.tb1; 
    +----+-------+------+ 
    | id | name  | age  | 
    +----+-------+------+ 
    |  1 | tom  |  10 | 
    |  2 | jack  |  20 | 
    |  3 | jason |  30 | 
    |  4 | lucky |  40 | 
    +----+-------+------+ 
#数据全部恢复

6、总结

利用innobackupex工具可对在有混合存储引擎的场景下对数据库进行全备份,当是备份innodb表时innobackupex脚本内部会自动调用xtrabackup工具来进行备份操作,

在数据还原时应停止mysql实例,清空数据目录,然后先做prepare准备工作,第二步才是真正的数据还原(–copy-back),数据还原到数据目录后不要忘记修改数据目录的权限。

当然innobackupex工具也能实现对单库单表的导出、导出,如果是对Innodb表,那建议直接用xtrabackup工具,这样更直观的使用各个选项进行备份。

============================华丽分隔线(下面是重点)================================================

背景:在到第5.3步的时候,数据库启动失败。why、what、fuck。说好的一条龙服务?

痛定思痛,上日志。

151216 11:16:20
mysqld_safe Starting mysqld daemon with databases from /data/mysql
151216 11:16:20 [Note] /usr/libexec/mysqld (mysqld 5.5.47-log) starting as process 2931 ...
151216 11:16:20 [Note] Plugin 'FEDERATED' is disabled.
151216 11:16:20 InnoDB: The InnoDB memory heap is disabled
151216 11:16:20 InnoDB: Mutexes and rw_locks use GCC atomic builtins
151216 11:16:20 InnoDB: Compressed tables use zlib 1.2.3
151216 11:16:20 InnoDB: Using Linux native AIO
151216 11:16:20 InnoDB: Initializing buffer pool, size = 128.0M
151216 11:16:20 InnoDB: Completed initialization of buffer pool
InnoDB: Error: log file ./ib_logfile0 is of different size 0 50331648 bytes        #这里是48M
InnoDB: than specified in the .cnf file 0 5242880 bytes!           #这里是5M
151216 11:16:20 [ERROR] Plugin 'InnoDB' init function returned error.
151216 11:16:20 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.   #注册引擎失败,打击好大
151216 11:16:20 [ERROR] Unknown/unsupported storage engine: innodb     #什么,又不支持innodb
151216 11:16:20 [ERROR] Aborting
 
151216 11:16:20 [Note] /usr/libexec/mysqld: Shutdown complete
 
151216 11:16:20 mysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended

首先我删除了恢复到/data/mysql目录下面的ibdata1和ib_logfile0、ib_logfile1,此时可以启动数据库,然而提示表不存在。

向各位老师请教后,修改innodb_log_file_size=48M并写入/etc/my.cnf,启动正常。

总结:innodb_log_file_size参数属于mysql系统参数,当配置不当时,mysql会启动失败。使用xtrabackup备份时默认值是5M,但是当迁移到新的环境后,初始化为48M,导致不匹配。后续应该将此参数写入/etc/my.cnf防止迁移带来的参数不匹配问题。

Command-Line Format --innodb_log_file_size=#
System Variable Name innodb_log_file_size
Variable Scope Global
Dynamic Variable No
Permitted Values Type integer
Default 5242880
Min Value 1048576
Max Value 4GB / innodb_log_files_in_group

The size in bytes of each log file in a log group. The combined size of log files (innodb_log_file_size * innodb_log_files_in_group) cannot exceed a maximum value that is slightly less than 4GB. A pair of 2047 MB log files, for example, would allow you to approach the range limit but not exceed it. The default value is 5MB. Sensible values range from 1MB to 1/N-th of the size of the buffer pool, where N is the number of log files in the group. The larger the value, the less checkpoint flush activity is needed in the buffer pool, saving disk I/O. Larger log files also make crash recovery slower, although improvements to recovery performance in MySQL 5.5 and higher make the log file size less of a consideration. For general I/O tuning advice, 

具体参考:http://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_log_file_size

原创文章,作者:陈近南,如若转载,请注明出处:http://www.178linux.com/10139

(1)
上一篇 2015-12-19 20:09
下一篇 2015-12-19 20:30

相关推荐

  • 运维监控大数据的提取与分析

    本文内容整理来自【敏捷运维大讲堂】蒋君伟老师的线上直播分享。分别从以下3个维度来分享:1、云时代监控分析的窘境;2、使用标签标记监控数据的维度;3、监控数据应用场景。 云时代监控分析的窘境 在虚拟化与容器技术广泛应用的情况下,运维对象大规模地增长,监控平台每天存储的指标都以亿计,所以监控数据如今已经成了大数据。传统的监控工具在这种场景下,对于数据的提取分析,…

    系统运维 2017-01-09
  • vncserver安装配置小结

      安装VNC Server 端:        1. yum install  tigervnc-server         //RHEL6: vnc server的包名          yum &nbs…

    Linux干货 2016-03-09
  • Linus:利用二级指针删除单向链表

    感谢网友full_of_bull投递此文(注:此文最初发表在这个这里,我对原文后半段修改了许多,并加入了插图) Linus大婶在slashdot上回答一些编程爱好者的提问,其中一个人问他什么样的代码是他所喜好的,大婶表述了自己一些观点之后,举了一个指针的例子,解释了什么才是core low-level coding。 下面是Linus的教学原文及翻译—— “…

    Linux干货 2016-07-10
  • 链接分析算法之:主题敏感PageRank

      前面的讨论提到。PageRank忽略了主题相关性,导致结果的相关性和主题性降低,对于不同的用户,甚至有很大的差别。例如,当搜索“苹果”时,一个数码爱好者可能是想要看 iphone 的信息,一个果农可能是想看苹果的价格走势和种植技巧,而一个小朋友可能在找苹果的简笔画。理想情况下,应该为每个用户维护一套专用向量,但面对海量用户这种方法显然不可行。所…

    Linux干货 2016-02-17
  • Ansible_variable

    Ansible变量        系统自动化让重复的工作变得更加容易,但是每个系统还是有一些细微的差别,变量就是如何处理系统之间的不同之处。这里将会列出变量的极大部分使用方法。   本文假设:你已经知道如何使用Ansible。知道inventory,facts等概念。   Ans…

    Linux干货 2015-11-26
  • 设计模式(一)工厂模式Factory(创建型)

      在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的。但是在一些情况下, new操作符直接生成对象会带来一些问题。举例来说, 许多类型对象的创造需要一系列的步骤: 你可能需要计算或取得对象的初始设置; 选择生成哪个子对象实例; 或在生成你需要的对象之前必须先生成一些辅助功能的对象。 在…

    Linux干货 2015-06-23

评论列表(3条)

  • stanley
    stanley 2015-12-19 20:22

    非常不错,久违的好博客,已置顶

  • 以马内利
    以马内利 2015-12-21 08:54

    我也发现innodb_log_file_size的问题了,哈哈。 这个坑貌似配过的都得踩一脚

  • bigwinner
    bigwinner 2016-04-14 11:05

    楼主写的十分详细,线上如果出问题,不会有时间一步一步的这么去恢复的,都是通过脚本实现的;