refer:http://www.voidman.com/2009/05/mogilefs-for-discuz.html
本文讨论内容基于 Discuz 7, Red Hat Enterprise Linux AS 4, MogileFs Server 2.17, MogileFS Client 1.08, MogileFS Utils 2.14
安装
基本安装顺序是 mogilefs-server (服务端), MogileFS-Client (客户端), MogileFS-Utils (工具包)。安装 MogileFS 其实并不复杂,但有些耗时,因为大多数据时间都被用在安装依赖包上了。在安装 MogileFS 之前有几个包是必需的:
Sys-Syscall-0.22 .tar.gz
Danga-Socket-1.56 .tar.gz
String-CRC32-1.4 .tar.gz
Gearman-1.07 .tar.gz
Gearman-Client-Async-0.93
Net-Netmask-1.9015 .tar.tar
Perlbal-1.70 .tar.tar
若在安装过程中还提示其它包不存在,可以根据提示到search.cpan.org 搜索相应的包装上。具体安装步骤可以参考这里 或这里 。
安装成功后,会提示安装了以下文件,在下文的 MogileF S配置部分中会提到。
/usr/bin/mogilefsd
/usr/bin/mogstored
/usr/bin/mogdbsetup
/usr/bin/mogautomount
/usr/bin/mogtool
/usr/bin/mogadm
数据库配置
MogileFS 通过数据库来维护文件的存储节点和存储份数等相关属性。 创建一个数据库命名为 mogilefs,创建一个用户 mogile,设置密码为 mogile
# mysql
mysql> CREATE DATABASE mogilefs;
mysql> GRANT ALL ON mogilefs.* TO 'mogile' @'%' ;
mysql> SET PASSWORD FOR 'mogile' @'%' = PASSWORD( 'mogile' ) ;
mysql> FLUSH PRIVILEGES ;
mysql> quit
然后通过 MogileFs 自带的工具创建表
# /usr/bin/mogdbsetup --dbhost=db.yourdomain.com --dbname=mogilefs --dbuser=mogile --dbpassword=mogile
tracker 配置
编辑 /etc/mogilefs/mogilefsd.conf
db_dsn DBI:mysql:mogilefs
db_user mogile
db_pass mogile
conf_port 6001
listener_jobs 5
存储节点配置
先编辑配置文件 /etc/moiglefs/mogstored.conf
httplisten =192.168 .0 .7 :7500
mgmtlisten =192.168 .0 .7 :7501
docroot =/var/mogdata
向系统添加存储节点主机,并查看是否添加成功。这里我们添加的主机名称是 file.yourdomain.com,IP为192.168.0.7
# /usr/bin/mogadm --trackers=192.168.0.7:6001 host add file.yourdomain.com --ip=192.168.0.7 --port=7500 --status=alive
# /usr/bin/mogadm --trackers=192.168.0.7:6001 host list
向系统添加存储节点设备,并查看是否添加成功
# mkdir /var/mogdata/dev1
# /usr/bin/mogadm --trackers=192.168.0.7:6001 device add file.yourdomain.com 1
# /usr/bin/mogadm --trackers=192.168.0.7:6001 device list
这里的 1 代表 file.yourdomain.com 主机下的存储设备编号,对应存储目录为 /var/mogdata/dev1
添加存储域。在 MogileFs 中,文件通过 KEY 来引用,KEY 在某个存储域下是唯一的。我们添加一个 bbs.yourdomain.com 域,论坛里的附件都存储到该域下。
# /usr/bin/mogadm --trackers=192.168.0.7:6001 domain add bbs.yourdomain.com
# /usr/bin/mogadm --trackers=192.168.0.7:6001 domain list
添加存储类别。在 MogileFs 中可以设置不同的存储类别存储不同份数的文件副本。我们添加一个 attach 类,每个文件至少存储 2 份
# /usr/bin/mogadm --trackers=192.168.0.7:6001 class add bbs.yourdomain.com attach --mindevcount=2
# /usr/bin/mogadm --trackers=192.168.0.7:6001 class list
最后在防火墙配置上述几个端口访问规则。现在可以启动 MogileFs,并查看进程与服务状态。
# /usr/bin/mogstored --daemon
# /usr/bin/mogilefsd -c /etc/mogilefs/mogilefsd.conf --daemon
# ps -fe |grep mogstored
# ps -fe |grep mogilefsd
# /usr/bin/mogadm --trackers=192.168.0.7:6001 check
# /usr/bin/mogadm --trackers=192.168.0.7:6001 stats
注:上述配置例子基于tracker,存储节点均在同一台主机,而实际使用上需要将存储节点分配到不同主机上才是真正意义上的分布式存储。甚至于 tracker 也可以是多个。
从 http://svn.usrportage.de/php-mogilefs/trunk/ 获取源代码编译安装:
$ phpize
$ ./configure
$ make install
将生成的 php-mogilefs.so 复制到 PHP 扩展目录,在 php.ini 添加一行扩展配置:
extension =php-mogilefs.so
重启 WEB 服务,用 phpinfo() 函数测试,如果显示结果如下图显示则表示安装成功
该扩展提供的方法和函数 可以直接使用,不过为了方便维护,可以对之进行一下简单的封装。
接下来会应用到 WordPress 的 Hook 机制,详见WordPress 的 Hook 机制在 Discuz 二次开发中的应用
附件上传
在 Discuz 7 中附件的上传由include/post.func.php
文件里的attach_upload()
函数处理,我们在其中增加将附件添加到 MogileFS 的处理。由于 Discuz 7 支持远程上传附件到 FTP,并且可以设置成只上传到远程 FTP,这会删除上传到 WEB 服务器的原始附件,所以要在这之前处理。
// begin of hack
dz_do_action( 'mogilefs_attachment_upload' , $attach , $target ) ;
// end of hack
// 找到以下这行代码,在这之前添加以上代码
$attach [ 'remote' ] = !$swfupload ? ftpupload( $target , $attach ) : 0 ;
mogilefs_attachment_upload 函数用来处理往 MoigleFs 添加附件。在前面提到,MogileFs 通过 KEY 来引用文件,我采用的 KEY 的规则是:
attach_{ attachment_md5} _{ ext}
attach_{ attachment_md5} _thumb_jpg
{md5} 是 Discuz 附件表 attachment 字段的 MD5 值,{ext} 是附件的扩展名。注意,Discuz 存储文件时会把部分可能不安全附件的后缀名更改为 attach。Discuz 中图片附件的缩略图均为 JPG 格式,所以 thumb_jpg 表示 JPG 格式缩略图的意思。
mogilefs_attachment_upload() 函数的处理流程:
附件删除
Discuz 7 中附件文件的删除由include/global.func.php
文件里的dunlink()
函数处理,我们在该函数结束之前添加 MogileFs 的文件删除处理:
dz_do_action( 'mogilefs_attachment_delete' , $filename , $havethumb ) ;
mogilefs_attachment_delete() 函数的处理流程:
由于附件的上传中可能出现错误,Discuz 7 会做回滚处理删除本次上传出现错误之前已经正常上传的附件,而这些文件同样已经被上传到 MogileFs,故也要做删除处理:
修改include/post.func.php
文件里的upload_error()
函数和ftpupload_error()
:
function upload_error( $message , $attacharray = array ( ) ) {
if ( !empty ( $attacharray ) ) {
foreach ( $attacharray as $attach ) {
@unlink ( $GLOBALS [ 'attachdir' ] .'/' .$attach [ 'attachment' ] ) ;
// begin of hack
dz_do_action( 'mogilefs_attachment_delete' , $attach [ 'attachment' ] , true ) ;
// end of hack
}
}
showmessage( $message ) ;
}
function ftpupload_error( $source , $attach ) {
@unlink ( $source ) ;
if ( $attach [ 'thumb' ] ) {
@unlink ( $source .'.thumb.jpg' ) ;
}
// begin of hack
dz_do_action( 'mogilefs_attachment_delete' , $source , $attach [ 'thumb' ] ) ;
// end of hack
showmessage( 'post_attachment_remote_save_error' ) ;
}
附件读取
附件的读取需要在 Discuz 后台打开“下载附件来路检查”选项,因为附件的读取操作是 hook 在attachment.php
文件上的。
缩略图处理
// begin of hack
dz_do_action( 'mogilefs_attachment_fetch' , $attach [ 'attachment' ] , true ) ;
// end of hack
//找到下面这行代码,在此之前添加上述代码
getlocalfile( $attachdir .'/' .$attach [ 'attachment' ] .'.thumb.jpg' ) ;
其他附件处理
先删除attachment.php
中的以下代码
if ( !$attach [ 'remote' ] && !is_readable ( $filename ) ) {
showmessage( 'attachment_nonexistence' ) ;
}
然后将以下代码添加到getlocalfile()
函数的起始处,接管该函数读取本地附件的处理。
// begin of hack
dz_do_action( 'mogilefs_attachment_fetch' , $filename ) ;
// end of hack
mogilefs_attachment_fetch() 的处理流程
当然,此外还有一些细节处理,如文件大小,文件头响应输出等,不再赘述。