自从成为mjj以后手头上VPS很多啊,真的是遏制不住自己的欲望去买买买。但是,为了保证我的博客能在多台服务器上保持数据同步,我也是花了不少精力。我厌烦cron自动打包博客的目录然后手动备份,说到底还是懒惰,希望能全自动解决问题。正好,我的typecho博客也是docker镜像部署的,那也就再麻烦一下下折腾一下多端数据同步的问题,做到一个站点更改,所有站点响应。
在多台服务器之间同步文件,rsync 是一个常用的工具。它通过增量传输、压缩和删除操作,实现了高效的目录同步。然而,rsync 的经典工作模式是"手动或定时触发",这对于那些需要实时同步的场景而言显得力不从心。
1. rsync 的工作模式
rsync 通过比较源和目标目录之间的差异,仅传输发生变化的文件或数据块,从而减少带宽消耗。这种方式非常适合备份和同步大量数据,特别是在带宽有限的环境下。然而,rsync 通常需要通过手动或定时任务(如 cron)触发。对于需要实时更新的应用场景,这种模式会导致数据滞后和资源浪费。
2. rsync + inotify 的不足
为了解决实时同步的问题,可以使用 inotify 监控文件系统的变化,并在发生变化时触发 rsync。然而,这种方式有几个明显的不足:
- inotify 需要额外的脚本来结合 rsync 工作,增加了系统的复杂度。
- 这种方案通常是单向的,无法实现多源实时同步。这与我的目的相互违背了。
3. lsyncd 的优势
为了解决上述问题,lsyncd 结合了 inotify 的实时监控能力和 rsync 的高效传输能力,实现了简单而强大的多源实时同步。lsyncd 的优势在于:
- lsyncd 通过一个简单的配置文件即可完成复杂的实时同步任务,无需编写额外的脚本。
- 支持多台服务器间的双向或多向同步,确保每台服务器上的数据都是最新的。这点对于我而言十分重要。
4. lsyncd 的保姆级配置教程
以下是如何使用 lsyncd 实现多源实时同步的步骤:
安装 lsyncd 和 rsync:
在所有参与同步的服务器上,运行以下命令安装必要工具:
sudo apt-get install lsyncd rsync
配置 lsyncd:
在每台服务器上,创建配置文件 /etc/lsyncd.conf
,内容如下:
settings {
logfile = "/var/log/lsyncd/lsyncd.log",
statusFile = "/var/log/lsyncd/lsyncd.status",
inotifyMode = "CloseWrite or Modify",
maxProcesses = 1,
maxDelays = 1,
-- nodaemon =true,
}
sync {
default.rsyncssh,
source = "/var/www",
targetdir = "/var/www",
host = "45.*.*.*",
delete = true,
rsync = {
binary = "/usr/bin/rsync",
archive = true,
compress = true,
verbose = true,
},
delay = 1,
}
解释:
source
:本地的监控目录/var/www/
。(替换成你自己的)host
:远程目标服务器(排除自身)。targetdir
:远程目标目录/var/www/
。(替换成你自己的)delay
:设置延迟同步时间(秒),可以防止频繁变动时过多同步。delete
:在目标服务器上删除在源服务器上已删除的文件。
注:使用rsyncssh时maxProcesses必须为1,使用rsync时可以选择大一点的数值(比如5)
注意:为了查错,建议先用 lsyncd /etc/lsyncd.conf
启动一下,来排除错误。另外,请先建立好 log 的目录,即 mkdir /var/log/lsyncd
。
这里还要另外提一嘴,为了让各服务器能够无密码登录到彼此,需要配置 SSH 无密码登录。
为了实现自动化的实时同步,需要确保源服务器能够通过 SSH 无密码登录到目标服务器。
在源服务器上生成 SSH 密钥:
ssh-keygen -t rsa
按提示完成操作,通常不设置密码短语。
将公钥复制到目标服务器:
ssh-copy-id user@target-server
这会将生成的公钥复制到目标服务器,以便能够无密码登录。注意:两边的服务器都要配置。
配置完成后启动验证即可。
启动 lsyncd:
lsyncd -log Exec /etc/lsyncd.conf
验证配置:
在任意一台服务器的 /var/www/
目录中进行文件操作,检查其他服务器的同步情况。
5. 冲突解决的方法
当多台服务器同时对同一文件进行修改时,可能会产生冲突。但是我懒,而且我的使用场景应该不会出现冲突。所以不改了 :D