在 Discuz 中应用 MogileFS 分布式文件存储系统
本文讨论内容基于 Discuz 7, Red Hat Enterprise Linux AS 4, MogileFs Server 2.17, MogileFS Client 1.08, MogileFS Utils 2.14
MogileFS 安装和配置
安装
基本安装顺序是 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 也可以是多个。
安装 MogileFS PHP 扩展
从 http://svn.usrportage.de/php-mogilefs/trunk/ 获取源代码编译安装:
$ phpize
$ ./configure
$ make install
将生成的 php-mogilefs.so 复制到 PHP 扩展目录,在 php.ini 添加一行扩展配置:
extension=php-mogilefs.so
重启 WEB 服务,用 phpinfo() 函数测试,如果显示结果如下图显示则表示安装成功
该扩展提供的方法和函数可以直接使用,不过为了方便维护,可以对之进行一下简单的封装。
改造 Discuz 的附件系统
接下来会应用到 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() 函数的处理流程:
- 判断 MogileFs 扩展是否加载,否则退出处理
- 获取 MogileFs 单个操作实例
- 根据传入的附件信息($target, $attach)生成 attach_key,然后往 MogileFs 提交文件
- 如果附件是图片,检查图片的缩略图是否存在,如果存在,则生成 thumb_key ,然后往 MogileFs 提交缩略图文件
附件删除
Discuz 7 中附件文件的删除由include/global.func.php
文件里的dunlink()
函数处理,我们在该函数结束之前添加 MogileFs 的文件删除处理:
dz_do_action('mogilefs_attachment_delete', $filename, $havethumb);
mogilefs_attachment_delete() 函数的处理流程:
- 判断 MogileFs 扩展是否加载,否则退出处理
- 获取 MogileFs 单个操作实例
- 根据传入的附件路径 $filename 生成 attach_key,然后通过 MogileFs 提供的方法删除文件
- 根据 $havethumb 判断是否存在缩略图,若存在则生成 thumb_key,然后通过 MogileFs 提供的方法删除文件
由于附件的上传中可能出现错误,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() 的处理流程
- 判断 MogileFs 扩展是否加载,否则退出处理
- 获取 MogileFs 单个操作实例
- 根据传入参数判断读取的是缩略图还是原附件,生成 thumb_key 或 attach_key
- 通过 MogileFs 扩展提供的方法读取文件内容
- 输出
当然,此外还有一些细节处理,如文件大小,文件头响应输出等,不再赘述。
Comments
不愧是做技术的,厉害。
@Chen: 这还只是初级的应用而已。
好复杂啊 看不懂
看上去,有点复杂,不懂
怎么实现 WordPress首页每个分类只出现一篇文章
要实现排序。就是最新发布的放在前面。。。
所以。现有的那个函数没法用的。因为没办法排序。
怎么查询数据库才能 每个分类查询出来最新的一篇文章呢?
比如。我有十个分类。
然后 调用 每个分类的最新文章。然后这十篇文章按照发布时间排序。
具体怎么实现呢|
请大神赐教。万分感谢
@布衣: 已经邮件回复给你了
我怎么总也配置不成功呢,怎么回事呢
Unable to find MogileFS::Admin module. Please ensure that you have the
module installed in a location in your search path. Or, add a search path
to mogadm:
mogadm –lib=/path/to/lib
Or add it to the configuration file:
lib = /path/to/lib
@lgpzll: 检查一下 MogileFS-Utils 有没有安装正确
很详细 顶一个
Leave a Reply