返回

Rsync在多个服务器间同步备份网站

之前一直想着利用软件在多个服务器之间同步数据,一来可以用来备份数据,二来如果之后想要实现负载均衡也要保证多台机器上的数据一致,今天了解了一下rsync,并在两台服务器上实践了一下。

Rsync同步备份网站

之前一直想着利用软件在多个服务器之间同步数据,一来可以用来备份数据,二来如果之后想要实现负载均衡也要保证多台机器上的数据一致,今天了解了一下rsync,并在两台服务器上实践了一下。

配置ssh密钥登录

rsync可以在本地的两个文件夹之间同步数据,也可以将一台服务器上的数据同步到远程的另外一台服务器,可以经由ssh的方式传输,也可以使用rsync自己的daemon来传输(运行一个服务器端),我采用了第一种方案,而rsync里面是不能直接设置ssh的连接密码的,显然不利于自动化的同步,所以我们首先要为服务器配置好密钥登录。

使用ssh-keygen生成密钥,分为公钥和私钥。我们需要将公钥中的内容复制到远程服务器(需要上传数据过去的),并把公钥加到要登陆的用户的用户目录下的authorized_keys文件中(如果是root就是/root/.ssh/authorized_keys 普通用户则是 /home/用户名/.ssh/authorized_keys)。配置好之后可以试着用ssh -i privkey root@example.com登录一下,看看能否直接连接。

使用rsync同步站点文件

首先先考虑站点文件的备份,需要备份的有/var/www/html下的文件,使用下面的命令:

-a: 等价于-rlptgoD,归档式
-r: 递归
-l: 复制软件链接
-p: 保留权限信息
-t: 将src的修改时间,同步到dest
-g: 同步组信息(group)
-o: 同步拥有者信息(own)
-D: 保持字符与块设备文件
-z: 启用压缩传输
–delete:如果src没有此文件,那么dest也不能有,即在dest删除src里没有的文件。(如果你使用这个选项,就必须搭配-r选项一起)
# -a代表archive模式,会递归同步文件夹下的文件并且会保留修改日期、权限等元数据
# --delete 表示如果本地删除了文件,远程也会删除对应的文件
# 注意,文件后面加 / 的话,是不会在远程目录下新建同名文件夹的,而只是把源目录下的文件同步过去。
rsync -e 'ssh -i /root/.ssh/privkey' -av --progress --delete  /var/www/html/source1 /var/www/html/source2 root@example.com:/var/www/html/backup
#注意下面就没用delete,并且源目录后面加了 / 表示目录中的文件
rsync -e 'ssh -i /root/.ssh/privkey' -av --progress  /etc/nginx/sites-available/ root@example.com:/etc/nginx/sites-available

第一次同步会比较耗时,之后的同步就快了,因为rsync会采取增量同步的方式,只同步发生了变化的文件,更多的命令可以参考此文

数据库同步

上面的命令已经同步了网站的文件,但是还有一个问题就是动态网站还需要将数据库进行同步。数据库的同步有一点麻烦,如果直接同步可能会在不同的数据库管理程序版本上出现问题。数据库没办法直接按文件同步的方式来进行同步(至少很麻烦)愿意折腾的可以参考这篇文章https://www.electricmonk.nl/log/2016/11/06/very-fast-mysql-slave-setup-with-zero-downtime-using-rsync/,使用mysql的主从复制。

考虑到个人网站数据不会有频繁的写入,并且数据库暂时出现一点差异影响也不是特别大,所以我采用了mysqldump配合rsync以及entr的同步方法,我的想法是远程服务器创建同名数据库和数据库用户,密码设置也一样,同步之前先在本地服务器mysqldump一下,然后rsync同步到远程,远程服务器检测到文件发生变化执行mysql导入的命令即可。

首先要解决的问题就是如何在目录发生变化的时候执行命令

google了一下linux execute command when file changes,找到了很多种解决方案,比如inotify-tool或者entr,这里我使用了entr命令,参考How to Run a Linux Command When a File Set Changes

apt install entr
#另外由于entr执行完一次命令之后便会返回,所以我们想要监控目录变化需要把entr写到循环里面去
# 另外由于entr会在子shell中执行,所以下面用到了exprt -f,还有,如果dir目录中一个文件都没有,会导致刷屏,所以可以先新建一个空文件
do_it(){
 echo Directory files change!; 
 #在这里执行mysql数据导入 偷了个懒,每次都导入了多个数据库,其实完全可以分开多个目录监控,调用多个函数来导入
 mysql -u typecho -ptypecho typechodb < typechodb.sql
}
export -f do_it
while true; do 
        ls /home/datasyn/* | entr -pd -s do_it; 
done

通过bash运行之后,尝试使用rsync同步文件看看反应如何。

mysqldump -u typecho -p typecho > database/typechodb.sql
rsync -e 'ssh -i /root/.ssh/privkey' -av --progress  /home/sync/database/ root@example.com:/home/databasesyn

实际测试之后,发现确实可以进行同步了。

参考

https://einverne.github.io/post/2017/07/rsync-introduction.html

https://www.ruanyifeng.com/blog/2020/08/rsync.html

https://docs.microsoft.com/zh-cn/azure/virtual-machines/linux/create-ssh-keys-detailed

https://wangdoc.com/ssh/key.html

comments powered by Disqus
本站访客数:
Built with Hugo
Theme Stack designed by Jimmy