两个web服务器,当用户访问server01时上传了文件,下次访问到server02时发现文件不存在了,因为上传的文件在server01上
解决方案无非就是使用第三方存储、文件同步。
使用第三方存储可以使用nfs、ftp同一保存在第三方文件服务器。而且PHP实现保存文件到第三方服务器也非常简单,比如说保存在ftp服务器,直接copy($file, 'ftp://test:test123@ftpserver/')就可以实现了,几乎连代码都不需要改,只需修改存储路径。但是在我的需求中遇到了一个问题,有时需要读取文件,貌似ftp协议的文件fopen之后无法fseek
文件同步最简单的方法就是使用inotify+rsync了,网上教程一大堆,但是都太啰嗦
有一点需要注意:网上大多数教程是只要监控到有改变的时候,直接同步整个目录,如果目录中文件很多,是非常消耗性能的,正确的做法是只同步当前变动的文件
还有一点需要注意:当创建文件的时候,会触发create事件,之后马上又会触发modify事件,所以,根本没有必要监控那么多事件
#!/bin/sh
inotifywait -rmq --format '%Xe %w%f' /var/www/web/public/upload/ /var/www/web/private/upload -e delete,create --exclude "/\." | while read line
do
echo $line
EVENT=$(echo $line | awk '{print $1}')
FILE=$(echo $line | awk '{print $2}')
if [ "$EVENT" = 'CREATE' -o "$EVENT" = 'MODIFY' -o "$EVENT" = 'CLOSE_WRITE' -o "$EVENT" = 'MOVED_TO' ]
then
rsync -ar $(dirname ${FILE})/ root@server02:$(dirname ${FILE})/
fi
if [ "$EVENT" = 'DELETE' -o "$EVENT" = 'MOVED_FROM' ]
then
rsync -ar --delete $(dirname ${FILE})/ root@server02:$(dirname ${FILE})/
fi
done
这种方式遇到了一些问题,经常出现一些文件没有同步过来,有时候同步文件的时候报文件不存在,因为是用root运行的,同步的文件目录权限是root,导致之后的文件上传都没有写权限
就算加上了保持文件属性和权限信息的参数rsync -artpogv,还是经常发生目录权限是root的问题
试试用rsync服务同步,不用ssh同步
首先配置rsync服务器
vi /etc/rsyncd.conf
uid = www-data
gid = www-data
log file = /var/log/rsyncd.log
[www]
path = /var/www #要同步的目录
auth users = user #rsync用户
read only = no #这个一定要设置,否则无法写入
secrets file = /etc/rsyncd.secrets #用户密码配置文件
comment = web upload file #备注,随意填写
客户端配置,配置rsync账号和密码
vi /etc/rsyncd.secrets
这个文件里面存储rsync的账号和密码,格式:user:password,每行一个
同步脚本:
#!/bin/sh
cd /var/www
inotifywait -rmq --format '%Xe %w%f' upload -e delete,create,modify,MOVED_TO,MOVED_FROM,CLOSE_WRITE --exclude "/\." | while read line
do
echo $line
EVENT=$(echo $line | awk '{print $1}')
FILE=$(echo $line | awk '{print $2}')
if [ "$EVENT" = 'CREATE' -o "$EVENT" = 'MODIFY' -o "$EVENT" = 'CLOSE_WRITE' -o "$EVENT" = 'MOVED_TO' -o "$EVENT" = "CLOSE_WRITEXCLOSE" -o "$EVENT" = "CREATEXISDIR" ]
then
rsync -aRtzpogv --password-file=rsyncd.password $FILE rsync://user@server01/www/
fi
if [ "$EVENT" = 'DELETE' -o "$EVENT" = 'MOVED_FROM' -o "$EVENT" = 'DELETEXISDIR' ]
then
rsync -aRrtpogv --delete --password-file=rsyncd.password $(dirname ${FILE})/ rsync://user@server01/www/
fi
done
说明:
inotifywait那一行是监听的upload 目录,这里可以监控多个目录,用空格分隔
这里rsync同步的时候用了参数R,表示使用相对路径,所以后面的目标目录只需要根路径就可以了
我对inotify的事件触发顺序不太清楚,所以尽量多监听一些事件,比如说在编辑文件的时候是否会同时触发modify、close_write、close_writexclose事件?创建文件的时候是否会同时触发create、close_write、close_writexclose事件?
手动测试了一下,上面的方案完美解决了问题。不知道部署之后会不会出现问题
2019.07.18追加:
当有文件写入耗时比较长的时候会出现文件内容错乱的问题,导致的原因是写入数据的时候会触发文件同步,同步到另一台服务器的时候又会触发文件同步,如此循环,导致新写入的数据被文件同步给冲了
解决办法是不监听create和modify事件,只需要监听close_write,只有在文件写入完毕之后才触发文件同步
参考:
http://www.ttlsa.com/web/let-infotify-rsync-fast/
https://www.cnblogs.com/Dev0ps/p/8948457.html