MySQL 数据备份与同步

前段时间使用MySQL做为数据存储作了一个小项目。项目上线运行了几十天以后,数据已经愈来愈多,达到了100多M。用mysqldump天天备份全量数据而后传输到另一台机器上这种方式进行数据备份,长此以往愈来愈慢。因而开始研究如何利用mysql的主从同步功能实现自动备份。若是实现自动备份,主从服务器之间只须要在有数据更新时同步一点增量数据,不会在备份时占用大量的CPU和内网的网络带宽资源了。介绍主从同步以前,仍是先从基础的mysqldump备份开始讲起。html

mysqldump

mysqldump是mysql数据库提供的一个数据备份工具。顾名思义,mysqldump能够把mysql数据库导出成sql语句文件,并保存到磁盘上。mysqldump命令产生的.sql文件包含一系列SQL INSERT语句,能够用来进行数据恢复。mysql

假定咱们在星期日下午1点进行了备份,此时负荷较低。下面的命令能够彻底备份全部数据库中的全部表:sql

shell> mysqldump --single-transaction --all-databases > backup_sunday_1_PM.sql

各类用法说明shell

     A. 最简单的用法:数据库

 mysqldump -uroot -pPassword [database name] > [dump file]

     上述命令将指定数据库备份到某dump文件(转储文件)中,好比:bash

mysqldump -uroot -p123 test > test.dump

  生成的test.dump文件中包含建表语句(生成数据库结构哦)和插入数据的insert语句。服务器

     B. --opt网络

     若是加上--opt参数则生成的dump文件中稍有不一样:编辑器

     . 建表语句包含drop table if exists tableNameide

     . insert以前包含一个锁表语句lock tables tableName write,insert以后包含unlock tables


     C. 跨主机备份

     使用下面的命令能够将host1上的sourceDb复制到host2的targetDb,前提是host2主机上已经建立targetDb数据库:

mysqldump --host=host1 --opt sourceDb| mysql --host=host2 -C targetDb

  其中:-C指示主机间的数据传输使用数据压缩

 

     D. 只备份表结构

mysqldump --no-data --databases mydatabase1 mydatabase2 mydatabase3 > test.dump

 

    将只备份表结构。--databases指示主机上要备份的数据库。若是要备份某个MySQL主机上的全部数据库可使用--all-databases选项,以下:

 mysqldump --all-databases
> test.dump

     E. 从备份文件恢复数据库

 mysql [database name] < [backup file name]

使用mysqldump进行数据备份,至少有两个问题:

(1)mysqldump运行时,须要消耗必定的计算资源。并且数据库越大,消耗的计算资源也就越多,所以可能会形成系统在备份时运行效率低,容易形成用户卡死。

(2)对mysqldump备份的数据进行恢复,会丢掉从备份点开始的更新数据。

为了解决第2点的问题, mysql文档中给出了一个解决办法。那就是利用mysqlbinlog二进制文件保存增量的数据。采用全量mysqldump+增量mysqlbinlog的方式进行数据恢复。

mysqlbinlog

 

mysqlbinlog就是mysql的二进制数据文件。在对mysql进行一些配置以后,mysql会把数据库的更新操做都记录在一个文件中。mysqlbinlog能够在mysqld的--bin-log选项或者在配置文件(my.cnf或者my.ini)中打开。

[mysqld]

log-bin=mysql-bin   //[必须]启用二进制日志

 

在启用了二进制日志之后,在mysql的数据目录下,会出现一些以数字为结尾的文件,例如:

-rw-rw---- 1 guilhem  guilhem   1277324 Nov 10 23:59 mysql-bin.000001
-rw-rw---- 1 guilhem  guilhem         4 Nov 10 23:59 mysql-bin.000002 

这些文件就是二进制的日志文件。每次mysql启动都会增长一个文件。 

下面回到上节提出的问题,如何采用全量mysqldump+增量mysqlbinlog的方式进行数据恢复?

mysqldump全量备份+mysqlbinlog二进制日志增量备份

从mysqldump备份文件恢复数据会丢失掉从备份点开始的更新数据,因此还须要结合mysqlbinlog二进制日志增量备份。确保my.ini或者my.cnf中包含下面的配置以启用二进制日志,或者mysqld ---log-bin:

[mysqld]
log-bin=mysql-bin

在每次使用mysqldump进行全量数据备份时,用--flush-logs选项:

mysqldump --single-transaction --flush-logs --master-data=2 > backup.sql

在使用这样的语句进行备份以后,mysql就会关闭原来的二进制日志文件,开启一个新的二进制日志文件。好比,新开启的二进制日志文件为 mysql-bin.000003。 那么在进行数据恢复的时候,你能够利用backup.sql进行全量恢复+ mysql-bin.000003进行增量同步。

数据恢复的方法也很简单。

shell> mysql -uroot -pPwd < backup_sunday_1_PM.sql

shell> mysqlbinlog mysql-bin.000003 | mysql -uroot -pPwd

或者:

cat backup.sql | mysql -uroot -ppassword
mysqlbinlog mysql-bin.000003 | mysql -uroot -ppassword

此外mysqlbinlog还能够指定--start-date、--stop-date、--start-position和--stop-position参数,用于精确恢复数据到某个时刻以前或者跳过中间某个出问题时间段恢复数据,直接摘录MySQL文档说明中相关内容以下:

5.9.3.1. 指定恢复时间
对于MySQL 4.1.4,能够在mysqlbinlog语句中经过--start-date和--stop-date选项指定DATETIME格式的起止时间。举例说明,假设在今天上午10:00(今天是2005年4月20日),执行SQL语句来删除一个大表。要想恢复表和数据,你能够恢复前晚上的备份,并输入:
mysqlbinlog --stop-date="2005-04-20 9:59:59" /var/log/mysql/bin.123456 \
     | mysql -u root -pmypwd
该命令将恢复截止到在--stop-date选项中以DATETIME格式给出的日期和时间的全部数据。若是你没有检测到几个小时后输入的错误的SQL语句,可能你想要恢复后面发生的活动。根据这些,你能够用起使日期和时间再次运行mysqlbinlog:

mysqlbinlog --start-date="2005-04-20 10:01:00" /var/log/mysql/bin.123456 \
     | mysql -u root -pmypwd \
在该行中,从上午10:01登陆的SQL语句将运行。组合执行前夜的转储文件和mysqlbinlog的两行能够将全部数据恢复到上午10:00前一秒钟。你应检查日志以确保时间确切。下一节介绍如何实现。

5.9.3.2. 指定恢复位置
也能够不指定日期和时间,而使用mysqlbinlog的选项--start-position和--stop-position来指定日志位置。它们的做用与起止日选项相同,不一样的是给出了从日志起的位置号。使用日志位置是更准确的恢复方法,特别是当因为破坏性SQL语句同时发生许多事务的时候。要想肯定位置号,能够运行mysqlbinlog寻找执行了不指望的事务的时间范围,但应将结果从新指向文本文件以便进行检查。操做方法为:
mysqlbinlog --start-date="2005-04-20 9:55:00" --stop-date="2005-04-20 10:05:00" \
      /var/log/mysql/bin.123456 > /tmp/mysql_restore.sql
该命令将在/tmp目录建立小的文本文件,将显示执行了错误的SQL语句时的SQL语句。你能够用文本编辑器打开该文件,寻找你不要想重复的语句。若是二进制日志中的位置号用于中止和继续恢复操做,应进行注释。用log_pos加一个数字来标记位置。使用位置号恢复了之前的备份文件后,你应从命令行输入下面内容:

mysqlbinlog --stop-position="368312" /var/log/mysql/bin.123456 \
    | mysql -u root -pmypwd 
 
mysqlbinlog --start-position="368315" /var/log/mysql/bin.123456 \
    | mysql -u root -pmypwd \ 
上面的第1行将恢复到中止位置为止的全部事务。下一行将恢复从给定的起始位置直到二进制日志结束的全部事务。由于mysqlbinlog的输出包括每一个SQL语句记录以前的SET TIMESTAMP语句,恢复的数据和相关MySQL日志将反应事务执行的原时间。

 mysqlbinlog是一个读取 mysql二进制日志输出sql语句的命令行工具。使用方法能够从http://doc.mysql.cn/mysql5/refman-5.1-zh.html-chapter/client-side-scripts.html#mysqlbinlog 查到。

还记得上文提出的mysqldump备份的两个问题吗,如今第二个问题解决了,第一个问题尚未解决

“ mysqldump运行时,须要消耗必定的计算资源。并且数据库越大,消耗的计算资源也就越多,所以可能会形成系统在备份时运行效率低,容易形成用户卡死。”

下文中咱们利用mysql主从同步来解决这个问题。

主从同步

主从同步的含义很是简单。经过必定的设置,让两台或者多台mysql服务器的数据保持一致。设置的方法网上已经有不少方法了,推荐这篇帖子http://369369.blog.51cto.com/319630/790921

设置成主从同步以后,基本上就免去了天天全量备份之苦。并且一但主数据库出问题,能够立刻切换到从数据库进行服务,大大减小了故障恢复的时间。

 

我讲一讲我在配置中遇到的2个问题:

 

1 在从服务器上 show slave status时,显示 Slave_SQL_Running: No. 错误的缘由是 mysql 数据库的db表已经存在,不能再创建。

 

错误的缘由是这样的, 我在每台数据上都运行了 mysql_install_db这个命令安装了 mysql test info_schema这3个数据库。当我主从同步开始时,主数据库要向从数据库同步创建mysql数据库的操做。而从数据库已经创建了mysql数据库。

 

我解决的方法是在配置文件里指明写二进制文件的数据库名称。只有真正须要同步的业务数据库才写二进制文件。

主数据库:

[mysqld]

binlog-do-db=exampledb

 

从数据库:

[mysqld]

replicate-do-db=exampledb

 

2 个人主数据库已经运行有一段时间了。在从服务器设置master_log_pos的时候设置成主服务器的当前日志位置。结果同步时也出现了Slave_SQL_Running: No. 错误的缘由是: 执行Insert语句时数据表没有创建。

 

错误的缘由也很简单,我在从数据库里面尚未创建对应的数据库,而同步的操做为插入数据。

 

解决的方法是经过mysqldump对主数据库进行一次全量数据备份,而且在从数据库中恢复这个备份以后才开始进行主从同步。

 

参考:

一、 https://www.cnblogs.com/martinjinyu/articles/3750422.html

二、https://www.cnblogs.com/feichexia/p/MysqlDataBackup.html