web项目中,图片上传功能很常见,对于小应用来说,一般没有用到DFS,就直接存储到本地磁盘上。

现在需要把包含这样功能的一个项目,从单点服务器迁移到双机vip上去,而且由于服务器是由合作方提供的,我没法通过ip或者域名指定访问哪一台服务器。

考虑了两种方案:

1、使用一台机器作为文件存储服务器。上传图片时,仅存储在该服务器上。读取图片时,web server通过内网ip访问该文件服务器,缓存在本地。

2、每台web server都存储同样的图片。上传图片时,同步到所有web server上。读取图片时,直接读取本地图片。

考虑到,我最好能在半天内完成该部分工作,而我们的功能决定,图片上传是少数功能,且目前看来,admin上传的图片占绝大多数,所以写时的体验不是很重要。所以,以一种简单的方式,实现方案2。即,综合使用php的remote file读写功能,和ftp。

首先配置ftp。

  • yum install vsftpd,安装ftp daemon。
  • adduser -d /tmp/ftpbasedir/ -g ftp -s /sbin/nologin ftpusername
  • passwd ftpusername 更改密码
  • 配置/etc/vsftpd/vsftpd.conf (http://www.linuxsir.org/main/node/152?q=node/152#8.5) :这里禁止匿名访问,允许local用户upload
  • chmod 0777 /tmp/ftpbasedir/ -R 允许所有人读写
  • service vsftpd start 启动服务。最好加入到/etc/rc.local中,使开机自动启动
  • ftp 尝试连接和上传,确保没有错误

然后修改php代码,原先代码里可能会有这样的code:

if (move_uploaded_file($fileTmp, $output)) {
chmod($output, 0644);
}
修改为:
global $img_hosts;
if (strpos($output, GLOBAL_IMG_ROOT) === 0){
$output = substr($output, strlen(GLOBAL_IMG_ROOT));
}
foreach($img_hosts as $i){
if ($i != $_SERVER[‘SERVER_ADDR’]){
$remote_file = sprintf(“ftp://%s:%s@%s%s”,SECRET_FTP_USER, SECRET_FTP_PWD, $i, $output);
if (!($fp = fopen($remote_file, ‘w’))){
error_log(“Sync to $remote_file fail”);
continue;
}
if(false === fwrite($fp, file_get_contents($fileTmp))){
error_log(“Sync-write to $remote_file fail”);
}
error_log(“Sync-write to $remote_file OK”);
fclose($fp);
}
}
unlink($fileTmp);
这里,用了sync的方式,将file同步到多台server,如果server较多,可以考虑使用异步或者队列的方式。并且,最好开一个cron,检测是否有同步失败的情况,进行重传。
————————————————————————-

内网情况下,也可以使用NFS实现,具体参看:http://linux.vbird.org/linux_server/0330nfs.php 进行配置。

注:rpcbind改名为portmap了,所以只要有portmap命令运行着,就可以尝试启动nfs。

注:更改了NFS server的配置 /etc/exports 之后,通过exportfs -ra来重新载入。

2 Comments

  1. lan says:

    这样的代码也太复杂了,我宁愿用NFS 或者后台起一个脚本定时rsync

  2. admin says:

    hello~lan!

    是的,后来是使用了NFS~谢谢您的建议

Leave a Reply