赞
踩
FastDFS是一款开源的轻量级分布式文件系统,功能主要包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了文件大容量存储和高性能访问的问题。
FastDFS特别适合以中小文件(建议范围:4KB<file_size<500MB)为载体的在线服务,如图片、视频、文档等等。FastDFS没有文件切块的处理,单个大文件传输性能较弱,所以不适合存储大文件。
存储海量小文件存在的问题:(1)元数据管理低效,访问文件需要访问目录项,inode和数据,但这三者在存储介质的不同位置;(2)数据布局低效,文件经过大量删除和修改后,数据块在磁盘会零散的分配,产生大量磁盘碎片,造成访问性能下降和磁盘空间浪费;(3)I/O访问流程复杂,linux系统采用VFS来抽象文件系统的实现,对于小文件的I/O访问,系统调用成为了主要耗时,导致性能降低。
FastDFS提供了小文件合并存储的功能,减少存储海量小文件对性能的影响。
重要角色:
节点对等特性
FastDFS中的Tracker和Storage都可以有多台,不存在单点问题,且Tracker之间和同组内的Storage之间都是对等关系。传统的Master-Slave架构中,Master是单点,对等结构中所有节点地位相同,每个节点都是Master,不存在单点问题。
在学习过程之前,先了解一些FastDFS协议:
FastDFS协议头部
typedef struct
{
char pkg_len[FDFS_PROTO_PKG_LEN_SIZE];//body length, not including header(8个字节)
char cmd;//command code(1个字节)
char status;//status code for response(1个字节)
} TrackerHeader;
字段解释:
FastDFS协议头部由10个字节组成:
文件上传协议
字段含义 | 字节数 |
---|---|
TrackerHeader | 10个字节 |
storage_index | 1个字节 |
文件长度 | 8个字节 |
文件后缀名 | 6个字节 |
字段含义 | 字节数 |
---|---|
TrackerHeader | 10个字节 |
组名(group name) | 16个字节 |
文件路径名 | TrackerHeader.pck_len - 16个字节 |
上传文件通信图如下:
以上传一个文件(下载地址.txt)为例:
文件内容为:(文件大小为253字节)
https://github.com/happyfish100/fastdfs/archive/V6.04.tar.gz
https://github.com/happyfish100/fastdfs-nginx-module/archive/V1.22.tar.gz
https://github.com/happyfish100/libfastcommon/archive/V1.0.42.tar.gz
https://nginx.org/download/nginx-1.16.1.tar.gz
客户端向集群中任意一台Tracker server发起TCP连接,建立连接后,客户端发送上传请求报文。报文data内容(十六进制)如下:
00000000000000006500 //10个字节
解释:data共10个字节,结构就是上面协议中谈到的FastDFS协议头部TrackerHeader。前8个字节为0,因为这个报文没有报文体,cmd=65(十六进制)=101(十进制),status=0。
101命令对应源码中的定义:
#define TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE 101
Tracker收到客户端的上传请求报文后,需要选择文件存储的group,选择方式可在tracker.conf配置文件配置,具体配置项如下:
# 如何选择上传文件的存储group
# 0: 轮询
# 1: 指定group名称
# 2: 负载均衡, 选择空闲空间最大的存储group
store_lookup=2
# 选择哪一个存储group,当store_lookup=1时,须指定存储group的名称
store_group=group2
选择完group之后,需要选择文件存储的storage server,选择方式可在tracker.conf配置文件配置,具体配置项如下:
# 如何选择上传文件的存储server
# 0: 轮询
# 1: 以ip地址排序的第一个地址
# 2: 以优先级排序(优先级在storage上配置)
store_server=0
Tracker选择完可用的Storage服务器后,向客户端返回信息。返回的报文data内容(十六进制)如下(为了便于观察,做了内容换行):
00000000000000286400 //10个字节
67726f75703200000000000000000000 //16个字节
3139322e3136382e34322e3432000000 //16个字节
000000000059d8 //7个字节
00 //1个字节
解释:data共50个字节
第一行10个字节为TrackerHeader,其中前8个字节为报文体长度,28(十六进制)=40(十进制),对应的接下来的报文体16+16+7+1=40个字节;64(十六进制)=100(十进制),100命令对应源码中的定义:
#define TRACKER_PROTO_CMD_RESP 100
第二行16个字节为Storage的组名(group name),翻译为ASCII为group2,正好是我Storage中的一个组名。
第三行16个字节为Storage的ip,翻译为ASCII为192.168.42.42
第四行7个字节为Storage的port,翻译为ASCII为23000
第五行1个字节为storage_index
拿到了Tracker返回的Storage服务器的group name,ip和port后,向这台Storage服务器发起TCP连接请求,建立连接后,开始上传文件,
先发送一个告知文件大小的报文,data内容(十六机制)如下:
000000000000010c0b00 //10个字节
解释:data共10个字节,前8个字节为之后所有报文报文体的长度,10c(十六进制)=268(十进制),268字节比真实的文件253字节多了15个字节,这15个字节用于告知storage_index,文件长度和文件名。cmd=0b(十六进制)=11(十进制),11命令对应的源码定义如下:
#define STORAGE_PROTO_CMD_UPLOAD_FILE 11
(1)选择storage path
storage server收到客户端上传文件的请求后,为文件分配一个数据存储目录,分配的规则可在tracker.conf配置文件中配置,具体配置项如下:
# 选择存储server的哪一个路径(磁盘或挂载点)上传文件
# 0: 轮询
# 2: 负载均衡, 选择空闲空间最大的路径来存储文件
store_path=0
(2)生成fileId
选定了存储目录后,storage文件生一个fileid,由storage server ip、文件创建时间、文件大小、文件crc32和一个随机数拼接而成,然后将这个二进制串进行base64编码,转换为可打印的字符串。
(3)选择两级目录
默认每个存储目录下有两级子目录,分别是00~FF,共256*256个子目录,storage选择两级目录的规则可以在storage.conf配置文件中配置,具体配置项如下:
# 选择文件存储的路径
# 0: 轮询(默认)
# 1: 随机,通过hash分布
file_distribute_path_mode=0
# 当选择了轮询方式,存储路径从00/00开始,目录下的文件数到达这个值(默认100),
# 就换下一个目录00/01,依次直到FF/FF
file_distribute_rotate_count=100
选择了目录后,将文件以fileId为文件名存储到该子目录下。
(4)存储文件
开始发送真正的文件内容,报文data内容(十六进制)如下:
00 //1个字节
00000000000000fd //8个字节
747874000000 //6个字节
68747470733a2f2f6769746875622e636f6d2f6861707079666973683130302f666173746466732f617263686976652f56362e30342e7461722e677a0d0a68747470733a2f2f6769746875622e636f6d2f6861707079666973683130302f666173746466732d6e67696e782d6d6f64756c652f617263686976652f56312e32322e7461722e677a0d0a68747470733a2f2f6769746875622e636f6d2f6861707079666973683130302f6c696266617374636f6d6d6f6e2f617263686976652f56312e302e34322e7461722e677a0d0a68747470733a2f2f6e67696e782e6f72672f646f776e6c6f61642f6e67696e782d312e31362e312e7461722e677a//253个字节
解释:data共268个字节
Storage将文件写入磁盘后,返回客户端文件的路径和文件名,报文data内容(十六进制)如下:
000000000000003c6400 //10个字节
67726f75703200000000000000000000 //16个字节
4d30302f30302f30302f774b67714856344f51517941626f3959414141415f666453706d673835352e747874 //44个字节
解释:data共70个字节
第一行10个字节为TrackerHeader,前8个字节为报文体长度,3c(十六进制)=60(十进制);cmd=64(十六进制)=100(十进制),100命令对应的源码定义如下:
#define TRACKER_PROTO_CMD_RESP 100
第二行16个字节为组名(group name),翻译为ASCII为group2
第三行44个字节为文件路径和文件名,翻译为ASCII为M00/00/00/wKgqHV4OQQyAbo9YAAAA_fdSpmg855.txt
当group中包含了多台storage server时,接收了上传文件的storage需要把文件同步给其他的storage。在FastDFS中,每个Storage之间的同步都由一个独立线程负责,该线程中所有操作都是以同步方式执行。例如一个group中由A,B,C三台机器,那么每台机器上都有两个线程负责同步。
FastDFS提供的HTTP服务较为简单,无法提供负载均衡等高性能服务,且在v4.05版本之后去除了内置HTTP服务,因此需要结合Nginx来进行访问。fastdfs提供了扩展模块fastdfs-nginx-module,使用方式:在每台storage server上安装nginx,结合fastdfs-nginx-module,直接对外提供HTTP服务。如图结构:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。