FastDFS上传文件原理详解

FastDFS简介

​FastDFS是一款开源的轻量级分布式文件系统,功能主要包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了文件大容量存储和高性能访问的问题。

适用场景

​FastDFS特别适合以中小文件(建议范围:4KB<file_size<500MB)为载体的在线服务,如图片、视频、文档等等。FastDFS没有文件切块的处理,单个大文件传输性能较弱,所以不适合存储大文件。

​存储海量小文件存在的问题:(1)元数据管理低效,访问文件需要访问目录项,inode和数据,但这三者在存储介质的不同位置;(2)数据布局低效,文件经过大量删除和修改后,数据块在磁盘会零散的分配,产生大量磁盘碎片,造成访问性能下降和磁盘空间浪费;(3)I/O访问流程复杂,linux系统采用VFS来抽象文件系统的实现,对于小文件的I/O访问,系统调用成为了主要耗时,导致性能降低。

​FastDFS提供了小文件合并存储的功能,减少存储海量小文件对性能的影响。

FastDFS架构

在这里插入图片描述
重要角色:

  1. 跟踪服务器(Tracker):主要作用是维护Storage信息,每个Storage在启动后都需要上报自己所属的group,磁盘剩余空间,文件同步状况等信息,并保持周期性的心跳。
  2. 存储服务器(Storage):主要作用是存储所有上传的文件。Storage采用分组存储的方式,属于同组的Storage存储的文件是完全相同的,起到互备的作用。

节点对等特性

​FastDFS中的Tracker和Storage都可以有多台,不存在单点问题,且Tracker之间和同组内的Storage之间都是对等关系。传统的Master-Slave架构中,Master是单点,对等结构中所有节点地位相同,每个节点都是Master,不存在单点问题。

FastDFS上传文件详细过程

FastDFS上传协议

在学习过程之前,先了解一些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个字节组成:

  • pck_len:一个int64_t的整型,除去TrackerHeader长度的报文长度
  • cmd:命令
  • status:返回时的状态码,发送时设置为0

文件上传协议

  1. 文件上传协议头部:
字段含义字节数
TrackerHeader10个字节
storage_index1个字节
文件长度8个字节
文件后缀名6个字节
  1. 上传文件完成后,storage回复客户端的协议:
字段含义字节数
TrackerHeader10个字节
组名(group name)16个字节
文件路径名TrackerHeader.pck_len - 16个字节
FastDFS上传步骤解析

上传文件通信图如下:
在这里插入图片描述

以上传一个文件(下载地址.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
1. 上传连接请求

​客户端向集群中任意一台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
2. Tracker选择group和storage

​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
3. 返回Storage信息

​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

4. 上传文件

​拿到了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
5.选择存储路径、生成文件id并存储文件

(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个字节

  • 第一行1个字节为storage_index
  • 第二行8个字节为文件长度,fd(十六进制)=253(十进制),表示真正的文件大小
  • 第三行7个字节为文件后缀名,翻译为ASCII为txt
  • 第四行253个字节为上传文件的内容,翻译为ASCII即为开头出的“下载地址.txt”文件中的内容
6. 上传成功,返回访问路径

​ 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

7. 文件同步(若storage是集群)

当group中包含了多台storage server时,接收了上传文件的storage需要把文件同步给其他的storage。在FastDFS中,每个Storage之间的同步都由一个独立线程负责,该线程中所有操作都是以同步方式执行。例如一个group中由A,B,C三台机器,那么每台机器上都有两个线程负责同步。

Http访问FastDFS文件

​ FastDFS提供的HTTP服务较为简单,无法提供负载均衡等高性能服务,且在v4.05版本之后去除了内置HTTP服务,因此需要结合Nginx来进行访问。fastdfs提供了扩展模块fastdfs-nginx-module,使用方式:在每台storage server上安装nginx,结合fastdfs-nginx-module,直接对外提供HTTP服务。如图结构:
在这里插入图片描述

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值