相比较于MogileFS,FastDFS同样有tracker和storage这样的功能分类。但是FastDFS的tracker节点的元数据信息是由各个storage节点通过tcp协议上报得到的,因此在一定程度上减轻了tracker的负载压力。storage节点以group为单位进行组织。任何一个storage server都应该属于某个group,一个group应该包含多个storage server;在同一个group内部,各storage server的数据互相冗余。
本文通过构建FastDFS集群,结合安装了fastdfs插件的Nginx,实现图片文件的上传和访问功能
关于FastDFS
体系结构图
由下图可以看出,Tracker群中,各个tracker server相互独立,不进行相互的通信。Storage群中各个group组相互独立,不进行相互通信。也就是说,各个组之间保存的数据是不相同的。针对于每一个group组,其中的节点是属于相互备份的关系。图中的每一个Storage server会启动一个单独的线程主动向Tracker中的每一个tracker server报告其状态信息,包括磁盘使用情况,文件同步情况以及上传下载的次数统计等信息。
文件上传流程图
由下图可以看到,文件上传的流程可以分为4个步骤:
客户端通过API接口,与Tracker发生通信
Tracker返回给客户端一台可用的Storage server和端口号
客户端依据返回值,自动向对应的Storage server发送请求,并开始上传
上传完毕之后,Storage server返回给客户端所上传的文件的ID,并结束。
文件下载流程图
文件下载的流程可以分为3个步骤:
客户端通过Tracker server下载指定Storage组中的某个文件
Tracker server向客户端返回一个可用的Storage server的IP地址和端口号
Client直接通过Tracker server返回的IP地址和端口与其中一台Storage server建立连接并进行文件下载
FastDFS拓扑设计
设计结构和IP规划如下所示。这里采用一个客户端,两个tracker,4个storage,2个storage组的结构。
节点IP | 节点功能 |
---|---|
192.7.20.121 | FastDFS客户端,ansible主控端 |
192.7.20.60 | FastDFS tracker 节点1, FastDFS storage 节点1 |
192.7.20.61 | FastDFS tracker 节点2,FastDFS storage 节点2 |
192.7.20.62 | FastDFS storage 节点3 |
192.7.20.63 | FastDFS storage 节点4 |
ansible初始配置
为了方便安装配置,这里采用自动化运维工具ansible用来提高效率。首先在客户端上面配置3个host组,附加到/etc/ansible/hosts文件后面,分别命名为slave, ftracker, fstorage,内容如下所示。其中slave组和fstorage组的节点相同,只是出于配置的内容而分成了这两组:
[slave] 192.7.20.60 192.7.20.61 192.7.20.62 192.7.20.63 [ftracker] 192.7.20.60 192.7.20.61 [fstorage] 192.7.20.60 192.7.20.61 192.7.20.62 192.7.20.63
之后需要建立ssh免密码登录,在客户端主机上面使用ssh-copy-id
命令将客户端公钥导入到4台slave节点上面。
ssh-copy-id ~/.ssh/id_rsa.pub [email protected] ssh-copy-id ~/.ssh/id_rsa.pub [email protected] ssh-copy-id ~/.ssh/id_rsa.pub [email protected] ssh-copy-id ~/.ssh/id_rsa.pub [email protected]
之后,通过ping模块测试一下4台slave节点的连通状态,正常情况下,4台slave可通:
$ ansible slave -m ping 192.7.20.60 | SUCCESS => { "changed": false, "ping": "pong" } 192.7.20.62 | SUCCESS => { "changed": false, "ping": "pong" } 192.7.20.61 | SUCCESS => { "changed": false, "ping": "pong" } 192.7.20.63 | SUCCESS => { "changed": false, "ping": "pong" }
编译FastDFS源码,并进行部署
从GitHub面可以下载到最新版本的fastdfs源码文件,以及fastdfs依赖库源码文件。将二者都下载到客户端主机,并用unzip
命令解压,其目录中的内容如下所示:
fastdfs源码目录: client common conf COPYING-3_0.txt fastdfs.spec HISTORY init.d INSTALL make.sh php_client README.md restart.sh stop.sh storage test tracker libfastcommon源码目录: doc HISTORY INSTALL libfastcommon.spec make.sh php-fastcommon README src
分别查看fastdfs.spec文件以及libfastcommon.spec文件,可以发现,spec文件中所要求的Source的格式为%{name}-%{version}.tar.gz
的形式,因此,我们需要将fastdfs和libfastcommon的源码重新打包为带有version格式的tar.gz的压缩包。而版本号可以从spec文件的开头部分找到:
$ tar -zcvf libfastcommon-1.0.36.tar.gz libfastcommon-master/* $ tar -zcvf fastdfs-5.0.11.tar.gz fastdfs-master/*
在root家目录下面创建rpmbuild文件夹,并在该文件夹里面再创建SOURCES和SPECS两个文件夹,将fastdfs.spec和libfastcommon.spec文件复制到/root/rpmbuild/SPECS目录下面,将libfastcommon-1.0.36.tar.gz和fastdfs-5.0.11.tar.gz复制到/root/rpmbuild/SOURCES目录下面:
$ mkdir -pv /root/rpmbuild/{SOURCES,SPECS} $ cp fastdfs-master/fastdfs.spec /root/rpmbuild/SPECS $ cp libfastcommon-master/libfastcommon.spec /root/rpmbuild/SPECS $ cp fastdfs-5.0.11.tar.gz /root/rpmbuild/SOURCES $ cp libfastcommon-1.0.36.tar.gz /root/rpmbuild/SOURCES
进入SPECS目录,运行rpmbuild命令,分别将fastdfs和libfastcommon编译为rpm包。正常情况下,所编译完成的rpm包会在/root/rpmbuild/RPMS/i386或者/root/rpmbuild/RPMS/x86_64目录下面:
$ cd /root/rpmbuild/SPECS $ rpmbuild -bb libfastcommon.spec $ rpmbuild -bb fastdfs.spec $ ls /root/rpmbuild/RPMS/x86_64 | grep -iE 'fast*|lib*' fastdfs-5.0.11-1.el7.centos.x86_64.rpm fastdfs-debuginfo-5.0.11-1.el7.centos.x86_64.rpm fastdfs-server-5.0.11-1.el7.centos.x86_64.rpm fastdfs-tool-5.0.11-1.el7.centos.x86_64.rpm libfastcommon-1.0.36-1.el7.centos.x86_64.rpm libfastcommon-debuginfo-1.0.36-1.el7.centos.x86_64.rpm libfastcommon-devel-1.0.36-1.el7.centos.x86_64.rpm libfdfsclient-5.0.11-1.el7.centos.x86_64.rpm libfdfsclient-devel-5.0.11-1.el7.centos.x86_64.rpm
下面就用上述生成的rpm包进行安装。首先需要在客户端上面进行安装。因为客户端也需要用fastdfs的命令进行文件的上传,查看,修改,删除……
yum localinstall /root/rpmbuild/RPMS/x86_64/*.rpm
之后将上述的rpm包放到一个名字为fastdfs_rpm的文件夹里面,并将该文件夹打包为tar.gz格式的压缩包,然后将其分发到4台slave上面,并解压。
$ cd $ mkdir fastdfs_rpm $ cp /root/rpmbuild/RPMS/x86_64/*.rpm fastdfs_rpm/ $ tar zcvf fastdfs_rpm.tar.gz fastdfs_rpm/ $ ansible slave -m copy -a 'src=/root/fastdfs_rpm.tar.gz dest=/root/' $ ansible slave -m shell -a 'chdir=/root tar -zxvf fastdfs_rpm.tar.gz' $ ansible slave -m shell -a 'ls /root/fastdfs_rpm/' 192.7.20.61 | SUCCESS | rc=0 >> fastdfs-5.0.11-1.el7.centos.x86_64.rpm fastdfs-debuginfo-5.0.11-1.el7.centos.x86_64.rpm fastdfs-server-5.0.11-1.el7.centos.x86_64.rpm fastdfs-tool-5.0.11-1.el7.centos.x86_64.rpm libfastcommon-1.0.36-1.el7.centos.x86_64.rpm libfastcommon-debuginfo-1.0.36-1.el7.centos.x86_64.rpm libfastcommon-devel-1.0.36-1.el7.centos.x86_64.rpm libfdfsclient-5.0.11-1.el7.centos.x86_64.rpm libfdfsclient-devel-5.0.11-1.el7.centos.x86_64.rpm 192.7.20.60 | SUCCESS | rc=0 >> fastdfs-5.0.11-1.el7.centos.x86_64.rpm fastdfs-debuginfo-5.0.11-1.el7.centos.x86_64.rpm fastdfs-server-5.0.11-1.el7.centos.x86_64.rpm fastdfs-tool-5.0.11-1.el7.centos.x86_64.rpm libfastcommon-1.0.36-1.el7.centos.x86_64.rpm libfastcommon-debuginfo-1.0.36-1.el7.centos.x86_64.rpm libfastcommon-devel-1.0.36-1.el7.centos.x86_64.rpm libfdfsclient-5.0.11-1.el7.centos.x86_64.rpm libfdfsclient-devel-5.0.11-1.el7.centos.x86_64.rpm 192.7.20.63 | SUCCESS | rc=0 >> fastdfs-5.0.11-1.el7.centos.x86_64.rpm fastdfs-debuginfo-5.0.11-1.el7.centos.x86_64.rpm fastdfs-server-5.0.11-1.el7.centos.x86_64.rpm fastdfs-tool-5.0.11-1.el7.centos.x86_64.rpm libfastcommon-1.0.36-1.el7.centos.x86_64.rpm libfastcommon-debuginfo-1.0.36-1.el7.centos.x86_64.rpm libfastcommon-devel-1.0.36-1.el7.centos.x86_64.rpm libfdfsclient-5.0.11-1.el7.centos.x86_64.rpm libfdfsclient-devel-5.0.11-1.el7.centos.x86_64.rpm 192.7.20.62 | SUCCESS | rc=0 >> fastdfs-5.0.11-1.el7.centos.x86_64.rpm fastdfs-debuginfo-5.0.11-1.el7.centos.x86_64.rpm fastdfs-server-5.0.11-1.el7.centos.x86_64.rpm fastdfs-tool-5.0.11-1.el7.centos.x86_64.rpm libfastcommon-1.0.36-1.el7.centos.x86_64.rpm libfastcommon-debuginfo-1.0.36-1.el7.centos.x86_64.rpm libfastcommon-devel-1.0.36-1.el7.centos.x86_64.rpm libfdfsclient-5.0.11-1.el7.centos.x86_64.rpm libfdfsclient-devel-5.0.11-1.el7.centos.x86_64.rpm
在4台节点上面安装上述rpm文件,至此,完成fastdfs在4台slave上面的部署工作。
$ ansible slave -m shell -a 'yum localinstall /root/fastdfs_rpm/*.rpm -y'
Tracker节点的配置
下一步我们需要配置两台Tracker节点。首先需要准备tracker进程的目录。其次,需要准备tracker.conf,http.conf,mime.types这三个文件,之后便是修改配置文件并启动tracker进程。
创建目录: $ ansible ftracker -m shell -a 'mkdir -p /data/fastdfs' 准备tracker配置文件: $ ansible ftracker -m shell -a 'chdir=/etc/fdfs cp tracker.conf.sample tracker.conf' 将客户端机器的源码目录中的http.conf和mime.types拷贝到tracker的/etc/fdfs目录下面: $ ansible ftracker -m copy -a 'src=/root/fastdfs-master/conf/{http.conf,mime.types} dest=/etc/fdfs' 修改base_path选项为/data/fastdfs目录 $ ansible ftracker -m shell -a 'chdir=/etc/fdfs/ sed -i 's:base_path=.*:base_path=/data/fastdfs:g' tracker.conf' 修改http.server_port为80端口 $ ansible ftracker -m shell -a 'chdir=/etc/fdfs/ sed -i 's:http.server_port=.*:http.server_port=80:g' tracker.conf' 修改store_lookup的值为0,即对于不同的group使用round-robin方式: $ ansible ftracker -m shell -a 'chdir=/etc/fdfs sed -i 's:store_lookup=.*:store_lookup=0:g' tracker.conf' 启动tracker进程 $ ansible ftracker -m shell -a 'service fdfs_trackerd start' 查看tracker进程监听端口 $ ansible ftracker -m shell -a 'ss -tnlp | grep -i trackerd' 192.7.20.61 | SUCCESS | rc=0 >> LISTEN 0 128 *:22122 *:* users:(("fdfs_trackerd",pid=2629,fd=5)) 192.7.20.60 | SUCCESS | rc=0 >> LISTEN 0 128 *:22122 *:* users:(("fdfs_trackerd",pid=2828,fd=5))
Storage节点的配置
配置storage节点,规划如下:192.7.20.60和192.7.20.62这两台机器作为group1,192.7.20.61和192.7.20.63这两台节点作为group2。创建/data/fastdfs目录(虽然是storage节点,但是仍然需要这么一个目录),创建/data/storage目录作为存储节点的目录。准备storage.conf,http.conf,mime.types这三个文件。并对storage的配置文件进行修改,之后启动服务。
创建/data/fastdfs目录: $ansible fstorage -m shell -a 'mkdir -p /data/fastdfs' 创建/data/storage目录: $ ansible fstorage -m shell -a 'mkdir -p /data/storage' 准备storage.conf文件: $ ansible fstorage -m shell -a 'chdir=/etc/fdfs cp storage.conf.sample storage.conf' 准备http.conf文件和mime.types文件: $ ansible fstorage -m copy -a 'src=/root/fastdfs-master/conf/{http.conf,mime.types} dest=/etc/fdfs' 设定base_path为/data/fastdfs: $ ansible fstorage -m shell -a 'sed -i 's:base_path=.*:base_path=/data/fastdfs:g' /etc/fdfs/storage.conf' 设定存储目录路径为/data/storage: $ansible fstorage -m shell -a 'sed -i 's:store_path0=.*:store_path0=/data/storage:g' /etc/fdfs/storage.conf' 设定两台tracker_server,分别为192.7.20.60:22122和192.7.20.61:22122 ansible fstorage -m shell -a 'sed -i '/tracker_server=.*/a\tracker_server==/' /etc/fdfs/storage.conf' ansible fstorage -m shell -a 'sed -i '/tracker_server=$/tracker_server=192.7.20.60:22122' /etc/fdfs/storage.conf' ansible fstorage -m shell -a 'sed -i '/tracker_server==$/tracker_server=192.7.20.61:22122' /etc/fdfs/storage.conf' 定义192.7.20.61和192.7.20.63为group2组: ansible 192.7.20.61 -m shell -a 'sed -i s/group_name=group1/group_name=group2/g /etc/fdfs/storage.conf' ansible 192.7.20.63 -m shell -a 'sed -i s/group_name=group1/group_name=group2/g /etc/fdfs/storage.conf' 启动storaged进程: $ ansible fstorage -m shell -a 'service fdfs_storaged start' 查看storaged进程监听端口: ansible fstorage -m shell -a 'ss -tnlp | grep storaged' 192.7.20.60 | SUCCESS | rc=0 >> LISTEN 0 128 *:23000 *:* users:(("fdfs_storaged",pid=1009,fd=5)) 192.7.20.61 | SUCCESS | rc=0 >> LISTEN 0 128 *:23000 *:* users:(("fdfs_storaged",pid=834,fd=5)) 192.7.20.62 | SUCCESS | rc=0 >> LISTEN 0 128 *:23000 *:* users:(("fdfs_storaged",pid=975,fd=5)) 192.7.20.63 | SUCCESS | rc=0 >> LISTEN 0 128 *:23000 *:* users:(("fdfs_storaged",pid=922,fd=5))
Client的配置以及测试
使用192.7.20.121作为FastDFS的客户端。需要在客户端也建立/data/fastdfs目录,复制client.conf.sample文件为client.conf,并使用client.conf作为配置文件。在该配置文件里面,设定base_path的路径为/data/fastdfs,以及两台tracker_server的地址和端口。配置完毕之后如下所示:
$ grep base_path /etc/fdfs/client.conf base_path=/data/fastdfs $ grep tracker_server /etc/fdfs/client.conf | grep -vE "^#|^[^t]" tracker_server=192.7.20.60:22122 tracker_server=192.7.20.61:22122
将client配置完毕之后,便可以进行测试。在测试之前,先列出fastdfs的工具程序。如下所示。其中fdfs_upload_file
用于上传文件,fdfs_delete_file
用于删除文件,fdfs_trackerd
用于远程启动trackerd进程,fdfs_storaged
用于远程启动storaged进程,fdfs_monitor
用于查询storage节点的group信息。其余的选项,通过命令行帮助即可得到使用方式,在这里不一一赘述。
fdfs_appender_test fdfs_append_file fdfs_delete_file fdfs_file_info fdfs_storaged fdfs_test1 fdfs_upload_appender fdfs_appender_test1 fdfs_crc32 fdfs_download_file fdfs_monitor fdfs_test fdfs_trackerd fdfs_upload_file
进行文件的上传,由于使用了轮询storage的配置,因此在前后两次上传之后分别传送到了不同group组。通过fdfs_delete_file命令将其删除:
上传 $ fdfs_upload_file /etc/fdfs/client.conf kde.jpg group1/M00/00/00/wAcUPFl4fp6AGwNPAA6q2wjnW8s033.jpg $ fdfs_upload_file /etc/fdfs/client.conf resplendentSunset.jpg group2/M00/00/00/wAcUPVl4fsSAVEclAAUpOv3StqA293.jpg 查看各个storage节点上面的文件: ansible fstorage -m shell -a 'ls /data/storage/data/00/00' 192.7.20.60 | SUCCESS | rc=0 >> wAcUPFl4fp6AGwNPAA6q2wjnW8s033.jpg 192.7.20.62 | SUCCESS | rc=0 >> wAcUPFl4fp6AGwNPAA6q2wjnW8s033.jpg 192.7.20.63 | SUCCESS | rc=0 >> wAcUPVl4fsSAVEclAAUpOv3StqA293.jpg 192.7.20.61 | SUCCESS | rc=0 >> wAcUPVl4fsSAVEclAAUpOv3StqA293.jpg 删除 $ fdfs_delete_file /etc/fdfs/client.conf group1/M00/00/00/wAcUPFl4fp6AGwNPAA6q2wjnW8s033.jpg $ fdfs_delete_file /etc/fdfs/client.conf group2/M00/00/00/wAcUPVl4fsSAVEclAAUpOv3StqA293.jpg 查看各个storage节点上面的文件: ansible fstorage -m shell -a 'ls /data/storage/data/00/00' 192.7.20.60 | SUCCESS | rc=0 >> 192.7.20.62 | SUCCESS | rc=0 >> 192.7.20.63 | SUCCESS | rc=0 >> 192.7.20.61 | SUCCESS | rc=0 >>
Nginx + fastdfs模块配置
通过Nginx的第三方模块fastdfs-nginx-module,安装部署在storage节点上面,可以实现将FastDFS存储的文件通过http协议呈现给浏览器客户端。该模块主要解决同步延迟的问题。同组之间的服务器需要复制文件,有延迟的问题。假设Tracker服务器将文件上传到了192.168.1.80,文件ID已经返回客户端,这时,后台会将这个文件复制到192.168.1.30,如果复制没有完成,客户端就用这个ID在192.168.1.30取文件,肯定会出现错误。这个fastdfs-nginx-module可以重定向连接到源服务器取文件,避免客户端由于复制延迟的问题,出现错误。
使用--add-module
选项将上述模块包含进去,并将nginx重新编译(这里略去编译过程),并在配置文件中添加如下内容:
server { listen 8080; location /M00 { alias /data/storage/data; ngx_fastdfs_module; } }
将编译好的nginx打包,利用ansible推送到所有storage上面去。
将FastDFS源码包中的mod_fastdfs.conf文件进行修改,如下所示,也将其推送到所有storage上面去,并解压缩。
base_path=/data/fastdfs tracker_server=192.7.20.60:22122 tracker_server=192.7.20.60:22122 store_path0=/data/storage log_filename=/data/fastdfs/logs/mod_fastdfs.log
$ ansible fstorage -m copy -a 'src=/root/nginx-1.12.0 dest=/root/'
创建nginx组和nginx用户,创建一个该nginx模块的log文件,用于记录log
$ ansible fstorage -m shell -a 'groupadd -r nginx' $ ansible fstorage -m shell -a 'useradd -r -g nginx -s /sbin/nologin -m nginx' $ ansible fstorage -m shell -a 'touch /data/fastdfs/logs/mod_fastdfs.log' $ ansible fstorage -m shell -a 'chown nginx.nginx /data/fastdfs/logs/mod_fastdfs.log'
创建/opt/nginx目录,并将nginx包解压到该目录下面,并启动:
$ ansible fstorage -m shell -a 'mkdir /opt/nginx' $ ansible fstorage -m shell -a 'tar -zxf /root/nginx-1.12.0.tar.gz -C /opt/nginx' $ ansible fstorage -m shell -a 'chown -R nginx.nginx /opt/nginx' $ ansible fstorage -m shell -a '/opt/nginx/sbin/nginx'
启动完毕之后,正常情况下,便可以从任何storage节点上面,访问任意group的资源了,如下所示: