FastDFS简介
FastDFS是一款开源的轻量级分布式文件系统,使用C实现,支持Linux、BSD等unix-like操作系统。值得注意的是,fastdfs并不是通用的文件系统,只能通过专用的API访问。
fastdfs为互联网应用量身定做,解决了大容量文件存储的问题,fastdfs追求高性能和高扩展性。fastdfs的主要概念:
tracker-server:跟踪服务器。用于跟踪文件,主要起调度作用。在内存中记录了所有存储组和存储服务器的状态信息,是客户端和数据存储的主要枢纽。相比GFS更为精简,因为不记录文件索引。
storage-server: 存储服务器。用于存储文件。直接使用操作系统的文件系统来管理和组织文件。
group: 组,卷。多个服务器存在一个组中,在一个组中的服务器存储的文件是完全相同的,并且同一个组的服务器地位是对等的。对于文件的操作可以在任意一个组中的服务器上进行。
metadata: 元数据。以键值对的方式存储,用于存储文件的相关信息。
各大存储系统的对比
话说没有对比就没有伤害,fastdfs也不是万能的,需要根据业务来选择适合的存储系统。
存储系统 | 适合存储的文件类型 | 文件分布情况 | 系统性能 | 复杂度 | FUSE(用户文件系统) | POSIX() | 备份机制 | 通讯协议接口 | 社区情况 | 实现语言 |
---|
FastDFS | 4KB至500MB | 将小文件合并存储 | 很高 | 简单 | 不支持 | 不支持 | 组内冗余备份 | HTTP API | 国内用户 | C |
TFS | 所有文件 | 小文件合并以块组织分片 | - | 复杂 | 不支持 | 不支持 | 块存储多份,主辅灾备 | HTTP API | 少 | C++ |
MFS | 大于64K | 分片存储 | Master节点占用内存较高 | - | 支持 | 支持 | 多点备份,动态冗余 | 使用FUSE挂载 | 较多 | Perl |
HDFS | 大文件 | 大文件分片块存储 | - | 简单 | 支持 | 支持 | 多副本 | 原生API | 较多 | Java |
Ceph | 对象大文件 | OSD一主多从 | - | 复杂 | 支持 | 支持 | 多副本 | 原生API | 较少 | C++ |
MogileFS | 海量小图片 | - | 高 | 复杂 | 支持 | 不支持 | 动态冗余 | 原生API | 文档少 | Perl |
ClusterFS | 大文件 | - | - | 简单 | 支持 | 支持 | - | - | 多 | C |
GitHub项目主页: https://github.com/happyfish100/fastdfs
FastDFS客户端与服务器端交互原理
FastDFS+Nginx整合
架构图
安装FastDFS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | mkdir /source cd /source yum install -y gcc gcc-c++ make cmake wget libevent wget https: //github .com /happyfish100/libfastcommon/archive/V1 .0.35. tar .gz wget https: //github .com /happyfish100/fastdfs/archive/V5 .10. tar .gz tar -zxvf V1.0.35. tar .gz tar -zxvf V5.10. tar .gz cd libfastcommon-1.0.35 . /make .sh . /make .sh install ln -s /usr/lib64/libfastcommon .so /usr/local/lib/libfastcommon .so cd ../ cd fastdfs-5.10/ . /make .sh . /make .sh install cd ../ rm -rf libfastcommon-1.0.35 rm -rf fastdfs-5.10 cp /etc/fdfs/tracker .conf.sample /etc/fdfs/tracker .conf cp /etc/fdfs/storage .conf.sample /etc/fdfs/storage .conf cp /etc/fdfs/client .conf.sample /etc/fdfs/client .conf mkdir -p /data/fdfs/tracker mkdir -p /data/fdfs/storage ln -s /usr/bin/stop .sh /usr/local/bin/stop .sh ln -s /usr/bin/restart .sh /usr/local/bin/restart .sh |
修改配置文件
修改跟踪器配置文件:
1 | base_path= /data/fdfs/tracker |
修改存储器配置文件:
1 2 3 | base_path= /data/fdfs/storage store_path0= /data/fdfs/storage tracker_server=192.168.80.3:22122 |
修改客户端配置文件:
1 2 | base_path= /data/fdfs/client tracker_server=192.168.80.3:22122 |
启动
1 2 | /etc/init.d/fdfs_trackerd start /etc/init.d/fdfs_storaged start |
1 2 3 4 | netstat -tunlap | grep :22122 tcp 0 0 0.0.0.0:22122 0.0.0.0:* LISTEN 7247 /fdfs_trackerd tcp 0 0 192.168.80.3:22122 192.168.80.3:39318 ESTABLISHED 7247 /fdfs_trackerd tcp 0 0 192.168.80.3:39318 192.168.80.3:22122 ESTABLISHED 7444 /fdfs_storaged |
启动后要查看状态, 出现 active (exited)
字样可以尝试重启服务。
测试
1 2 | /usr/bin/fdfs_upload_file /etc/fdfs/client .conf /source/FastDFS_v5 .05. tar .gz group1 /M00/00/00/wKhQA1ysjSGAPjXbAAVFOL7FJU4 . tar .gz |
文件存储在:
1 | ll /data/fdfs/storage/data/00/00/wKhQA1ysjSGAPjXbAAVFOL7FJU4 . tar .gz |
安装Nginx并配置模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # 安装Nginx需要的pcre(Perl兼容正则表达式)库,允许Nginx使用rewrite模块提供URL重写功能。 yum install pcre pcre-devel perl-ExtUtils-Embed -y # 安装openssl-devel,允许Nginx提供HTTPS服务。 yum install openssl-devel -y # 下载软件包 cd /source wget http: //59 .80.44.46 /nginx .org /download/nginx-1 .14.2. tar .gz wget http: //nchc .dl.sourceforge.net /project/fastdfs/FastDFS %20Nginx%20Module%20Source%20Code /fastdfs-nginx-module_v1 .16. tar .gz # 解压软件包 tar xvf nginx-1.14.2. tar .gz tar xvf fastdfs-nginx-module_v1.16. tar .gz # 创建必要的软连接 ln -s /usr/include/fastdfs/ /usr/local/include/fastdfs ln -s /usr/include/fastcommon/ /usr/local/include/fastcommon cp FastDFS /conf/http .conf /etc/fdfs/ cp FastDFS /conf/mime .types /etc/fdfs/ cp fastdfs-nginx-module /src/mod_fastdfs .conf /etc/fdfs/ mkdir -p /data/fdfs/fastdfs-nginx-module |
修改配置文件 /etc/fdfs/mod_fastdfs.conf
:
1 2 3 4 5 6 | connect_timeout=10 base_path=/data/fdfs/fastdfs-nginx-module # 配置服务器的地址 tracker_server=192.168.80.3:22122 url_have_group_name = true store_path0=/data/fdfs/storage |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | mkdir /applications mkdir /tmp/nginx useradd nginx -s /sbin/nologin -M cd nginx-1.14.2 . /configure \ --user=nginx \ --group=nginx \ --prefix= /applications/nginx-1 .14.2 \ --with-http_ssl_module \ --with-http_gzip_static_module \ --http-client-body-temp-path= /tmp/nginx/client \ --http-proxy-temp-path= /tmp/nginx/proxy \ --http-fastcgi-temp-path= /tmp/nginx/cgi \ --with-poll_module \ --with- file -aio \ --with-http_realip_module \ --with-http_addition_module \ --with-http_random_index_module \ --with-pcre \ --with-http_stub_status_module \ --with-stream \ --add-module= /source/fastdfs-nginx-module/src make make install ln -s /applications/nginx-1 .14.2/ /applications/nginx chown -R nginx.nginx /applications/nginx chown -R nginx.nginx /applications/nginx-1 .14.2/ chown -R nginx.nginx /tmp/nginx/ |
修改配置文件 /applications/nginx/conf/nginx.conf
, 在http区块添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | server { listen 8000; server_name media; location / { root html; index index.html index.htm; } # 拦截文件请求,转发到下面的模块 location ~ /group [0-9] { ngx_fastdfs_module; } error_page 500 502 503 504 /50x .html; location = /50x .html { root html; } } |
测试配置文件正确性并启动:
1 2 | /applications/nginx/sbin/nginx -t /applications/nginx/sbin/nginx |
删除临时文件:
1 2 3 4 | rm -rf FastDFS rm -rf fastdfs-nginx-module rm -rf libfastcommon-1.0.35 rm -rf nginx-1.14.2 |
测试Nginx文件下载功能, 在浏览器输入: http://192.168.80.3:8000/group1/M00/00/00/wKhQA1ysjSGAPjXbAAVFOL7FJU4.tar.gz
一个nginx只能访问一个storage服务器的数据,所以多个storage服务器要配置多个nginx,然后将nginx按照请求路径中的组id(groupid)进行路由。
简单的启动停止服务的脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # start-service # usage: ./start-service echo "============================================Sync datetime===========================================" ntpdate time7.aliyun.com echo "===========================================Getting status===========================================" /etc/init .d /fdfs_trackerd status /etc/init .d /fdfs_storaged status echo "==========================================Starting service==========================================" /etc/init .d /fdfs_storaged start /etc/init .d /fdfs_trackerd start echo "===========================================Getting status===========================================" /etc/init .d /fdfs_trackerd status /etc/init .d /fdfs_storaged status echo "=========================================Testing config file========================================" /applications/nginx/sbin/nginx -t echo "=========================================Starting web server========================================" /applications/nginx/sbin/nginx echo "=======================================Getting network status=======================================" sleep 5s netstat -tunlap | grep :22122 netstat -tunlap | grep :8000 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # stop-service # usage: ./stop-service echo "===========================================Getting status===========================================" /etc/init .d /fdfs_trackerd status /etc/init .d /fdfs_storaged status echo "==========================================Stopping service==========================================" /etc/init .d /fdfs_storaged stop /etc/init .d /fdfs_trackerd stop echo "========================================Stopping web server=========================================" kill ` cat /applications/nginx/logs/nginx .pid` echo "===========================================Getting status===========================================" /etc/init .d /fdfs_trackerd status /etc/init .d /fdfs_storaged status echo "=======================================Getting network status=======================================" sleep 5s netstat -tunlap | grep :22122 netstat -tunlap | grep :8000 |
基于Token的防盗链实现
FastDFS内置使用Token的方式实现防盗链,Token是带有时效性的,Token中包含了文件id、时间戳ts和token。在FastDFS中使用URL带上ts和token的方式请求资源。在FastDFS中提供了生成Token的算法,扩展模块会对Token进行验证。由于Token的生成和校验都在服务器端,因此不会存在安全性问题。链接示例:
http://192.168.1.15:8080/group1/M01/01/01/wKgBD01c15nvKU1cAABAOeCdFS466570.c?token=b32cd06a53dea4376e43d71cc882f9cb&ts=1297930137
在 /etc/fdfs/http.conf
中修改:
1 2 3 4 5 6 7 8 | # 开启Token校验 http.anti_steal.check_token=true # Token的声明周期为240秒 http.anti_steal.token_ttl=240 # 加密字符串,可以使用 openssl rand -base64 64 生成 http.anti_steal.secret_key=2scPwMPctXhbLVOYB0jyuyQzytOofmFCBIYe65n56PPYVWrntxzLIDbPdvDDLJM8QHhKxSGWTcr+9VdG3yptkw # Token校验失败的时候返回的图片 http.anti_steal.token_check_fail=/data/fdfs/error.svg |
使用Java客户端验证:
将客户端安装到本地仓库:
1 2 3 | git clone https: //github .com /happyfish100/fastdfs-client-java .git cd fastdfs-client-java mvn clean install |
使用Maven创建一个普通的项目,在POM文件中添加依赖:
1 2 3 4 5 6 7 | < dependencies > < dependency > < groupId >org.csource</ groupId > < artifactId >fastdfs-client-java</ artifactId > < version >1.27-SNAPSHOT</ version > </ dependency > </ dependencies > |
在resources目录下创建FastDFS配置文件 fastdfs-client.properties
:
1 2 3 4 5 6 7 | fastdfs.connect_timeout_in_seconds = 5 fastdfs.network_timeout_in_seconds = 30 fastdfs.charset = UTF-8 fastdfs.http_anti_steal_token = true fastdfs.http_secret_key = 2scPwMPctXhbLVOYB0jyuyQzytOofmFCBIYe65n56PPYVWrntxzLIDbPdvDDLJM8QHhKxSGWTcr+9VdG3yptkw fastdfs.http_tracker_http_port = 8080 fastdfs.tracker_servers = 192.168.80.3:22122 |
创建 com.bluemiaomiao.Demo.java
类文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | package com.bluemiaomiao; import org.csource.common.MyException; import org.csource.fastdfs.ClientGlobal; import org.csource.fastdfs.ProtoCommon; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.Properties; public class Demo { public static void main(String[] args) throws IOException, MyException, NoSuchAlgorithmException { // 加载配置文件 Properties prop = new Properties(); prop.load(Demo. class .getResourceAsStream( "/fastdfs-client.properties" )); ClientGlobal.initByProperties(prop); // 显示初始化配置信息 System.out.println(ClientGlobal.configInfo()); // 使用文件上传工具返回的地址,一般情况下保存在数据库中 String remoteFileName = "group1/M00/00/00/wKhQA1ysjSGAPjXbAAVFOL7FJU4.tar.gz" ; // 获取当前时间戳 int ts = ( int )(System.currentTimeMillis()/ 1000 ); // 获取Token, 传入的文件ID不要含有分组信息 String token = ProtoCommon.getToken( "M00/00/00/wKhQA1ysjSGAPjXbAAVFOL7FJU4.tar.gz" , ts, prop.getProperty( "fastdfs.http_secret_key" )); // 使用浏览器访问返回的URL System.out.println( "http://192.168.80.3:8000/" + remoteFileName + "?token=" + token + "&ts=" + ts); } } |
如果访问时显示防盗链图片,可能是测试客户端与服务器之间的之间有一定差距,两个主机之间不能有分钟级别的差距,可以使用如下方法同步服务器:
1 2 3 4 | # 安装同步时间服务器的客户端, Windows系统也需要与该服务器同步 # 控制面板->时钟和区域->设置日期和时间->Internet时间->更改设置 yum install ntpdate ntpdate time7.aliyun.com |
整合FastDHT实现数据去重
FastDHT是分布式哈希系统(DHT),使用BerkeleyDB做数据存储,使用libevent做网络IO处理。依赖于libfastcommon组件。
下载
去Oracle官方网站下载 Berkeley DB 数据库,去Fastdfs的GitHub主页下载FastDHT的源码包。由于之前已经安装过linevent和libfastcommon,因此只需要安装数据库和FastDHT即可。
安装配置数据库与FastDHT
1 2 3 4 5 6 7 8 | tar -xvf db-6.2.23. tar .gz cd db-6.2.23 /build_unix/ .. /dist/configure --prefix= /applications/db-6 .2.23 cd ../../ rm -rf db-6.2.23 unzip fastdht-master.zip cd fastdht-master vim make .sh |
修改第27行代码:
1 | CFLAGS='-Wall -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I /applications/db-6.2.23/include/ -L /applications/db-6.2.23/lib/' |
-I
: 指定数据库提供的头文件目录
-L
: 指定数据库提供的库文件目录
1 2 3 4 | . /make .sh . /make .sh install cd ../ rm -rf fastdht-master |
配置
修改 /etc/fdht/fdht_client.conf
内容:
1 2 | base_path=/data/fdht #include /etc/fdht/fdht_servers.conf |
修改 /etc/fdht/fdht_servers.conf
内容:
1 | group0 = 192.168.80.3:11411 |
修改 /etc/fdht/fdhtd.conf
内容:
1 2 | base_path= /data/fdht #include /etc/fdht/fdht_servers.conf |
修改 /etc/fdfs/storage.conf
内容:
1 2 3 4 | check_file_duplicate=1 key_namespace=FastDFS keep_alive=1 #include /etc/fdht/fdht_servers.conf |
主要需要包含服务器端配置文件。
1 2 | ln -s /applications/db-6 .2.23 /lib/libdb-6 .2.so /usr/lib/libdb-6 .2.so ln -s /applications/db-6 .2.23 /lib/libdb-6 .2.so /usr/lib64/libdb-6 .2.so |
启动并测试
1 | fdhtd /etc/fdht/fdhtd .conf |
重启使用:
1 | fdhtd /etc/fdht/fdhtd .conf restart |
查看结果:
1 2 | netstat -tunlap | grep :11411 tcp 0 0 0.0.0.0:11411 0.0.0.0:* LISTEN 20605 /fdhtd |
由于安装FastDHT的时候关闭了FastDFS,因此需要启动FastDFS
修改之前的 start-service
脚本, 在启动tracker和storage服务之前添加:
1 | fdhtd /etc/fdht/fdhtd .conf |
在查看tracker和ngixn网络状态之前添加:
1 | netstat -tunlap | grep :11411 |
测试:
1 2 3 4 5 6 7 8 9 | fdfs_upload_file /etc/fdfs/client .conf /source/db-6 .2.23. tar .gz group1 /M00/00/00/wKhQA1yu2L6APTk-AqQOLABfhaQ . tar .gz fdfs_upload_file /etc/fdfs/client .conf /source/db-6 .2.23. tar .gz group1 /M00/00/00/wKhQA1yu2MKAOmIiAqQOLHUWXfw . tar .gz ll /data/fdfs/storage/data/00/00/ total 45268 -rw-r--r-- 1 root root 44305964 Apr 11 14:03 wKhQA1yu2L6AM0aiAqQOLKFBFuc. tar .gz lrwxrwxrwx 1 root root 64 Apr 11 14:03 wKhQA1yu2L6APTk-AqQOLABfhaQ. tar .gz -> /data/fdfs/storage/data/00/00/wKhQA1yu2L6AM0aiAqQOLKFBFuc . tar .gz lrwxrwxrwx 1 root root 64 Apr 11 14:03 wKhQA1yu2MKAOmIiAqQOLHUWXfw. tar .gz -> /data/fdfs/storage/data/00/00/wKhQA1yu2L6AM0aiAqQOLKFBFuc . tar .gz |
自定义 fastdfs-spring-boot-starter
为了快速构建SpringBoot项目,我们可以自定义一个场景启动器来解决。详细信息: https://github.com/bluemiaomiao/fastdfs-spring-boot-starter .
下面使用SpringBoot构建一个示例项目:
添加依赖:
1 2 3 4 5 | < dependency > < groupId >com.bluemiaomiao</ groupId > < artifactId >fastdfs-spring-boot-starter</ artifactId > < version >1.0-SNAPSHOT</ version > </ dependency > |
在主配置类中添加注解:
1 2 3 4 5 6 7 8 9 10 11 | @EnableFastdfsClient @SpringBootApplication public class DemoApplication { @Autowired private FastdfsClientService fastdfsClientService; public static void main(String[] args) { SpringApplication.run(DemoApplication. class , args); } } |
此时将会自动初始化好全局客户端。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。