FastDFS 集群部署(已验证)及开发示例

1 FastDFS 简介

FastDFS 是一个高性能的分布式文件系统(DFS),具有以下主要功能:文件存储、文件同步、文件访问(文件上传和下载)。它解决了大容量存储和负载均衡的问题,特别适合以中小文件(建议范围:4KB < file_size < 500MB)为载体的在线服务,如相册网站、短视频网站等。

1.1 主流分布式文件系统对比

名称特性
HDFS (Hadoop Distributed File System)* 大数据领域龙头
* 高容错的系统,适合部署到廉价的机器上
* 能提供高吞吐量的数据访问,非常适合大规模数据应用
* 采用主从架构,一个 HDFS 由一个 name 节点和 N 个 data 节点组成
* name 节点储存元数据,一个文件分割成 N 份存储在不同的 data 节点上
GFS (Google File System)可扩展的分布式文件系统,用于大型的,分布式的,对大量数据进行访问的应用。
* 运行于廉价的普通硬件上,可以提供容错功能
* 它可以给大量的用户提供总体性能较高的服务
* GFS 采用主从架构,一个 GFS 集群由一个 master 和大量的 chunkserver(分块服务器)组成
* 一个文件被分割若干块,分散储存到多个分块 server 中
FastDFS由淘宝资深架构师余庆编写并开源,专为互联网量身打造。它在设计时充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用性、高性能等核心指标。使用 FastDFS,可以轻松搭建一套高性能的文件服务器集群,提供文件上传、下载等服务。

对比:

  • DFS 和 GFS 等是通用的分布式文件系统,适用于存储大型文件。这些系统的优点在于开发体验良好,然而系统的复杂度较高,性能一般。
  • FastDFS 是一款专门为互联网应用设计的分布式文件系统,虽然开发体验可能不太友好,但它的复杂度较低,性能也相对较高。尤其适合存储和处理图片、小视频等小文件。这是因为 FastDFS 不对文件进行分割,因此避免了文件合并时的开销。

2 FastDFS 系统架构

FastDFS 的系统架构如下图所示:

FastDFS 系统架构

FastDFS 服务端有两个角色:跟踪器 (tracker)存储节点 (storage)

  • 跟踪器 (Tracker)
    • 主要负责调度工作,在访问中起到负载均衡的作用。它管理着存储服务(Storage Server)。
    • Tracker Server 可以通过集群实现高可用性,其策略为“轮询”。
  • 存储节点 (Storage)
    • 主要功能是文件存储,客户端上传的文件最终都会被存储到 Storage 服务器上。
    • Storage 集群采用分组的方式,同一组内的每台服务器地位平等,数据进行同步,目的是实现数据备份,从而实现高可用性。不同组的服务器之间是不通信的。
    • 在同一组内,如果每台服务器的存储量不一致,系统会选择容量最小的那个进行存储,因此,同一组内的服务器之间软硬件最好保持一致。
    • Storage Server 会连接集群中的所有 Tracker Server,定期向他们汇报自己的状态,例如:剩余空间,文件同步情况,文件上传下载次数等信息。

Tracker 和 Storage 均可由一台或多台服务器组成。Tracker 和 Storage 节点中的服务器可以随时增加或下线,而不会对线上服务产生影响。在 Tracker 中,所有服务器都是对等的,可以根据服务器的压力情况随时增加或减少。

3 FastDFS 上传下载原理

3.1 文件上传原理

FastDFS 文件上传原理
  1. 客户端向 Tracker Server 发送请求,要求上传文件。
  2. Tracker Server 根据一定的策略选择一个 Storage Server,并将客户端重定向到选定的 Storage Server。
  3. Storage Server 接收上传请求,将文件存储到指定的存储空间中,并返回文件 ID(File ID)给客户端。
客户端上传文件后,返回的文件 id 示例如下:

group1/M00/02/11/Cgp9HWAaP06ASpANAACOQ0WzRSk795.png

  • group1 (组名): 文件上传后,所在 Storage 组的名称,由 Storage 返回,需要客户端自行保存。
  • M00 (虚拟磁盘路径):
    • Storage 配置的虚拟路径,在磁盘选项 storage_path 对应。
    • storage_path0 对应 M00
    • storage_path1 对应 M01
    • 以此类推…
  • 02/11 (数据二级目录): Storage 在虚拟磁盘下自行创建的 n x n 个目录。
  • Cgp9HWAaP06ASpANAACOQ0WzRSk795.png (文件名): 上传后会重命名,是用 Storage 根据特定信息生成的,里面包含:Storage 服务器的 ip,创建时间戳,大小,后缀名等信息。

3.2 文件下载原理

FastDFS 文件下载原理
  1. 客户端向 Tracker Server 发送文件下载请求,包括文件 ID 等信息。
  2. Tracker Server 根据请求中的信息,定位到目标 Storage Server,并将客户端重定向到该 Storage。
  3. Storage Server 根据文件 ID 等信息找到对应的文件,并将文件内容返回给客户端。

4 FastDFS 集群部署

4.1 环境配置

这里我们使用 Linux 发行版 CentOS7 环境进行安装,首先是编译环境配置:

1
2
3
4
# 安装 gcc(编译时需要)
yum install -y gcc gcc-c++
# 安装 libevent(运行时需求)
yum -y install libevent

然后安装 libfastcommon,GitHub - libfastcommon 是 FastDFS 官方提供的,内部包含了 FastDFS 运行所需要的一些基础库。我们需要去 Github 上下载 libfastcommon-master.zip,然后通过 FTP 等工具上传到服务器,解压后编译即可,编译命令如下:

1
2
3
# 进入解压后的源码目录,然后:
./make.sh
./make.sh install

libfastcommon 安装好后会在 /usr/lib64 目录下生成 libfastcommon.so 等库文件,但是 FastDFS 主程序设置的 lib 目录是 /usr/local/lib,所以需要创建软链接:

1
2
3
4
ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so
ln -s /usr/lib64/libfastcommon.so /usr/lib/libfastcommon.so
ln -s /usr/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so
ln -s /usr/lib64/libfdfsclient.so /usr/lib/libfdfsclient.so

当然,也可以直接拷贝过去:

1
2
3
4
cp /usr/lib64/libfastcommon.so /usr/local/lib/
cp /usr/lib64/libfastcommon.so /usr/lib/
cp /usr/lib64/libfdfsclient.so /usr/local/lib/
cp /usr/lib64/libfdfsclient.so /usr/lib/

注意: 为了避免配置文件的版本差异导致的错误(毕竟这个项目比较古老了),这里我们选择在 /usr/lib//usr/local/lib/ 下各复制一份。

4.2 Tracker 服务器安装配置

在配置好以上环境后,下载 FastDFS_v5.05.tar.gz(5.05 是目前最稳的版本),并上传到服务器安装路径解压。然后编译安装:

1
2
./make.sh
./make.sh install

将 FastDFS 源码中 conf 目录下的 tracker.conf 文件拷贝到 /etc/fdfs/ 下:

1
cp /root/FastDFS/conf/tracker.conf /etc/fdfs/

安装完成后,进行配置,编辑 /etc/fdfs/tracker.conf

1
2
3
4
5
6
7
#端口号
port=22122
#基础目录:Tracker 运行时会向此目录存储 storage 的管理数据
base_path=/root/fastdfs/tracker
# HTTP 服务端口
http.server_port=80
# 此端口要与 Nginx 的此项目监听端口一致

创建 tracker 基础数据目录,即 base_path 对应的目录

1
mkdir -p /root/fastdfs/tracker

防火墙中打开跟踪端口(默认的 22122)

1
2
3
4
firewall-cmd --zone=public --add-port=22122/tcp --permanent
 
# 重启防火墙生效
systemctl restart firewalld

启动 Tracker 服务器

1
2
3
4
usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart

# or
service fdfs_trackerd start

检测启动状态:

1
2
3
4
netstat -unltp|grep fdfs_trackerd

# 如下显示:
tcp    0    0 0.0.0.0:22122     0.0.0.0:*      LISTEN      2116/fdfs_trackerd

22122 端口监听成功,说明 Tracker 服务正常启动。

4.3 Storage 服务器安装配置

安装完 Tracker 后,我们紧接着安装 Storage 端,方法同 Tracker 一致,安装完成后将 FastDFS 源码中 conf 目录下的 storage.conf 文件拷贝到 /etc/fdfs/ 下:

1
cp /root/FastDFS/conf/storage.conf /etc/fdfs/

然后开始配置,编辑 /etc/fdfs/storage.conf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#配置组名
group_name=group1

#端口
port=23000
#向 tracker 心跳间隔(秒)
heart_beat_interval=30

# Storage 数据和日志目录地址(根目录必须存在,子目录会自动生成)
base_path=/root/fastdfs/storage

#store 存放文件的位置 (store_path)
#可以理解一个磁盘一个 path,多个磁盘,多个 store_path
#storage 目录不存在,需要自行创建
store_path0=/root/fastdfs/store0

#配置 tracker 服务器的 IP:Port
tracker_server=106.75.26.191:22122

# 访问端口
http.server_port=80
# 此端口要与 Nginx 的此项目监听端口一致

创建 storage 基础数据目录与虚拟磁盘目录:

1
2
mkdir -p /root/fastdfs/storage
mkdir -p /root/fastdfs/store0

防火墙中打开跟踪端口(默认的 23000)

1
2
3
4
firewall-cmd --zone=public --add-port=23000/tcp --permanent
 
# 重启防火墙生效
systemctl restart firewalld

启动 storage 服务器:

1
2
3
4
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart

# or
service fdfs_storaged start

检测启动状态:

1
2
3
4
netstat -unltp|grep fdfs_storaged

# 如下显示:
tcp    0    0 0.0.0.0:23000     0.0.0.0:*      LISTEN      2618/fdfs_storaged

23000 端口监听成功,说明 Storage 服务正常启动。

4.4 Nginx & fastdfs-nginx-module 安装配置

FastDFS 在 4.05 版本时,决定移除对 HTTP 协议的支持。这是因为其自带的 HTTP 服务功能较为简陋,且容易因文件在各个 Storage 之间的拷贝延迟导致下载失败。换句话说,文件 ID 已经由 Tracker 下发,但文件尚未同步到目标 Storage,此时请求下载就会失败。因此,FastDFS 提供了 Nginx+fastdfs-nginx-module 的方案,以实现重定向连接到源服务器读取文件,避免客户端因复制延迟的问题出现错误。同时,Nginx 还可以提供负载均衡等高性能服务。

4.4.1 Nginx 安装

分别在 Tracker 与 Storage 的服务器上安装 Nginx,这里省略。

4.4.2 Storage 端安装 fastdfs-nginx-module

我们仅需要在 Storage 的服务器上安装 fastdfs-nginx-module 模块:

  1. GitHub -FastDFS nginx module 下载合适的版本后,上传到 Storage 服务器并解压,移动到合适的文件夹:

    1
    
    tar -zxvf fastdfs-nginx-module_v1.16.tar.gz
    
  2. 进入源码文件夹:fastdfs-nginx-module/src,打开 config 文件,将 fastdfs 安装目录改为实际安装目录(默认情况需要将 /usr/local 改为 /usr):

    1
    2
    3
    4
    5
    6
    
    ngx_addon_name=ngx_http_fastdfs_module
    HTTP_MODULES="$HTTP_MODULES ngx_http_fastdfs_module"
    NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_fastdfs_module.c"
    CORE_INCS="$CORE_INCS /usr/include/fastdfs /usr/include/fastcommon/"
    CORE_LIBS="$CORE_LIBS -L/usr/lib -lfastcommon -lfdfsclient"
    CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64 -DFDFS_OUTPUT_CHUNK_SIZE='256*1024' -DFDFS_MOD_CONF_FILENAME='\"/etc/fdfs/mod_fastdfs.conf\"'"
  3. 重新编译 Nginx,添加 fastdfs-nginx-module 模块:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    # 先停掉 nginx 服务
    /usr/local/nginx/sbin/nginx -s stop
    
    # 进入 Nginx 源码解压包目录
    cd nginx-x.x.x/
    
    # 添加模块
    ./configure --add-module=${pathto}/fastdfs-nginx-module/src
    
    #重新编译、安装
    make && make install
    

4.4.3 Storage 端 Nginx 配置

  1. 配置 nginx conf,在 server 块下添加以下内容:

    1
    2
    3
    
    location ~/group[1-9]/M0[0-9] {
        ngx_fastdfs_module;
    }
  2. 将 FastDFS 源码中 conf 目录下的 http.conf、mime.types 文件拷贝到 /etc/fdfs/ 下:

    1
    2
    3
    
    cp /root/FastDFS/conf/http.conf  /etc/fdfs/
    cp /root/FastDFS/conf/mime.types  /etc/fdfs/
    # 在 Nginx 启动模块后,如果找不到以上两个文件,会将 Worker 进程杀掉
    
  3. 将源码 fastdfs-nginx-module/src 下的 mod_fastdfs.conf 拷贝至 /etc/fdfs 下:

    1
    
    cp mod_fastdfs.conf /etc/fdfs/
    
  4. 修改 /etc/fdfs/mod_fastdfs.conf

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    base_path=/root/fastdfs/storage
    storage_server_port=23000
    tracker_server=106.75.26.191:22122
    #(n 个 tracker 配置 n 行)
    #tracker_server=x.x.x.x:22122
    #url 中包含 group 名称
    url_have_group_name=true
    #指定文件存储路径(上面配置的 store 路径)
    store_path0=/root/fastdfs/store0
  5. 创建 nginx/client 目录:

    1
    
    mkdir -p /var/temp/nginx/client
    

4.4.4 Tracker 端 Nginx 配置

Tracker 作为 Client 访问的入口,需要将客户端对 fileId 的请求转发到 Storage 集群,所以需要在 Nginx conf 文件中添加以下规则:

1
2
3
4
5
6
7
8
9
upstream fastdfs_group_server {
	server 117.50.96.126:80
	# Storage 端 nginx 监听的 ip:port
	# 有多组 则添加多条数据
}

location ~/group[1-9]/M0[0-9] {
	proxy_pass http://fastdfs_group_server;
}

5 原生 FastDFS API 使用示例

5.1 依赖配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!--fastdfs 的 java 客户端-->
<dependency>
	<groupId>net.oschina.zcx7878</groupId>
	<artifactId>fastdfs-client-java</artifactId>
	<version>1.27.0.0</version>
</dependency>
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-io</artifactId>
	<version>1.3.2</version>
</dependency>

5.2 创建 FastDFS 客户端配置文件

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 = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = 80
fastdfs.tracker_servers = 106.75.26.191:22122

5.3 文件上传示例

 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
29
30
31
public class TestUpload {
	public static void main(String[] args) {
		try {
			// 加载配置文件
			ClientGlobal.initByProperties("config/fastdfs-client.properties");
			// 创建 tracker 客户端
			TrackerClient trackerClient = new TrackerClient();
			// 通过 tracker 客户端获取 tracker 的连接服务并返回
			TrackerServer trackerServer = trackerClient.getConnection();
			// 声明 storage 服务
			StorageServer storageServer = null;
			// 定义 storage 客户端
			StorageClient1 client = new StorageClient1(trackerServer,
			storageServer);
			// 定义文件元信息
			NameValuePair[] list = new NameValuePair[1];
			list[0] = new NameValuePair("fileName","1.jpg");
			String fileID = client.upload_file1("F:\\img\\1.jpg", "jpg", list);
			System.out.println("fileID = " + fileID);
			// group1/M00/00/00/CgHc918f8l6AFYp0AAWICfQnHuk889.jpg
			/*
			group1:一台服务器,就是一个组
			M00: store_path0 ----> /home/fastdfs/fdfs_storage/data
			00/00:两级数据目录
			*/
			trackerServer.close();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
}

5.4 文件查询示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class TestQuery {
	public static void main(String[] args) throws Exception {
		// 加载配置文件
		ClientGlobal.initByProperties("config/fastdfs-client.properties");
		// 创建 tracker 客户端
		TrackerClient trackerClient = new TrackerClient();
		// 通过 tracker 客户端获取 tracker 的连接服务并返回
		TrackerServer trackerServer = trackerClient.getConnection();
		// 声明 storage 服务
		StorageServer storageServer = null;
		// 定义 storage 客户端
		StorageClient1 client = new StorageClient1(trackerServer,
		storageServer);
		FileInfo fileInfo =
		client.query_file_info1("group1/M00/00/00/CgHc918f8l6AFYp0AAWICfQnHuk889.jpg");
		if(fileInfo!=null)
			System.out.println("fileInfo = " + fileInfo);
		else
			System.out.println("查无此文件!");
		trackerServer.close();
	}
}

5.5 文件下载示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class TestDownload {
	public static void main(String[] args) throws Exception{
		// 加载配置文件
		ClientGlobal.initByProperties("config/fastdfs-client.properties");
		// 创建 tracker 客户端
		TrackerClient trackerClient = new TrackerClient();
		// 通过 tracker 客户端获取 tracker 的连接服务并返回
		TrackerServer trackerServer = trackerClient.getConnection();
		// 声明 storage 服务
		StorageServer storageServer = null;
		// 定义 storage 客户端
		StorageClient1 client = new StorageClient1(trackerServer,
		storageServer);
		byte[] bytes =
		client.download_file1("group1/M00/00/00/CgHc918f8l6AFYp0AAWICfQnHuk889.jpg");
		// 通过 io 将字节数组,转换成一个文件
		FileOutputStream fileOutputStream = new FileOutputStream(new
		File("F:/xxxxxx.jpg"));
		fileOutputStream.write(bytes);
		fileOutputStream.close();
		trackerServer.close();
		System.out.println("下载完毕!");
	}
}

至此,FastDFS 的主要内容就介绍完了。


欢迎关注我的公众号,第一时间获取文章更新:

微信公众号

相关内容