首页 > 代码库 > FastDFS学习笔记
FastDFS学习笔记
fastdfs作者及软件的下载方式:https://github.com/happyfish100
FastDFS基础
fastdfs是一个开源的,高性能的的分布式文件系统,他主要的功能包括:文件存储,同步和访问,设计基于高可用和负载均衡,fastfd非常适用于基于文件服务的站点,例如图片分享和视频分享网站
fastfds有两个角色:跟踪服务和存储服务
跟踪服务控制:主要做调度工作,在访问上起负载均衡的作用。
存储服务包括:文件存储,文件同步,提供文件访问接口,同时以key value的方式管理文件的元数据
跟踪器和存储节点都可以由一台多台服务器构成。跟踪器和存储节点中的服务器均可以随时增加或下线而不会影响线上服务。其中跟踪器中的所有服务器都是对等的,可以根据服务器的压力情况随时增加或减少。
为了支持大容量,存储节点(服务器)采用了分卷(或分组)的组织方式。存储系统由一个或多个卷组成,卷与卷之间的文件是相互独立的,所有卷的文件容量累加就是整个存储系统中的文件容量。一个卷可以由一台或多台存储服务器组成,一个卷下的存储服务器中的文件都是相同的,卷中的多台存储服务器起到了冗余备份和负载均衡的作用。
在卷中增加服务器时,同步已有的文件由系统自动完成,同步完成后,系统自动将新增服务器切换到线上提供服务。
当存储空间不足或即将耗尽时,可以动态添加卷。只需要增加一台或多台服务器,并将它们配置为一个新的卷,这样就扩大了存储系统的容量。
轻量级
FastDFS只有两个角色:Tracker server和Storage server。
Tracker server作为中心结点,其主要作用是负载均衡和调度。
Tracker server在内存中记录分组和Storage server的状态等信息,不记录文件索引信息,占用的内存量很少。另外,客户端(应用)和Storage server访问Tracker server时,Tracker server扫描内存中的分组和Storage server信息,然后给出应答。由此可以看出Tracker server非常轻量化,不会成为系统瓶颈。
FastDFS中的Storage server在其他文件系统中通常称作Trunk server或Data server。Storage server直接利用OS的文件系统存储文件。FastDFS不会对文件进行分块存储,客户端上传的文件和Storage server上的文件一一对应。
众所周知,大多数网站都需要存储用户上传的文件,如图片、视频、电子文档等。出于降低带宽和存储成本的考虑,网站通常都会限制用户上传的文件大小,例如图片文件不能超过5MB、视频文件不能超过100MB等。我认为,对于互联网应用,文件分块存储没有多大的必要。它既没有带来多大的好处,又增加了系统的复杂性。FastDFS不对文件进行分块存储,与支持文件分块存储的DFS相比,更加简洁高效,并且完全能满足绝大多数互联网应用的实际需要。
在FastDFS中,客户端上传文件时,文件ID不是由客户端指定,而是由Storage server生成后返回给客户端的。文件ID中包含了组名、文件相对路径和文件名,Storage server可以根据文件ID直接定位到文件。因此FastDFS集群中根本不需要存储文件索引信息,这是FastDFS比较轻量级的一个例证。而其他文件系统则需要存储文件索引信息,这样的角色通常称作NameServer。其中mogileFS采用MySQL数据库来存储文件索引以及系统相关的信息,其局限性显而易见,MySQL将成为整个系统的瓶颈。
FastDFS轻量级的另外一个体现是代码量较小。最新的V2.0包括了C客户端API、FastDHT客户端API和PHP extension等,代码行数不到5.2万行。
分组方式
类Google FS都支持文件冗余备份,例如Google FS、TFS的备份数是3。一个文件存储到哪几个存储结点,通常采用动态分配的方式。采用这种方式,一个文件存储到的结点是不确定的。举例说明,文件备份数是3,集群中有A、B、C、D四个存储结点。文件1可能存储在A、B、C三个结点,文件2可能存储在B、C、D三个结点,文件3可能存储在A、B、D三个结点。
FastDFS采用了分组存储方式。集群由一个或多个组构成,集群存储总容量为集群中所有组的存储容量之和。一个组由一台或多台存储服务器组成,同组内的多台Storage server之间是互备关系,同组存储服务器上的文件是完全一致的。文件上传、下载、删除等操作可以在组内任意一台Storage server上进行。类似木桶短板效应,一个组的存储容量为该组内存储服务器容量最小的那个,由此可见组内存储服务器的软硬件配置最好是一致的。【一组storage的文件是一致的,客户端可以从组内的任一服务器下载文件】
采用分组存储方式的好处是灵活、可控性较强。比如上传文件时,可以由客户端直接指定上传到的组。一个分组的存储服务器访问压力较大时,可以在该组增加存储服务器来扩充服务能力(纵向扩容)。当系统容量不足时,可以增加组来扩充存储容量(横向扩容)。采用这样的分组存储方式,可以使用FastDFS对文件进行管理,使用主流的Web server如Apache、nginx等进行文件下载。
对等结构
FastDFS集群中的Tracker server也可以有多台,Tracker server和Storage server均不存在单点问题。Tracker server之间是对等关系,组内的Storage server之间也是对等关系。传统的Master-Slave结构中的Master是单点,写操作仅针对Master。如果Master失效,需要将Slave提升为Master,实现逻辑会比较复杂。和Master-Slave结构相比,对等结构中所有结点的地位是相同的,每个结点都是Master,不存在单点问题。
从图上可以看出,Tracker server之间相互独立,不存在直接联系。
客户端和Storage server主动连接Tracker server。Storage server主动向Tracker server报告其状态信息,包括磁盘剩余空间、文件同步状况、文件上传下载次数等统计信息。Storage server会连接集群中所有的Tracker server,向他们报告自己的状态。Storage server启动一个单独的线程来完成对一台Tracker server的连接和定时报告。需要说明的是,一个组包含的Storage server不是通过配置文件设定的,而是通过Tracker server获取到的。
不同组的Storage server之间不会相互通信,同组内的Storage server之间会相互连接进行文件同步。
Storage server采用binlog文件记录文件上传、删除等更新操作。binlog中只记录文件名,不记录文件内容。
文件同步只在同组内的Storage server之间进行,采用push方式,即源头服务器同步给目标服务器。只有源头数据才需要同步,备份数据并不需要再次同步,否则就构成环路了。有个例外,就是新增加一台Storage server时,由已有的一台Storage server将已有的所有数据(包括源头数据和备份数据)同步给该新增服务器。
Storage server中由专门的线程根据binlog进行文件同步。为了最大程度地避免相互影响以及出于系统简洁性考虑,Storage server对组内除自己以外的每台服务器都会启动一个线程来进行文件同步。
文件同步采用增量同步方式,系统记录已同步的位置(binlog文件偏移量)到标识文件中。标识文件名格式:{dest storage IP}_{port}.mark,例如:192.168.1.14_23000.mark。
上传文件交互过程:
下载文件交互过程:
1. client询问tracker下载文件的storage,参数为文件标识(卷名和文件名)
2. tracker返回一台可用的storage
3. client直接和storage通讯完成文件下载
需要说明的是,client为使用FastDFS服务的调用方,client也应该是一台服务器,它对tracker和storage的调用均为服务器间的调用。
文件同步延迟问题的提出
客户端将一个文件上传到一台Storage server后,文件上传工作就结束了。由该Storage server根据binlog中的上传记录将这个文件同步到同组的其他Storage server。这样的文件同步方式是异步方式,异步方式带来了文件同步延迟的问题。新上传文件后,在尚未被同步过去的Storage server上访问该文件,会出现找不到文件的现象。FastDFS是如何解决文件同步延迟这个问题的呢?
文件的访问分为两种情况:文件更新和文件下载。文件更新包括设置文件附加属性和删除文件。文件的附加属性包括文件大小、图片宽度、图片高度等。FastDFS中,文件更新操作都会优先选择源Storage server,也就是该文件被上传到的那台Storage server。这样的做法不仅避免了文件同步延迟的问题,而且有效地避免了在多台Storage server上更新同一文件可能引起的时序错乱的问题。
那么文件下载是如何解决文件同步延迟这个问题的呢?
要回答这个问题,需要先了解文件名中包含了什么样的信息。Storage server生成的文件名中,包含了源Storage server的IP地址和文件创建时间等字段。文件创建时间为UNIX时间戳,后面称为文件时间戳。从文件名或文件ID中,可以反解出这两个字段。
然后我们再来看一下,Tracker server是如何准确地知道一个文件已被同步到一台Storage server上的。前面已经讲过,文件同步采用主动推送的方式。另外,每台storage server都会定时向tracker server报告它向同组的其他storage server同步到的文件时间戳。当tracker server收到一台storage server的文件同步报告后,它会依次找出该组内各个storage server(后称作为S)被同步到的文件时间戳最小值,作为S的一个属性记录到内存中。
FastDFS对文件同步延迟问题的解决方案
一个最简单的解决办法,和文件更新一样,优先选择源Storage server下载文件即可。这可以在Tracker server的配置文件中设置,对应的参数名为download_server。
另外一种选择Storage server的方法是轮流选择(round-robin)。当Client询问Tracker server有哪些Storage server可以下载指定文件时,Tracker server返回满足如下四个条件之一的Storage server:
1. 该文件上传到的源Storage server,文件直接上传到该服务器上的;
2. 文件创建时间戳 < Storage server被同步到的文件时间戳,这意味着当前文件已经被同步过来了;
3. 文件创建时间戳=Storage server被同步到的文件时间戳,且(当前时间—文件创建时间戳) > 一个文件同步完成需要的最大时间(如5分钟);
4. (当前时间—文件创建时间戳) > 文件同步延迟阈值,比如我们把阈值设置为1天,表示文件同步在一天内肯定可以完成。
FastDFS的简单实验配置
tracker: node1 192.168.2.11
tracker: node2 192.168.2.12
storage: node1 192.168.2.11
storage: node2 192.168.2.12
安装必要的软件包
fastdfs下载地址:https://github.com/happyfish100/fastdfs (版本号 5.0.8)
下面的步骤在tracker和storage差不多。就/etc/fdfs下的启用的文件不一样。
安装libfastcommon
# git clonehttps://github.com/happyfish100/libfastcommon.git
# cd libfastcommon/
#./make.sh
#./make.sh install
编译安装FastDFS
下载地址:https://github.com/happyfish100/fastdfs/releases
# unzip fastdfs-master.zip
# cd fastfds-master
# vim make.sh 修改地方如下:
# ./make.sh
# ./make.sh install
安装完成后,会在/etc/fdfs目录下生成3个文件
此外,我们还要把conf目录下的http.conf、mime.types、storage_ids.conf 复制到/etc/fdfs目录下。
install安装的同时还会在/etc/init.d目录下生成2个脚本文件
注意下,这2个启动脚本里面的程序的路径和我们安装的路径不一致,下面我们会做一个软链接即可解决。
添加环境变量及创建软链接
# ln -s /usr/local/FastDFS/bin/fdfs_trackerd/usr/bin/fdfs_trackerd
# ln -s /usr/local/FastDFS/bin/fdfs_storaged/usr/bin/fdfs_storaged
# echo ‘exportPATH=$PATH:/usr/local/FastDFS/bin‘ > /etc/profile.d/fdfs.sh
# source /etc/profile.d/fdfs.sh
【tracker节点的配置方法】
# cd /etc/fdfs/
# egrep -v ‘^#|^$‘ tracker.conf.sample > tracker.conf
# vim tracker.conf 主要注意的内容如下:
disabled=false #启用配置文件【】
port=22122 #设置tracker的端口号
base_path=/data/fastdfs/tracker # 设置tracker的数据文件和日志目录(需预先创建)
store_lookup=2 # 以负载均衡方式存文件(优先存放在最大空闲的group里)
store_group=group1
http.server_port=18080
其他未列出的就是保持默认的参数,配置文件里具体‘’都有很详细的说明
【2台storage节点的配置方法】
# cd /etc/fdfs/
# egrep -v ‘^#|^$‘ storage.conf.sample >storage.conf
# vim storage.conf 内容如下:
port=23000
base_path=/data/fastdfs/storage
#store_path0=/data/fastdfs/storage 可以直接注释掉这行,这样默认就使用base_path的路径。如果有多块硬盘,也可以使用store_pathX这种写法
store_group=group1
tracker_server=192.168.2.11:22122 # 如果有多个tracker_server,则每行写一个
tracker_server=192.168.2.11:22122 # 如果有多个tracker_server,则每行写一个
http.server_port=8888
【client节点的配置方法】
# egrep -v ‘^$|^#‘ client.conf.conf.sample >client.conf
# vim client.conf.conf 内容如下:
base_path=/data/fastdfs/client
tracker_server=192.168.2.11:22122
tracker_server=192.168.2.11:22122 # 如果有多个tracker_server,则每行写一个
创建上面提到的几个目录
# mkdir -pv/data/fastdfs/{tracker,storage,client}
启动trakcer、storaged
# /etc/rc.d/init.d/fdfs_trackerdstart
# /etc/rc.d/init.d/fdfs_storagedstart
ps -ef|grep fdfs可以看到fastdfs进程已经启动了
trakcer、storaged节点上配置开机自启动
# chkconfig fdfs_trackerd on
# chkconfig fdfs_storaged on
上传文件测试
# fdfs_upload_file/etc/fdfs/client.conf /etc/passwd
此时,我们如果使用find命令查找这个文件的话,可以看到图片上传到/data/fastdfs/storage/data/00/00目录下面的。
下载刚才上传的那个文件
用法:Usage: fdfs_download_file <config_file><file_id> [local_filename] [<download_offset><download_bytes>]
例如:fdfs_download_file /etc/fdfs/client.confgroup1/M00/00/00/wKgCC1hQBa2AO4kXAAAM0bnQXLc8822806
查看文件的info
可以看到很详细的信息。
删除文件
# fdfs_delete_file/etc/fdfs/client.conf group1/M00/00/00/wKgCC1hQBa2AO4kXAAAM0bnQXLc8822806
追加上传的方法:
echo abc > f1.txt
echo def > f2.txt
fdfs_upload_appender/etc/fdfs/client.conf f1.txt
fdfs_download_file/etc/fdfs/client.conf group1/M00/00/00/wKgCDFhQDwuET0QeAAAAAEd3frE087.txt 可以验证下内容和f1.txt一致
fdfs_append_file/etc/fdfs/client.conf group1/M00/00/00/wKgCDFhQDwuET0QeAAAAAEd3frE087.txtf2.txt 追加上传
fdfs_download_file/etc/fdfs/client.conf group1/M00/00/00/wKgCDFhQDwuET0QeAAAAAEd3frE087.txt 可以下载验证下内容和f1.txt一致
列出详细信息
fdfs_monitor /etc/fdfs/client.conf
会列出当前的全部group、tracker等信息。
删除某个storagegroup
先停止需要删除的那个group节点(以192.168.2.11为例)的storaged进程/etc/init.d/fdfs_storaged stop
然后执行fdfs_monitor /etc/fdfs/client.conf delete group1 192.168.2.11 即可删除
使用php_client来进行测试(这在官方的github有详细的安装配置方法):
在github下载的压缩包里面,自带了php_client的测试程序。
tar xf fastdfs-5.08.tar.gz
cd /root/fastdfs-5.08/php_client
./configure--with-php-config=/usr/local/php/bin/php-config #我这里演示的是编译安装的php5.4
make && make install
cat fastdfs_client.ini >> /usr/local/php/etc/php.ini 直接将内容追加到php.ini尾部即可
/usr/local/php/bin/php /root/fastdfs-5.08/php_client/fastdfs_test.php 即可执行官方自带的测试脚本
类似下图:
对于java的程序,官方也给出了实例文件。
下载地址 https://github.com/happyfish100/fastdfs-client-java
下面我直接在/root目录下演示的。
git clonehttps://github.com/happyfish100/fastdfs-client-java.git
cd /root/fastdfs-client-java/src
/usr/local/ant/bin/ant # 执行ant命令即可(需要事先安装ant工具)
这样就在build/目录下生成了fastdfs_client.jar文件及一个classess文件夹。
java -cp /root/fastdfs-client-java/src/build/fastdfs_client.jar 就可以显示java里面对fastdfs的具体的用法了。
具体用法:https://github.com/happyfish100/fastdfs-client-java/tree/master/src
尝试java调用fastdfs上传文件
cd /root/fastdfs-client-java/src
java -cp fastdfs_client.jarorg.csource.fastdfs.test.TestClient /etc/fdfs/client.conf /etc/shadow
我们可到/data/fastdfs/storage/data/00/00目录下,可以发现wKgCDFhQK-uANJG7AAAJG3YcMRs0452086这个文件和/etc/shadow内容一样的。
监控fastdfs的状态:
java -cp fastdfs_client.jarorg.csource.fastdfs.test.Monitor /etc/fdfs/client.conf
在tracker1上安装配置nginx[重点掌握]:
以node1 tracker为例演示。
fastdfs的nginx模块:https://github.com/happyfish100/fastdfs-nginx-module
cd /root
git clone https://github.com/happyfish100/fastdfs-nginx-module.git
另外需要解压缩一个pcre的包,下面nginx编译会用到,我这的路径是/root/pcre-8.36
找一个nginx-1.11.5的源码包,解压后执行:
# ./configure --user=www--group=www \
--prefix=/usr/local/nginx--with-http_stub_status_module \
--with-http_ssl_module--with-http_gzip_static_module \
--with-http_sub_module--with-google_perftools_module \
--with-pcre=/root/pcre-8.36\
--add-module=/root/fastdfs-nginx-module/src
# make && make install
# cp /root/fastdfs-nginx-module/src/mod_fastdfs.conf/etc/fdfs/
# cd /root/fastdfs-5.08/conf/
# cp anti-steal.jpg http.confmime.types /etc/fdfs/
# touch /var/log/mod_fastdfs.log
# chown www.www /var/log/mod_fastdfs.log
# vim /etc/fdfs/mod_fastdfs.conf 设置下tracker的信息
tracker_server=192.168.2.11:22122
tracker_server=192.168.2.12:22122
url_have_group_name=true
store_path0=/data/fastdfs/storage # 注意这里的路径要和/etc/fdfs/storage.conf里面配置的一致
log_filename=/var/log/mod_fastdfs.log
response_mode=proxy
然后,修改nginx的配置文件
# cd /usr/local/nginx/conf/
# vim nginx.conf 修改如下:
# 官方操作方法参考https://github.com/happyfish100/fastdfs-nginx-module/blob/master/INSTALL
server
{
listen 80;
server_name 192.168.2.11;
index index.html index.htm index.php;
root /home/wwwroot/default;
location /group1/M00 {
root /data/fastdfs/storage/data;
ngx_fastdfs_module;
}
# 注意,如果还要加其他的location同学请注意,我之前的某些其他location导致图片无法加载的。
}
启动nginx测试
# nginx -t
# /etc/init.d/nginx start
# 上传文件测试
fdfs_upload_file /etc/fdfs/client.conf /etc/inittab
此处我得到的路径为:group1/M00/00/00/wKgCC1hRbyWAVZw0AAADdDn5EZ87807780
然后,直接通过浏览器访问即可下载到这个文件。
fastdfs对图片的支持
上传图片后,在浏览里输入地址即可访问,如下图:
FastDFS学习笔记