分布式文件系统 | 适合类型 | 文件分布 | 系统性能 | 复杂度 | 备份机制 | 接口类型 | 开发语言 | 使用 |
---|---|---|---|---|---|---|---|---|
FastDFS | 4KB~500MB | 小文件合并存储,不分片处理 | 很高 | 简单 | 组(卷 )冗余存储 | API,HTTP接口 | C | 支付宝,UC,京东 |
TFS | 小文件 | 小文件合并,以block组织分片 | 很高 | 复杂 | Block存储多份,主从灾备 | API HTTP | C++ | 淘宝图片储存 |
glusterfs | 大文件 | 文件/块 | 很高 | 简单 | 镜像 | 大文件 镜像存储 |
FastDFS是阿里巴巴开源的一套轻量级,天生就是分布式设计的文件系统,是纯C语言开发的。
FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
官方论坛 http://bbs.chinaunix.net/forum-240-1.html
FastDfs google Code http://code.google.com/p/fastdfs/
分布式文件系统FastDFS架构剖析 http://www.programmer.com.cn/4380/
是一个高可扩展、高可用、高性能、面向互联网服务的分布式文件系统, 主要针对海量的非结构化数据,它构筑在普通的Linux机器集群上,可为外部提供高可靠和高并发的存储访问。TFS为淘宝提供海量小文件存储,通常文件大小不超过1M。它采用了HA架构和平滑扩容,保证了整个文件系统的可用性和扩展性。同时扁平化的数据组织结构,可将文件名映射到文件的物理地址,简化了文件的访问流程,一定程度上为TFS提供了良好的读写性能。
Gluster File System 是一款自由软件,主要由Z RESEARCH 公司负责开发,十几名开发者,最近非常活跃。 文档也比较齐全,不难上手。
主要应用在集群系统中,具有很好的可扩展性。软件的结构设计良好,易于扩展和配置,通过各个模块的灵活搭配以得到针对性的解决方案。可解决以下问题:网络存储,联合存储(融合多个节点上的存储空间),冗余备份,大文件的负载均衡(分块)。由于缺乏一些关键特性,可靠性也未经过长时间考验,还不适合应用于需要提供 24 小时不间断服务的产品环境。适合应用于大数据量的离线应用。
由于它良好的软件设计,以及由专门的公司负责开发,进展非常迅速,几个月或者一年后将会有很大的改进,非常值得期待。
GlusterFS通过Infiniband RDMA 或者Tcp/Ip 方式将许多廉价的x86 主机,通过网络互联成一个并行的网络文件系统
FastDFS的作者是余庆(happyfish100),github地址https://github.com/happyfish100
FastDFS服务端有三个模块:跟踪服务器(tracker server)、存储服务器(storage server)、客户端(client)。
跟踪服务器,主要做调度工作,起负载均衡的作用。在内存中记录集群中所有存储组和存储服务器的状态信息,是客户端和数据服务器交互的枢纽。相比GFS中的master更为精简,不记录文件索引信息,占用的内存量很少。
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的心跳信息,生成元数据信息来提供读写服务。
存储服务器(又称:存储节点或数据服务器),文件和文件属性(meta data)都保存到存储服务器上。Storage server直接利用OS的文件系统调用管理文件。
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的数据存储目录。
storage接受到写文件请求时,会根据配置好的规则(后面会介绍),选择其中一个存储目录来存储文件。为了避免单个目录下的文件数太多,在storage第一次启动时,会在每个数据存储目录里创建2级子目录,每级256个,总共65536个文件,新写的文件会以hash的方式被路由到其中某个子目录下,然后将文件数据直接作为一个本地文件存储到该目录中。
客户端,作为业务请求的发起方,通过专有接口,使用TCP/IP协议与跟踪器服务器或存储节点进行数据交互。FastDFS向使用者提供基本文件访问接口,比如upload、download、append、delete等,以客户端库的方式提供给用户使用。
另外两个概念:
group :组, 也可称为卷。 同组内服务器上的文件是完全相同的 ,同一组内的storage server之间是对等的, 文件上传、 删除等操作可以在任意一台storage server上进行 。
meta data :文件相关属性,键值对( Key Value Pair) 方式,如:width=1024,heigth=768 。
Tracker相当于FastDFS的大脑,不论是上传还是下载都是通过tracker来分配资源;客户端一般可以使用ngnix等静态服务器来调用或者做一部分的缓存;存储服务器内部分为卷(或者叫做组),卷于卷之间是平行的关系,可以根据资源的使用情况随时增加,卷内服务器文件相互同步备份,以达到容灾的目的。
首先客户端请求Tracker服务获取到存储服务器的ip地址和端口,然后客户端根据返回的IP地址和端口号请求上传文件,存储服务器接收到请求后生产文件,并且将文件内容写入磁盘并返回给客户端file_id、路径信息、文件名等信息,客户端保存相关信息上传完毕。
内部机制如下:
当集群中不止一个tracker server时,由于tracker之间是完全对等的关系,客户端在upload文件时可以任意选择一个trakcer。 选择存储的group 当tracker接收到upload file的请求时,会为该文件分配一个可以存储该文件的group,支持如下选择group的规则:
当选定group后,tracker会在group内选择一个storage server给客户端,支持如下选择storage的规则:
当分配好storage server后,客户端将向storage发送写文件请求,storage将会为文件分配一个数据存储目录,支持如下规则:
选定存储目录之后,storage会为文件生一个Fileid,由storage server ip、文件创建时间、文件大小、文件crc32和一个随机数拼接而成,然后将这个二进制串进行base64编码,转换为可打印的字符串。 选择两级目录 当选定存储目录之后,storage会为文件分配一个fileid,每个存储目录下有两级256*256的子目录,storage会按文件fileid进行两次hash(猜测),路由到其中一个子目录,然后将文件以fileid为文件名存储到该子目录下。
当文件存储到某个子目录后,即认为该文件存储成功,接下来会为该文件生成一个文件名,文件名由group、存储目录、两级子目录、fileid、文件后缀名(由客户端指定,主要用于区分文件类型)拼接而成。
客户端带上文件名信息请求Tracker服务获取到存储服务器的ip地址和端口,然后客户端根据返回的IP地址和端口号请求下载文件,存储服务器接收到请求后返回文件给客户端。
跟upload file一样,在download file时客户端可以选择任意tracker server。tracker发送download请求给某个tracker,必须带上文件名信息,tracke从文件名中解析出文件的group、大小、创建时间等信息,然后为该请求选择一个storage用来服务读请求。由于group内的文件同步时在后台异步进行的,所以有可能出现在读到时候,文件还没有同步到某些storage server上,为了尽量避免访问到这样的storage,tracker按照如下规则选择group内可读的storage。
当一个文件上传成功后,客户端马上发起对该文件下载请求(或删除请求)时,tracker是如何选定一个适用的存储服务器呢? 其实每个存储服务器都需要定时将自身的信息上报给tracker,这些信息就包括了本地同步时间(即,同步到的最新文件的时间戳)。而tracker根据各个存储服务器的上报情况,就能够知道刚刚上传的文件,在该存储组中是否已完成了同步。同步信息上报如下图:
写文件时,客户端将文件写至group内一个storage server即认为写文件成功,storage server写完文件后,会由后台线程将文件同步至同group内其他的storage server。
每个storage写文件后,同时会写一份binlog,binlog里不包含文件数据,只包含文件名等元信息,这份binlog用于后台同步,storage会记录向group内其他storage同步的进度,以便重启后能接上次的进度继续同步;进度以时间戳的方式进行记录,所以最好能保证集群内所有server的时钟保持同步。
storage的同步进度会作为元数据的一部分汇报到tracker上,tracke在选择读storage的时候会以同步进度作为参考。 比如一个group内有A、B、C三个storage server,A向C同步到进度为T1 (T1以前写的文件都已经同步到B上了),B向C同步到时间戳为T2(T2 > T1),tracker接收到这些同步进度信息时,就会进行整理,将最小的那个做为C的同步时间戳,本例中T1即为C的同步时间戳为T1(即所有T1以前写的数据都已经同步到C上了);同理,根据上述规则,tracker会为A、B生成一个同步时间戳。
说到下载就不得不提文件索引(又称:FID)的精巧设计了。文件索引结构如下图,是客户端上传文件后存储服务器返回给客户端,用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。
知道FastDFS FID的组成后,我们来看看FastDFS是如何通过这个精巧的FID定位到需要访问的文件。
TFS(Taobao FileSystem)是一个高可扩展、高可用、高性能、面向互联网服务的分布式文件系统,其设计目标是支持海量的非结构化数据。
TFS主要针对海量非结构化(结构化的数据是指像mysql中的数据,非结构化就是像NOSQL中的数据)的小数据,通常的文件大小不超过1M,可以满足对小文件存储的需求.
采用了HA架构:HA架构就是高可用的缩写,有一个活动节点和备份节点,当活动节点挂了的时候,备份节点会监测到,然后代替活动节点进行工作.
平滑扩容: 下面会说到
扁平化数据组织结构,可将文件名映射到文件的物理地址,简化了文件的访问流程,一定程度上为TFS提供了良好的读写性能
一个TFS集群由两个NameServer节点(一主一备),和多个DataServer节点组成.这些服务程序都是作为一个用户级的普通程序运行在Linux虚拟机上的
在TFS中.将大量的小文件(就是传过来的图片之类的)合并成一个大文件,这个大文件称为Block(块),每个Block块拥有一个集群内唯一的BlockId 这是由NameServer创建Block时分配的,NameServer负责维护Block和DataServer的关系,Block的信息(Block元文件)都储存在NameServer上,而Block实际的数据都储存在DataServer上.每台DataServer服务器上基本都会有很多DataServer进程,他们通常挂载在一个独立的磁盘文件目录(分区),以降低磁盘损坏带来的影响.
管理维护Block和DataServer相关信息,包括!DataServer加入,退出, 心跳信息, block和!DataServer的对应关系建立,解除。
正常情况下,一个块会在!DataServer上存在, 主NameServer负责Block的创建,删除,复制,均衡,整理, NameServer不负责实际数据的读写,实际数据的读写由!DataServer完成。
NameServer的主机绑定对外VIP(就是主机的IP) 提供服务,当主机宕机之后,迅速将VIP绑定至备份NameServer 将其切换为主机,对外提供服务,HeartAgent完成此功能
DataServer主要功能: 负责实际数据的存储和读写。
理解了上图中所有组件的作用
HeartAgent负责监听NameServer(主机) 和Slave NameServer(从机) 主机从机之间
Sync Data 同步数据 NameServer 中关于Block的信息都储存在内存中,所以速度很快
app访问NameServer主机.然后NameServer主机给app分配DataServer和Block 然后app在上面读和写
TFS的块大小可以通过配置项来决定,通常使用的块大小为64M。TFS的设计目标是海量小文件的存储,所以每个块中会存储许多不同的小文件。
DataServer进程会给Block中的每个文件分配一个ID(File ID,该ID在每个Block中唯一),并将每个文件在Block中的信息存放在和Block对应的Index文件中。这个Index文件一般都会全部load在内存,除非出现DataServer服务器内存和集群中所存放文件平均大小不匹配的情况(这句话还没理解)。
可以再创建一个和TFS对等的集群,由主集群负责写入这个集群 和同步数据 这个集群只对外提供读的功能, 当主机群挂了的时候,这个集群会自动顶上去.
由于NameServer和DataServer 之间是通过心跳机制来通信的,如果集群需要扩容,只需要将新的DataServer服务器部署好,然后启动即可.这些DataServer服务器会像NameServer发送心跳汇报 . NameServer的写入策略是 在容量较小,负载较轻的服务器写入新数据的概率会比较高, 同时.在集群负载较轻的时候, NameServer 会对所有的DataServer 和Block进行均衡. 使所有的DataServer容器尽早达到均衡.
进行均衡计划时,首先计算每台机器应拥有的blocks平均数量,然后将机器划分为两堆,一堆是超过平均数量的,作为移动源;一类是低于平均数量的,作为移动目的。
移动目的的选择:首先一个block的移动的源和目的,应该保持在同一网段内,也就是要与另外的block不同网段;另外,在作为目的的一定机器内,优先选择同机器的源到目的之间移动,也就是同台!DataServer服务器中的不同!DataServer进程。
当有服务器故障或者下线退出时(单个集群内的不同网段机器不能同时退出),不影响TFS的服务。此时!NameServer会检测到备份数减少的Block,对这些Block重新进行数据复制。
在创建复制计划时,一次要复制多个block, 每个block的复制源和目的都要尽可能的不同,并且保证每个block在不同的子网段内。因此采用轮换选择(roundrobin)算法,并结合加权平均。
由于DataServer之间的通信是主要发生在数据写入转发的时候和数据复制的时候,集群扩容基本没有影响。假设一个Block为64M,数量级为1PB。那么NameServer上会有 1 * 1024 * 1024 * 1024 / 64 = 16.7M个block。假设每个Block的元数据大小为0.1K,则占用内存不到2G。
TFS可以配置主辅集群,一般主辅集群会存放在两个不同的机房。主集群提供所有功能,辅集群只提供读。主集群会把所有操作重放到辅集群。这样既提供了负载均衡,又可以在主集群机房出现异常的情况不会中断服务或者丢失数据。
NameServer采用了HA结构,一主一备,主NameServer上的操作会重放至备NameServer。如果主NameServer出现问题,可以实时切换到备NameServer。
另外: NameServer 与DataServer之间也有心跳机制.DataServer 会将他的Block的信息定时发送到NameServer上, NameServer会根据这些信息重建Block和DataServer的关系(这里高版本的TFS已经不将这个功能放到心跳机制里了,心跳机制只用来检查DataServer是否还活着,以及有没有其他的DataServer加入).
TFS采用备份多个Block来实现DataServer容错,每个Block 在集群中存在多份,并且他们分别部署在不同网段的不同DataServer上,一般为3份,我记得可以通过配置max_Block…来修改,正是因为这样,如果你只有一台DataServer的时候,那么你的这个属性就要改为1 否则不能启动TFS
对于每一个写入请求.必须等待所有的Block备份完成之后才算写入成功.当出现磁盘损坏或者DataServer宕机的时候,TFS会启动复制流程,通过心跳机制获得这些DataServer上Block的信息,把那备份数小于3的Block尽快复制到其他的DataServer上去.
TFS对每一个文件会记录校验crc ,当客户端访问这个文件的时候发现crc和文件内容不匹配的时候,会自动切换到一个好的Block上去读取.此后客户端会修复单个文件损坏的情况.
对同一个文件来说,TFS支持并发的读 ,但是不支持并发的写入,其实单个Block块也是不支持并发的写入
TFS的文件名由块号和文件号通过某种对应关系组成,最大长度为18字节。文件名固定以T开始,第二字节为该集群的编号(可以在配置项中指定,取值范围 1~9)。余下的字节由Block ID和File ID通过一定的编码方式得到。文件名由客户端程序进行编码和解码
分布式存储已经研究很多年,但直到近年来,伴随着谷歌、亚马逊和阿里等互联网公司云计算和大数据应用的兴起,它才大规模应用到工程实践中。如谷歌的分布式文件系统GFS、分布式表格系统google Bigtable,亚马逊的对象存储AWS,阿里的TFS等都是很好的代表,同时也催生了一大批优秀的开源分布式存储系统,包括ceph、swift、Lustre和glusterfs等。
分布式存储按其存储接口分为三种:文件存储、块存储和对象存储。
通常支持POSIX接口(如glusterfs,但GFS、HDFS是非POSIX接口的),可以像普通文件系统(如ext4)那样访问,但又比普通文件系统多了并行化访问的能力和冗余机制。主要的分布式文件存储系统有TFS、cephfs、glusterfs和HDFS等。主要存储非结构化数据,如普通文件、图片、音视频等。可以采用NFS和CIFS等协议访问,共享方便。NAS是文件存储类型。
这种接口通常以QEMU Driver或者Kernel Module的方式存在,主要通过qemu或iscsi协议访问。主要的块存储系统有ceph块存储、sheepdog等。主要用来存储结构化数据,如数据库数据。数据共享不方便。DAS和SAN都是块存储类型。
对象存储系统综合了NAS和SAN的优点,同时具有SAN的高速直接访问和NAS的数据共享等优势。以对象作为基本的存储单元,向外提供RESTful数据读写接口,常以网络服务的形式提供数据访问。主要的对象存储系统有AWS、swift和ceph对象存储。主要用来存储非结构化数据。
Glusterfs是一个开源分布式文件系统,具有强大的横向扩展能力,可支持数PB存储容量和数千客户端,通过Infiniband RDMA 或Tcp/Ip 方式将许多廉价的x86 主机,通过网络互联成一个并行的网络文件系统。具有可扩展性、高性能、高可用性等特点。
Glusterfs是根据fuse提供的接口实现的一个用户态的文件系统,主要包括gluster、glusterd、glusterfs和glusterfsd四大模块组成:
在使用glusterfs提供的存储服务之前,需要先挂载存储池,向挂载点写数据,会经过fuse内核模块传给客户端,客户端检查存储池的类型,然后计算数据所在服务器 ,最后通过socket或rdma与服务器通信,如图2所示:
Glusterfs作为一款开源的分布式文件系统,在开源社区的活跃度很高,目前已经被红帽收购,国内外也有大量的用户在研究和应用,相关技术文档很丰富。它并不完美,为了支持线性扩展和高性能,而在小文件性能和元数据性能上做了让步,但却可以满足一定的场景,如大数据应用和视频存储等。
接下来会从优点和缺点两方面入手来介绍glusterfs。
采用无中心对称式架构,没有专用的元数据服务器,也就不存在元数据服务器瓶颈。元数据存在于文件的属性和扩展属性中。当需要访问某文件时,客户端使用DHT算法,根据文件的路径和文件名计算出文件所在brick,然后由客户端从此brick获取数据,省去了同元数据服务器通信的过程。
使用弹性hash算法代替传统的有元数据节点服务,获得了接近线性的高扩展性。
采用副本、EC等冗余设计,保证在冗余范围内的节点掉线时,仍然可以从其它服务节点获取数据,保证高可用性。采用弱一致性的设计,当向副本中文件写入数据时,客户端计算出文件所在brick,然后通过网络把数据传给所在brick,当其中有一个成功返回,就认为数据成功写入,不必等待其它brick返回,就会避免当某个节点网络异常或磁盘损坏时因为一个brick没有成功写入而导致写操作等待。
服务器端还会随着存储池的启动,而开启一个glustershd进程,这个进程会定期检查副本和EC卷中各个brick之间数据的一致性,并恢复。
丰富包括粗粒度、条带、副本、条带副本和EC,可以根据用户的需求,满足不同程度的冗余。粗粒度卷不带任何冗余,文件不进行切片,是完整的存放在某个brick上。
条带卷不带任何冗余,文件会切片存储(默认大小为128kB)在不同的brick上。这些切片可以并发读写(并发粒度是条带块),可以明显提高读写性能。该模式一般只适合用于处理超大型文件和多节点性能要求高的情况。
副本卷冗余度高,副本数量可以灵活配置,可以保证数据的安全性。
条带副本卷是条带卷和副本卷的结合。
EC卷使用EC校验算法,提供了低于副本卷的冗余度,冗余度小于100%,满足比较低的数据安全性,例如可以使2+1(冗余度为50%)、5+3(冗余度为60%)等。这个可以满足安全性要求不高的数据。
采用弱一致性的设计,向副本中写数据时,只要有一个brick成功返回,就认为写入成功,不必等待其它brick返回,这样的方式比强一致性要快。
还提供了I/O并发、write-behind、read-ahead、io-cache、条带等提高读写性能的技术。并且这些都还可以根据实际需求进行开启/关闭,i/o并发数量,cache大小都可以调整。
Glusterfs对逻辑卷中的存储单元brick划分hash分布空间(会以brick所在磁盘大小作为权重,空间总范围为0至232-1),一个brick占一份空间,当访问某文件时,使用Davies-Meyer算法根据文件名计算出hash值,比较hash值落在哪个范围内,即可确定文件所在的brick,这样定位文件会很快。但是在向逻辑卷中添加或移除brick时,hash分布空间会重新计算,每个brick的hash范围都会变化,文件定位就会失败,因此需要遍历文件,把文件移动到正确的hash分布范围对应的brick上,移动的文件可能会很多,加重系统负载,影响到正常的文件访问操作。
1.Glusterfs没有元数据节点,而是根据hash算法来确定文件的分布,目录利用扩展属性记录子卷的中brick的hash分布范围,每个brick的范围均不重叠。遍历目录时,需要readdir子卷中每个brick中的目录,获取每个文件的属性和扩展属性,然后进行聚合,相对于有专门元数据节点的分布式存储,遍历效率会差很多,当目录下有大量文件时,遍历会非常缓慢。
2.删除目录也会遇到同样的问题。
3.目前提供的解决方法是合理组织目录结构,目录层级不要太深,目录下文件数量不要太多,增大glusterfs目录缓存。另外,还可以设计把元数据和数据分离,把元数据放到内存数据库中(如redis、memcache),并在ssd上持久保存。
1.Glusterfs主要是为大文件设计,如io-cache、read-ahead、write-behind和条带等都是为优化大文件访问,对小文件的优化很少。
2.Glusterfs采用无元数据节点的设计,文件的元数据和数据一起保存在文件中,访问元数据和数据的速率相同,访问元数据的时间与访问数据的时间比例会较大,而有元数据中心的分布式存储系统,对元数据服务器可以采用更快速的ssd盘,可以采用更大的元数据缓存等优化措施来减小访问元数据时间与访问数据时间的比值,来提高小文件性能。
3.Glusterfs在客户端采用了元数据缓存md-cache来提高小文件性能,但是md-cache大小有限,但在海量小文件场景下,缓存命中率会严重下降,优化效果会减小,这就需要增大元数据缓存。
4.针对小文件性能差的问题,也可以参考TFS的做法, TFS会将大量的小文件合并成一个大文件,这个大文件称为Block,每个Block拥有在集群内唯一的编号(Block Id),Block Id在NameServer创建Block时分配,NameServer维护block与DataServer(存储Block的实际数据)的关系。