knight_ka | 生活及学习笔记

FastDFS简介及集群搭建

FastDFS简介

FastDFS是用c语言编写的一款开源的分布式文件系统,主要解决了海量数据存储问题,特别适合以中小文件(建议范围:4KB < file_size <500MB)为载体的在线服务。FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制。并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。

FastDFS架构包括:Tracker server 和 Storage server两个部分。其中Tracker server的作用主要是负载均衡和调度,而storage server的作用主要是文件存储。

客户端上传的文件最终保存在storage服务器上。Storage Server并没有实现自己的文件系统,而是利用操作系统的文件系统来管理文件。可以将Storage Server成为存储服务器。

FastDFS集群

FastDFS架构图
FastDFS由3部分组成:Client、Tracker、Stroage.

Client

Client是FastDFS的客户端,可以进行文件的上传、下载、删除等操作。
Client可以通过FastDFS的test命令 Java Client API 或者 nginx提供的http下载接口。
Client 也可以直接访问storage进行文件上传,下载,删除操作。但推荐通过Tracker进行文件上传、下载、删除。

Tracker Server

每个Tracker Server互相平等,客户端在上传文件时,可以选择集群中任意一个tracker server进行上传。tracker的主要作用是:获取一个group,并在该group中获取一个可用的storage server。
客户端Client获取到storage server后,会向storage server上传文件,storage server会为该文件分配一个存储路径。
Tracker需要管理的元信息很少,会全部存储在内存中;另外tracker上的元信息都是由storage汇报的信息生成的,本身不需要持久化任何数据,这样使得tracker非常容易扩展,直接增加tracker机器即可扩展为tracker cluster来服务,cluster里每个tracker之间是完全对等的,所有的tracker都接受stroage的心跳信息,生成元数据信息来提供读写服务。

Storage server

Storage server以组(卷,group或volume)为单位组织,一个group内包含多台storage机器,数据互为备份,存储空间以group内容量最小的storage为准,所以建议group内的多个storage尽量配置相同,以免造成存储空间的浪费。
以group为单位组织存储能方便的进行应用隔离、负载均衡、副本数定制(group内storage server数量即为该group的副本数),比如将不同应用数据存到不同的group就能隔离应用数据,同时还可根据应用的访问特性来将应用分配到不同的group来做负载均衡;缺点是group的容量受单机存储容量的限制,同时当group内有机器坏掉时,数据恢复只能依赖group内地其他机器,使得恢复时间会很长。
group内每个storage的存储依赖于本地文件系统,storage可配置多个数据存储目录,比如有10块磁盘,分别挂载在/data/disk1-/data/disk10,则可将这10个目录都配置为storage的数据存储目录。
storage接受到写文件请求时,会根据配置好的规则(后面会介绍),选择其中一个存储目录来存储文件。为了避免单个目录下的文件数太多,在storage第一次启动时,会在每个数据存储目录里创建2级子目录,每级256个,总共65536个文件,新写的文件会以hash的方式被路由到其中某个子目录下,然后将文件数据直接作为一个本地文件存储到该目录中。
所以FastDFS的集群就分为tracker部分的集群和Storage部分的集群。

时序图

文档中需要用到的资源:
链接: https://pan.baidu.com/s/1dF9rcfn 密码: yj3w

FastDFS-Tracker安装

安装libevent
FastDFS依赖libevent库,需要安装:

1
yum -y install libevent

安装libfastcommon
libfastcommon是FastDFS官方提供的,libfastcommon包含了FastDFS运行所需要的一些基础库。

1
2
3
4
tar -zxvf libfastcommonV1.0.7.tar.gz
cd libfastcommon-1.0.7
./make.sh
./make.sh install

注意:libfastcommon安装好后会自动将库文件拷贝至/usr/lib64下,由于FastDFS程序引用usr/lib目录所以需要将/usr/lib64下的库文件拷贝至/usr/lib下。

1
cp /usr/lib64/libfastcommon.so /usr/lib/

安装FastDFS-Tracker

1
2
3
4
tar -zxvf FastDFS_v5.05.tar.gz
cd FastDFS
./make.sh
./make.sh install

安装成功将安装目录下的conf下的文件拷贝到/etc/fdfs/下。

配置Tracker

1
2
3
4
5
6
7
#拷贝一份新的tracker配置文件:
cp tracker.conf.sample tracker.conf
#修改tracker.conf
vi tracker.conf
base_path=/home/yuqing/FastDFS
#改为:
base_path=/home/FastDFS

启动Tracker

1
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart

如果需要搭建tracker集群,则在多台服务器上执行此步骤。

安装FastDFS-storage

安装libevent

同上

安装libfastcommon

同上

storage编译安装
同Tracker Server编译安装过程一致。使用的配置文件和启动方式不同而已。

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#拷贝一份新的storage配置文件:
cp storage.conf.sample storage.conf
#修改storage.conf
vi storage.conf
group_name=group1 #配置不同的group
base_path=/home/yuqing/FastDFS
#改为:base_path=/home/FastDFS
store_path0=/home/yuqing/FastDFS
#改为:store_path0=/home/FastDFS/fdfs_storage
#如果有多个挂载磁盘则定义多个store_path,如下
#store_path1=.....
#store_path2=......
tracker_server=192.168.101.3:22122 #配置tracker服务器:IP
#如果有多个则配置多个tracker
tracker_server=192.168.101.4:22122

上传图片测试

FastDFS安装成功可通过/usr/bin/fdfs_test测试上传、下载等操作。

修改/etc/fdfs/client.conf

1
2
3
base_path=/home/fastdfs
tracker_server=192.168.101.3:22122
tracker_server=192.168.101.4:22122

上传本地图片:

1
/usr/bin/fdfs_test /etc/fdfs/client.conf upload /home/tomcat.png

上传完成后还无法进行http下载,需要与nginx整合之后才能用http进行下载。

与Nginx整合

Nginx整个FastDFS

在大多数业务场景中,往往需要为FastDFS存储的文件提供http下载服务,而尽管FastDFS在其storage及tracker都内置了http服务, 但性能表现却不尽如人意;
作者余庆在后来的版本中增加了基于当前主流web服务器的扩展模块(包括nginx/apache),其用意在于利用web服务器直接对本机storage数据文件提供http服务,以提高文件下载的性能。

Tracker整合nginx

一个Tracker可以对应多个Stroage,通过nginx对Storage进行负载均衡。
在每个Tracker上安装nginx,两个nginx为主备高可用。

配置nginx.conf:

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
#storage群group1组
upstream storage_server_group1{
server 192.168.101.5:80 weight=10;
server 192.168.101.6:80 weight=10;
}
#storage群group2组
upstream storage_server_group2{
server 192.168.101.7:80 weight=10;
server 192.168.101.8:80 weight=10;
}
server {
listen 80;
server_name ccc.test.com;
location /group1{
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://storage_server_group1;
}
location /group2{
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://storage_server_group2;
}
}

启动Nginx:

1
/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf

Storage整合nginx

更改nginx配置文件:

1
2
3
4
5
6
7
8
9
server {
listen 80;
server_name 192.168.101.7;
location /group1/M00/{
root /home/fastdfs/fdfs_storage/data;
ngx_fastdfs_module;
}
}

此时先不要启动该Nginx,因为还没有安装FastDFS-nginx-module。

FastDFS-nginx-module安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
tar -zxvf FastDFS-nginx-module_v1.16.tar.gz
cd FastDFS-nginx-module/src
#修改config文件:将CORE_INCS和CORE_LIBS中的/usr/local/路径改为/usr/
# 将FastDFS-nginx-module/src下的mod_FastDFS.conf拷贝至/etc/fdfs/下
cp mod_FastDFS.conf /etc/fdfs/
#并修改mod_FastDFS.conf的内容:
vi /etc/fdfs/mod_FastDFS.conf
base_path=/home/FastDFS
tracker_server=192.168.101.3:22122
tracker_server=192.168.101.4:22122
url_have_group_name=true #url中包含group名称
store_path0=/home/FastDFS/fdfs_storage #指定文件存储路径

这个fastdfs-nginx-module可以重定向连接到源服务器取文件,避免客户端由于复制延迟的问题,出现错误。

重新编译安装Nginx

1
2
3
./configure --add-module=/.../fastdfs-nginx-module/src/
make
make install

启动该Storage Server中的Nginx即可。

此时,就可以通过http的方式下载文件了。
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package fastdfs;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import org.junit.Test;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* Created by tnp on 08/04/2017.
*/
public class FastdfsClientTest2 {
//客户端配置文件
public String conf_filename = "/Users/tnp/Downloads/client.conf";
//本地文件,要上传的文件
public String local_filename = "/Users/tnp/Downloads/2.jpg";
//上传文件
@Test
public void testUpload() {
for(int i=0;i<100;i++){
try {
ClientGlobal.init(conf_filename);
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
StorageClient storageClient = new StorageClient(trackerServer,
storageServer);
NameValuePair nvp [] = new NameValuePair[]{
new NameValuePair("item_id", "100010"),
new NameValuePair("width", "80"),
new NameValuePair("height", "90")
};
String fileIds[] = storageClient.upload_file(local_filename,null,nvp);
System.out.println(fileIds.length);
System.out.println("组名:" + fileIds[0]);
System.out.println("路径: " + fileIds[1]);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}