# 12.4 备份和恢复
这小节我们要讨论应用程序管理的另一个方面：生成服务器上数据的备份和恢复。我们经常会遇到生成服务器的网络断了、硬盘坏了、操作系统奔溃、或者数据库不可用了等各种情况，所以我需要对我们的生成服务器上的应用、数据做异地灾备，冷备热备。在下面的介绍中，将讲解如何备份应用、如何备份Mysql数据库以及将其恢复，如何备份redis数据库以及恢复。

## 应用备份
在大多数集群坏境下，Web应用程序基本不需要备份，因为这个其实就是一个代码副本，我们在本地开发环境中，或者版本控制系统中已经保持了这些代码。但是很多时候，我们开发的站点需要用户动态来上传文件，那么我们需要对这些上传的文件进行备份，目前其实一种合适的做法是把和网站相关的需要存储的文件存储到云储存，这样即使系统奔溃我们的文件还在云储存，至少数据不会丢失。

如果我们没有采用云储存的情况下，如何做到网站的备份呢？这里我们介绍一个文件同步工具rsync：rsync能够实现网站的备份，文件的同步，不同系统的文件的同步，如果是windows的话，需要windows版本cwrsync。

### rsync安装
rysnc的官方网站：http://rsync.samba.org/ 可以从上面获取最新版本的源码。当然，因为rsync是一款如此有用的软件，所以很多Linux的发行版本都将它收录在内了。

软件包安装

	# sudo apt-get  install  rsync  注：在debian、ubuntu 等在线安装方法；
	# yum install rsync    注：Fedora、Redhat、CentOS 等在线安装方法；
	# rpm -ivh rsync       注：Fedora、Redhat、CentOS 等rpm包安装方法；

其它Linux发行版，请用相应的软件包管理方法来安装。源码包安装

	tar xvf  rsync-xxx.tar.gz
	cd rsync-xxx
	./configure --prefix=/usr  ;make ;make install   注：在用源码包编译安装之前，您得安装gcc等编译开具才行；

### rsync配置
rsync主要有以下三个配置文件rsyncd.conf(主配置文件)、rsyncd.secrets(密码文件)、rsyncd.motd(rysnc服务器信息)。

关于这几个文件的配置大家可以参考官方网站或者其他介绍rsync的网站，下面介绍服务器端和客户端如何开启

- 服务端开启：

		#/usr/bin/rsync --daemon  --config=/etc/rsyncd/rsyncd.conf

	--daemon参数方式，是让rsync以服务器模式运行。把rsync加入开机启动

		echo 'rsync --daemon' >> /etc/rc.d/rc.local
		
	设置rsync密码

		echo '你的用户名:你的密码' > /etc/rsyncd.secrets
		chmod 600 /etc/rsyncd.secrets


- 客户端同步：

	客户端可以通过如下命令同步服务器但的文件：
	
		rsync -avzP  --delete  --password-file=rsyncd.secrets   用户名@192.168.145.5::www /var/rsync/backup
	
	这条命令，简要的说明一下几个要点：
	
	1. -avzP是啥，读者可以使用--help查看
	2. --delete 是为了比如A上删除了一个文件，同步的时候，B会自动删除那个文件
	3. --password-file 客户端中/etc/rsyncd.secrets设置的密码，要和服务端的 /etc/rsyncd.secrets 中的密码一样，这样cron运行的时候，就不需要密码了
	4. 这条命令中的"用户名"为服务端的 /etc/rsyncd.secrets中的用户名
	5. 这条命令中的 192.168.0.100 为服务端的IP地址
	6. ::www，注意是2个 : 号，www为服务端的配置文件 /etc/rsyncd.conf 中的[www]，意思是根据服务端上的/etc/rsyncd.conf来同步其中的[www]段内容，一个 : 号的时候，用于不根据配置文件，直接同步指定目录。
	
	为了让同步实时性，可以设置crontab，保持rsync每分钟同步，当然用户也可以根据文件的重要程度设置不同的同步频率。
	

## MySQL备份
应用数据库目前还是MySQL为主流，目前MySQL的备份有两种方式：热备份和冷备份，热备份目前主要是采用master/slave方式，关于如何配置这方面的资料，大家可以找到很多。master/slave方式的同步目前主要用于读写分离，其实也可以用于热备份数据。冷备份的话就是数据有一定的延迟，但是可以保证该时间段之前的数据完整，例如有些时候可能我们的误操作引起了数据的丢失，那么master/slave模式是无法找回丢失数据的，但是通过冷备份可以部分恢复数据。

冷备份一般使用shell脚本定时的备份数据库，然后通过上面介绍rsync同步到异地机房的一台服务器。

下面这个是定时备份mysql的备份脚本，我们使用了mysqldump程序，这个命令可以把数据库导出到一个文件中。

	#!/bin/bash

    # 以下配置信息请自己修改
    mysql_user="USER" #MySQL备份用户
    mysql_password="PASSWORD" #MySQL备份用户的密码
    mysql_host="localhost"
    mysql_port="3306"
    mysql_charset="utf8" #MySQL编码
    backup_db_arr=("db1" "db2") #要备份的数据库名称，多个用空格分开隔开 如("db1" "db2" "db3")
    backup_location=/var/www/mysql  #备份数据存放位置，末尾请不要带"/",此项可以保持默认，程序会自动创建文件夹
    expire_backup_delete="ON" #是否开启过期备份删除 ON为开启 OFF为关闭
    expire_days=3 #过期时间天数 默认为三天，此项只有在expire_backup_delete开启时有效

    # 本行开始以下不需要修改
    backup_time=`date +%Y%m%d%H%M`  #定义备份详细时间
    backup_Ymd=`date +%Y-%m-%d` #定义备份目录中的年月日时间
    backup_3ago=`date -d '3 days ago' +%Y-%m-%d` #3天之前的日期
    backup_dir=$backup_location/$backup_Ymd  #备份文件夹全路径
    welcome_msg="Welcome to use MySQL backup tools!" #欢迎语

    # 判断MYSQL是否启动,mysql没有启动则备份退出
    mysql_ps=`ps -ef |grep mysql |wc -l`
    mysql_listen=`netstat -an |grep LISTEN |grep $mysql_port|wc -l`
    if [ [$mysql_ps == 0] -o [$mysql_listen == 0] ]; then
            echo "ERROR:MySQL is not running! backup stop!"
            exit
    else
            echo $welcome_msg
    fi

    # 连接到mysql数据库，无法连接则备份退出
    mysql -h$mysql_host -P$mysql_port -u$mysql_user -p$mysql_password <<end
    use mysql;
    select host,user from user where user='root' and host='localhost';
    exit
    end

    flag=`echo $?`
    if [ $flag != "0" ]; then
            echo "ERROR:Can't connect mysql server! backup stop!"
            exit
    else
            echo "MySQL connect ok! Please wait......"
            # 判断有没有定义备份的数据库，如果定义则开始备份，否则退出备份
            if [ "$backup_db_arr" != "" ];then
                    #dbnames=$(cut -d ',' -f1-5 $backup_database)
                    #echo "arr is (${backup_db_arr[@]})"
                    for dbname in ${backup_db_arr[@]}
                    do
                            echo "database $dbname backup start..."
                            `mkdir -p $backup_dir`
                            `mysqldump -h$mysql_host -P$mysql_port -u$mysql_user -p$mysql_password $dbname --default-character-set=$mysql_charset | gzip > $backup_dir/$dbname-$backup_time.sql.gz`
                            flag=`echo $?`
                            if [ $flag == "0" ];then
                                    echo "database $dbname success backup to $backup_dir/$dbname-$backup_time.sql.gz"
                            else
                                    echo "database $dbname backup fail!"
                            fi
                            
                    done
            else
                    echo "ERROR:No database to backup! backup stop"
                    exit
            fi
            # 如果开启了删除过期备份，则进行删除操作
            if [ "$expire_backup_delete" == "ON" -a  "$backup_location" != "" ];then
                     #`find $backup_location/ -type d -o -type f -ctime +$expire_days -exec rm -rf {} \;`
                     `find $backup_location/ -type d -mtime +$expire_days | xargs rm -rf`
                     echo "Expired backup data delete complete!"
            fi
            echo "All database backup success! Think you!"
            exit
    fi
    
修改shell脚本的属性：
    
	chmod 600 /root/mysql_backup.sh
	chmod +x /root/mysql_backup.sh

设置好属性之后，把命令加入crontab，我们设置了每天00:00定时自动备份，然后把备份的脚本目录/var/www/mysql设置为rsync同步目录。

	00 00 * * * /root/mysql_backup.sh    

## MySQL恢复
前面介绍MySQL备份分为热备份和冷备份，热备份主要是目的是为了能够实时的恢复，例如应用服务器出现了硬盘故障，那么我们可以通过修改配置文件把数据库的读取和写入改成slave，这样就可以尽量少时间的中断服务。

但是有时候我们需要通过冷备份的SQL会进行数据恢复，既然有了数据库的备份，就可以通过命令导入：

	mysql -u username -p databse < backup.sql
	
可以看到，导出和导入数据库数据都是相当简单，不过如果还需要管理权限，或者其他的一些字符集的设置的话，可能会稍微复杂一些，但是这些都是可以通过一些命令来完成的。

## redis备份
redis是目前我们使用最多的NOSQL，它的备份也分为两种：热备份和冷备份，redis也支持master/slave模式，所以我们的热备份可以通过这种方式实现，相应的配置大家可以参考官方的文档配置，相当的简单。我们这里介绍冷备份的方式：redis其实会定时的把内存里面的缓存数据保存到数据库文件里面，我们备份只要备份相应的文件就可以，然后利用前面介绍的rsync备份到异地机房就可以实现。

## redis恢复
redis的恢复分为热备份恢复和冷备份恢复，热备份恢复的目的和方法同MySQL的恢复一样，只要修改应用的相应的数据库连接即可。

但是有时候我们需要根据冷备份来恢复数据，redis的冷备份恢复其实就是只要把保存的数据库文件copy到redis的编译目录，然后启动redis就可以了，redis在启动的时候会自动加载数据库文件到内存中，启动的速度根据数据库的文件大小来决定。

## 小结
本小节介绍了当我们应用部分完毕之后，如何做好灾备，包括文件的备份、数据库的备份，这里我们介绍了rsync如何同步文件，MySQL数据库和redis数据库如何备份和恢复，希望通过本小节的介绍，能够让作为开发的你对于线上产品的灾备方案提供一个参考。 
 
## links
   * [目录](<preface.md>)
   * 上一章: [应用部署](<12.3.md>)
   * 下一节: [小结](<12.5.md>)