为什么要有分布式文件系统
单机时代
优点:文件访问比较便利,项目直接引用,实现起来简单,无需任何复杂技术,保存文件和访问文件都很方便。
缺点:一方面,文件和代码耦合在一起,文件越多存放越混乱。另一方面,如果流量比较大,静态文件访问会占据一定的资源,影响正常业务进行,不利于网站快速发展。
独立文件服务器
优点:Web/App服务器可以更专注发挥动态处理的能力。独立存储,更方便做扩容、容灾和数据迁移;方便做图片等资源请求的负载均衡,方便应用各种缓存策略(HTTP Header、Proxy Cache等),也更加方便迁移到CDN。
缺点:单机存在性能瓶颈,容灾、垂直扩展性稍差
分布式文件系统
优点:扩展能力: 毫无疑问,扩展能力是一个分布式文件系统最重要的特点;高可用性: 在分布式文件系统中,高可用性包含两层,一是整个文件系统的可用性,二是数据的完整和一致性;弹性存储: 可以根据业务需要灵活地增加或缩减数据存储以及增删存储池中的资源,而不需要中断系统运行。
缺点:系统复杂度稍高,需要更多服务器。
分布式存储解决方案对比
| 指标 | 适合类型 | 文件分布 | 复杂度 | FUSE | POSIX | 备份机制 | 通讯协议接口 | 社区支持 | 开发语言 |
|---|---|---|---|---|---|---|---|---|---|
| FastDFS | 4KB~500MB | 小文件合并存储不分片处理 | 简单 | 不支持 | 不支持 | 组内冗余备份 | Api http | 国内用户群 | C |
| TFS | 所有文件 | 小文件合并,以block组织分片 | 复杂 | 不支持 | 不支持 | Block存储多份,主辅灾备 | Api http | 少 | C++ |
| MFS | 大于64K | 分片存储 | 复杂 | 支持 | 支持 | 多点备份动态冗余 | 使用fuse | 较多 | Perl |
| HDFS | 大文件 | 大文件分片分块存储 | 简单 | 支持 | 支持 | 多副本 | 原生api | 较多 | Java |
| Ceph | 对象文件块 | OSD一主多从 | 复杂 | 支持 | 支持 | 多副本 | 原生api | 较少 | C++ |
| MogileFS | 海量小图片 | 不分片存储 | 复杂 | 可以支持 | 不支持 | 动态冗余 | http原生api | 文档少 | Perl |
什么是FastDFS
FastDFS是用C语言编写的一款开源的轻量级分布式文件系统。它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
FastDFS特性
- 分组存储,灵活简洁、对等结构,不存在单点
- 文件不分块存储,上传的文件和OS文件系统中的文件一一对应
- 文件ID由FastDFS生成,作为文件访问凭证,FastDFS不需要传统的name server
- 和流行的web server无缝衔接,FastDFS已提供apache和nginx扩展模块
- 中、小文件均可以很好支持,支持海量小文件存储
- 支持多块磁盘,支持单盘数据恢复
- 支持相同内容的文件只保存一份,节约磁盘空间
- 支持在线扩容 支持主从文件
- 存储服务器上可以保存文件属性(meta-data)V2.0网络通信采用libevent,支持大并发访问,整体性能更好
- 下载文件支持多线程方式,支持断点续传
FastDFS的构成

FastDFS由客户端(Client)、 跟踪服务器(Tracker Server)和存储服务器(Storage Server)构成。
客户端(client)
客户端(client),作为业务请求的发起方,通过专有接口,使用TCP/IP协议与跟踪器服务器或存储节点进行数据交互。
跟踪器(tracker)
Trackerserver作用是负载均衡和调度,通过Tracker server在文件上传时可以根据一些策略找到Storage server提供文件上传服务。可以将tracker称为追踪服务器或调度服务器。
跟踪器在访问上起负载均衡的作用。可以随时增加或下线而不会影响线上服务。
存储节点(storage)
Storageserver作用是文件存储,客户端上传的文件最终存储在Storage服务器上,Storage server没有实现自己的文件系统而是利用操作系统的文件系统来管理文件。可以将storage称为存储服务器。
存储节点中的服务器均可以随时增加或下线而不会影响线上服务。
Linux下FastDFS 安装
- 安装编译环境
yum install git gcc gcc-c++ make automake vim wget libevent -y
- 安装libfastcommon 基础库
mkdir /root/fastdfs
cd /root/fastdfs
git clone https://github.com/happyfish100/libfastcommon.git --depth 1
cd libfastcommon/
./make.sh && ./make.sh install
- 安装FastDFS
cd /root/fastdfs
wget https://github.com/happyfish100/fastdfs/archive/V5.11.tar.gz
tar -zxvf V5.11.tar.gz
cd fastdfs-5.11
./make.sh && ./make.sh install
配置文件准备
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
cp /root/fastdfs/fastdfs-5.11/conf/http.conf /etc/fdfs
cp /root/fastdfs/fastdfs-5.11/conf/mime.types /etc/fdfs
修改tracker.conf配置文件
vim /etc/fdfs/tracker.conf
需要修改的内容如下
port=22122
base_path=/home/fastdfs
修改storage.conf配置文件
vim /etc/fdfs/storage.conf
需要修改的内容如下
port=23000
# 数据和日志文件存储根目录
base_path=/home/fastdfs
# 第一个存储目录,可以有多个
store_path0=/home/fastdfs
tracker_server=192.168.211.136:22122
# http访问文件的端口(默认8888,看情况修改,和nginx中保持一致)
http.server_port=8888
- 启动
mkdir /home/fastdfs -p
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart
为了检查是否启动,查看所有运行的端口
netstat -ntlp
- 测试上传
修改client.conf配置文件
vim /etc/fdfs/client.conf
需要修改的内容如下
base_path=/home/fastdfs
#tracker服务器IP和端口
tracker_server=192.168.211.136:22122
#保存后测试,返回ID表示成功 如:group1/M00/00/00/xxx.png
/usr/bin/fdfs_upload_file /etc/fdfs/client.conf /root/fastdfs/1.png
- 安装fastdfs-nginx-module

cd /root/fastdfs
wget https://github.com/happyfish100/fastdfs-nginx-module/archive/V1.20.tar.gz
tar -xvf V1.20.tar.gz
修改配置文件
cd fastdfs-nginx-module-1.20/src
vim config
需要修改的内容如下
修改第5 行 和 15 行 修改成
ngx_module_incs="/usr/include/fastdfs /usr/include/fastcommon/"
CORE_INCS="$CORE_INCS /usr/include/fastdfs /usr/include/fastcommon/"
复制配置文件
cp mod_fastdfs.conf /etc/fdfs/
修改mod_fastdfs.conf配置文件
vim /etc/fdfs/mod_fastdfs.conf
需要修改的内容如下
tracker_server=192.168.211.136:22122
url_have_group_name=true
store_path0=/home/fastdfs
创建文件夹
mkdir -p /var/temp/nginx/client
- 安装nginx
cd /root/fastdfs
wget http://nginx.org/download/nginx-1.15.6.tar.gz
tar -zxvf nginx-1.15.6.tar.gz
cd nginx-1.15.6/
yum -y install pcre-devel openssl openssl-devel
# 添加fastdfs-nginx-module模块
./configure --add-module=/root/fastdfs/fastdfs-nginx-module-1.20/src
# 编译安装
make && make install
# 查看模块是否安装上
/usr/local/nginx/sbin/nginx -V
修改nginx配置文件
vim /usr/local/nginx/conf/nginx.conf
添加如下配置
server {
listen 8888;
server_name localhost;
location ~/group[0-9]/ {
ngx_fastdfs_module;
}
}
启动nginx
/usr/local/nginx/sbin/nginx
- 测试下载
# 关闭防火墙或打开通信端口
systemctl stop firewalld
http://192.168.211.136:8888/group1/M00/00/00/xxx.png
java访问FastDFS
可以参考官方案例 https://github.com/happyfish100/fastdfs-client-java
- 建立maven 工程 引入jar包
<!--fastdfs的java客户端-->
<dependency>
<groupId>cn.bestwu</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27</version>
</dependency>
- 引入配置文件fastdfs-client.properties
fastdfs.connect_timeout_in_seconds = 5
fastdfs.network_timeout_in_seconds = 30
fastdfs.charset = UTF-8
fastdfs.tracker_servers = 192.168.211.136:22122
- 编写测试类
@Test
public void testUpload() {
try {
//加载配置文件
ClientGlobal.initByProperties("fastdfs-client.properties");
//创建tracker客户端
TrackerClient tc = new TrackerClient();
//根据tracker客户端创建连接 获取到跟踪服务器对象
TrackerServer ts = tc.getConnection();
StorageServer ss = null;
//定义storage客户端
StorageClient1 client = new StorageClient1(ts, ss);
//文件元信息
NameValuePair[] list = new NameValuePair[1];
list[0] = new NameValuePair("fileName", "1.png");
//上传,返回fileId
String fileId = client.upload_file1("****.png", "png", list);
System.out.println(fileId);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testQuery() {
try {
//加载配置文件
ClientGlobal.initByProperties("fastdfs-client.properties");
// 创建tracker客户端
TrackerClient tc = new TrackerClient();
// 根据tracker客户端创建连接 获取到跟踪服务器对象
TrackerServer ts = tc.getConnection();
StorageServer ss = null;
//定义storage客户端
StorageClient1 client = new StorageClient1(ts, ss);
// 查询文件信息
FileInfo fileInfo = client.query_file_info1("group1/M00/00/00/****.png");
System.out.println(fileInfo);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testDownload() {
try {
//加载配置文件
ClientGlobal.initByProperties("config/fastdfs-client.properties");
// 创建tracker客户端
TrackerClient tc = new TrackerClient();
// 根据tracker客户端创建连接
TrackerServer ts = tc.getConnection();
StorageServer ss = null;
// 定义storage客户端
StorageClient1 client = new StorageClient1(ts, ss);
// 下载
byte[] bs = client.download_file1("group1/M00/00/00/****.png");
FileOutputStream fos = new FileOutputStream(new File("xxxx.png"));
fos.write(bs);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}