分布式文件系统FastDfs学习(理论篇)

609 阅读10分钟

一.什么是FastDfs?

FastDFS是一个开源的轻量级分布式文件系统。它解决了大数据量存储和负载均衡等问题。特别适合以中小文件(建议范围:4KB < file_size 
<500MB)为载体的在线服务。

二.FastDfs的相关概念

FastDFS是一个开源的轻量级分布式文件系统,由跟踪服务器(tracker server)、存储服务器(storage server)和客户端(client)三个部
分组成。

1、storage server(存储服务器)

存储服务器(又称:存储节点或数据服务器),文件和文件属性(meta data)都保存到存储服务器上。

Storage server(后简称storage)以组(卷,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的数据存储目录。

每个Strorage Server的存储结构:

storage接受到写文件请求时,会根据配置好的规则(后面会介绍),选择其中一个存储目录来存储文件。为了避免单个目录下的文件数太多,在
storage第一次启动时,会在每个数据存储目录里创建2级子目录,每级256个,总共65536个文件,新写的文件会以hash的方式被路由到其中某个子
目录下,然后将文件数据直接作为一个本地文件存储到该目录中。

2.tracker server(跟踪服务器)

tracker server,主要做调度工作,起负载均衡的作用。在内存中记录集群中所有存储组和存储服务器的状态信息,是客户端和数据服务器交互的
枢纽。

Tracker是FastDFS的协调者,负责管理所有的storage server和group,每个storage在启动后会连接Tracker,告知自己所属的group等信息,并保
持周期性的心跳,tracker根据storage的心跳信息,建立group==>[storage server list]的映射表。

Tracker需要管理的元信息很少,会全部存储在内存中;另外tracker上的元信息都是由storage汇报的信息生成的,本身不需要持久化任何数据,这
样使得tracker非常容易扩展,直接增加tracker机器即可扩展为tracker cluster来服务,cluster里每个tracker之间是完全对等的,所有的
tracker都接受stroage的心跳信息,生成元数据信息来提供读写服务。

3.client (客户端)

客户端,作为业务请求的发起方,通过专有接口,使用TCP/IP协议与跟踪器服务器或存储节点进行数据交互。FastDFS向使用者提供基本文件访
问接口,比如upload、download、append、delete等,以客户端库的方式提供给用户使用。

三个角色之间的交互:

特点:

1.group之间相互独立;
2.同一Group 内的Storage Server 之间需要互相备份:文件存放到一个Storage以后,需要备份到别的服务器
3.Tracker之间是不交互:每个storage sever 都需要向所有Tracker去主动报告信息

三.FastDfs的机制:

1.上传机制:

首先客户端请求Tracker服务获取到存储服务器的ip地址和端口,然后客户端根据返回的IP地址和端口号请求上传文件,存储服务器接收到请求后
生产文件,并且将文件内容写入磁盘并返回给客户端file_id、路径信息、文件名等信息,客户端保存相关信息上传完毕。

内部策略机制如下:

(1).选择tracker server:(tracker 集群不止一个,选择哪个?)

当集群中不止一个tracker server时,由于tracker之间是完全对等的关系,客户端在upload文件时可以任意选择一个trakcer。

(2). tracker server如何选择group?

  • Round robin,所有的group间轮询
  • Specified group,指定某一个确定的group
  • Load balance,选择最大剩余空 间的组上传文件

(3).选择storage server:(一个组内有多个Storage Server, 选择哪一个?)

  • Round robin,所有 server 轮询使用(默认)
  • 根据 IP 地址进行排序选择第一个服务器(IP 地址最小者)
  • 根据优先级进行排序(上传优先级由 storage server 来设置,参数为 upload_priority)

(4).选择storage path:

  • round robin,多个存储目录间轮询(默认)
  • load balance,选择使用剩余空间最大的存储路径

(5).生成fileId:

选定存储目录之后,storage会为文件生一个Fileid,由storage server ip、文件创建时间、文件大小、文件crc32和一个随机数拼接而成,然后
将这个二进制串进行base64编码,转换为可打印的字符串。
选定两级目录 ,storage会为文件分配一个fileid,每个存储目录下有两级256*256的子目录,storage会按文件fileid进行两次hash,路由到其中
一个子目录,然后将文件以fileid为文件名存储到该子目录下。

(6).生成文件名称:

当文件存储到某个子目录后,即认为该文件存储成功,接下来会为该文件生成一个文件名,文件名由group、存储目录、两级子目录、fileid、文件后缀名(由客户端指定,主要用于区分文件类型)拼接而成。

2.同步机制:

当一个文件上传成功后,客户端马上发起对该文件下载请求(或删除请求)时,tracker是如何选定一个适用的存储服务器呢?

其实每个存储服务器都需要定时将自身的信息上报给tracker,这些信息就包括了本地同步时间(即,同步到的最新文件的时间戳)。而tracker
根据各个存储服务器的上报情况,就能够知道刚刚上传的文件,在该存储组中是否已完成了同步。

写文件时,客户端将文件写至group内一个storage server即认为写文件成功,storage server写完文件后,会由后台线程将文件同步至同group
内其他的storage server。

每个storage写文件后,同时会写一份binlog,binlog里不包含文件数据,只包含文件名等元信息,这份binlog用于后台同步,storage会记录
向group内其他storage同步的进度,以便重启后能接上次的进度继续同步;进度以时间戳的方式进行记录,所以最好能保证集群内所有server
的时钟保持同步。

storage的同步进度会作为元数据的一部分汇报到tracker上,tracke在选择读storage的时候会以同步进度作为参考。

Storage Server之间的文件同步:

(1). A向B,C 同步文件X, 并且向Tracker Server 汇报我向 B 同步了X (文件创建时间9:30)我向 C 同步了X  ( 文件创建时间9:30 )

(2).B向A,C 同步文件Y, 并且向Tracker Server 汇报我向 A 同步了Y (文件创建时间9:31)我向 C 同步了Y  ( 文件创建时间9:31 )

(3).A向B,C 同步文件Z, 并且向Tracker Server 汇报我向 B 同步了Z(文件创建时间9:32)假设向C的同步还没开始

(4).9:33 用户向 服务器 C 上传了一个文件 W服务器C 向A , B 同步,并且报告Track Server我已经向A 同步了文件W   (文件创建时间9:33)我
已经向B 同步了文件W  (文件创建时间9:33)

(5).最后最早同步时间

3.下载机制:

客户端带上文件名信息请求Tracker服务获取到存储服务器的ip地址和端口,然后客户端根据返回的IP地址和端口号请求下载文件,存储服务器
接收到请求后返回文件给客户端。

跟upload file一样,在download file时客户端可以选择任意tracker server。

tracker发送download请求给某个tracker,必须带上文件名信息,tracke从文件名中解析出文件的group、大小、创建时间等信息,然后为该请
求选择一个storage用来服务读请求。由于group内的文件同步时在后台异步进行的,所以有可能出现在读到时候,文件还没有同步到某些
storage server上,为了尽量避免访问到这样的storage,tracker按照如下规则选择group内可读的storage:
  • 该文件上传到的源头storage - 源头storage只要存活着,肯定包含这个文件,源头的地址被编码在文件名中。
  • 文件创建时间戳 < Storage server被同步到的文件时间戳,这意味着当前文件已经被同步过来了。
  • 文件创建时间戳=Storage server被同步到的文件时间戳,且(当前时间—文件创建时间戳) > 一个文件同步完成需要的最大时间(如5分钟);
  • 当前时间-文件创建时间戳) > 同步延迟阀值(如一天)。 - 经过同步延迟阈值时间,认为文件肯定已经同步了。

4.小文件合并机制:

将小文件合并存储主要解决如下几个问题:

  • 本地文件系统inode数量有限,从而存储的小文件数量也就受到限制;

  • 多级目录+目录里很多文件,导致访问文件的开销很大(可能导致很多次IO);

  • 按小文件存储,备份与恢复的效率低.

    文件存储合并存储到trunk file后,根据其offset就能从trunk file读取到文件,文件在trunk file内的offset编码到文件名,决定了其
    在trunk file内的位置是不能更改的,也就不能通过compact的方式回收trunk file内删除文件的空间。但当trunk file内有文件删除时,
    其删除的空间是可以被复用的,比如一个100KB的文件被删除,接下来存储一个99KB的文件就可以直接复用这片删除的存储空间。
    

没有合并时的文件ID:

  • group1/M00/00/00/CmQPRlP0T4-AA9_ECDsoXi21HR0.tar:
    (1):storage_id(ip的数值型);
    (2): timestamp(创建时间);
    (3):file_size;
    (4):crc32(文件内容的检验码)
  • Base64编码

合并时的文件ID:

  • group1/M00/00/00/CgAEbFQWWbyIPCu1AAAFr1bq36EAAAAAQAAAAAAAAXH82.conf
    (1):file_size:占用大文件的空间(注意按照最小slot-256字节进行对齐);
    (2): mtime:文件修改时间;
    (3):file_size;
    (4):crc32:文件内容的crc32码;
    (5):formatted_ext_name:文件扩展名;
    (6):alloc_size:文件大小与size相等;
    (7):id:大文件ID如000001;
    (8):offset:文件内容在trunk文件中的偏移量;
    (9):size:文件大小

5.安全机制:

给URL增加token,只有自己才能生成,并且有过期时间。
Token  = md5(文件名,密钥, 时间戳)

安全机制的配置:

四.参考文章:

感谢作者的文章: