淘宝的TFS已经在其内部应用的比较成熟,但对大文件的存储支持的还不太好。2.0版本正在改进,非常期待。好好研究一下TFS、FastDFS和Ceph,相信会有很多收获的。
简介
TFS(Taobao FileSystem)是一个高可扩展、高可用、高性能、面向互联网服务的分布式文件系统,主要针对海量的非结构化数据,它构筑在普通的Linux机器集 群上,可为外部提供高可靠和高并发的存储访问。TFS为淘宝提供海量小文件存储,通常文件大小不超过1M,满足了淘宝对小文件存储的需求,被广泛地应用在 淘宝各项应用中。它采用了HA架构和平滑扩容,保证了整个文件系统的可用性和扩展性。同时扁平化的数据组织结构,可将文件名映射到文件的物理地址,简化了 文件的访问流程,一定程度上为TFS提供了良好的读写性能。
TFS的总体结构
一个TFS集群由两个NameServer节点(一主一备)和多个DataServer节点组成。这些服务程序都是作为一个用户级的程序运行在普通Linux机器上的。
在TFS中,将大量的小文件(实际数据文件)合并成为一个大文件,这个大文件称为块(Block), 每个Block拥有在集群内唯一的编号(Block Id), Block Id在NameServer在创建Block的时候分配, NameServer维护block与DataServer的关系。Block中的实际数据都存储在DataServer上。而一台DataServer 服务器一般会有多个独立DataServer进程存在,每个进程负责管理一个挂载点,这个挂载点一般是一个独立磁盘上的文件目录,以降低单个磁盘损坏带来 的影响。
NameServer主要功能是: 管理维护Block和DataServer相关信息,包括DataServer加入,退出, 心跳信息, block和DataServer的对应关系建立,解除。正常情况下,一个块会在DataServer上存在, 主NameServer负责Block的创建,删除,复制,均衡,整理, NameServer不负责实际数据的读写,实际数据的读写由DataServer完成。
DataServer主要功能是: 负责实际数据的存储和读写。
同时为了考虑容灾,NameServer采用了HA结构,即两台机器互为热备,同时运行,一台为主,一台为备,主机绑定到对外vip,提供服务;当主机器
宕机后,迅速将vip绑定至备份NameServer,将其切换为主机,对外提供服务。图中的HeartAgent就完成了此功能。
TFS的块大小可以通过配置项来决定,通常使用的块大小为64M。TFS的设计目标是海量小文件的存储,所以每个块中会存储许多不同的小文件。 DataServer进程会给Block中的每个文件分配一个ID(File ID,该ID在每个Block中唯一),并将每个文件在Block中的信息存放在和Block对应的Index文件中。这个Index文件一般都会全部 load在内存,除非出现DataServer服务器内存和集群中所存放文件平均大小不匹配的情况。
另外,还可以部署一个对等的TFS集群,作为当前集群的辅集群。辅集群不提供来自应用的写入,只接受来自主集群的写入。当前主集群的每个数据变更操作都会重放至辅集群。辅集群也可以提供对外的读,并且在主集群出现故障的时候,可以接管主集群的工作。
平滑扩容
原有TFS集群运行一定时间后,集群容量不足,此时需要对TFS集群扩容。由于DataServer与NameServer之间使用心跳机制通信,如果系 统扩容,只需要将相应数量的新DataServer服务器部署好应用程序后启动即可。这些DataServer服务器会向NameServer进行心跳汇 报。NameServer会根据DataServer容量的比率和DataServer的负载决定新数据写往哪台DataServer的服务器。根据写入 策略,容量较小,负载较轻的服务器新数据写入的概率会比较高。同时,在集群负载比较轻的时候,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中,将大量的小文件(实际用户文件)合并成为一个大文件,这个大文件称为块(Block)。TFS以Block的方式组织文件的存储。每一个
Block在整个集群内拥有唯一的编号,这个编号是由NameServer进行分配的,而DataServer上实际存储了该Block。在
NameServer节点中存储了所有的Block的信息,一个Block存储于多个DataServer中以保证数据的冗余。对于数据读写请求,均先由
NameServer选择合适的DataServer节点返回给客户端,再在对应的DataServer节点上进行数据操作。NameServer需要维
护Block信息列表,以及Block与DataServer之间的映射关系,其存储的元数据结构如下:
在DataServer节点上,在挂载目录上会有很多物理块,物理块以文件的形式存在磁盘上,并在DataServer部署前预先分配,以保证后续的访问
速度和减少碎片产生。为了满足这个特性,DataServer现一般在EXT4文件系统上运行。物理块分为主块和扩展块,一般主块的大小会远大于扩展块,
使用扩展块是为了满足文件更新操作时文件大小的变化。每个Block在文件系统上以“主块+扩展块”的方式存储。每一个Block可能对应于多个物理块,
其中包括一个主块,多个扩展块。
在DataServer端,每个Block可能会有多个实际的物理文件组成:一个主Physical Block文件,N个扩展Physical
Block文件和一个与该Block对应的索引文件。Block中的每个小文件会用一个block内唯一的fileid来标识。DataServer会在
启动的时候把自身所拥有的Block和对应的Index加载进来。
容错机制
1. 集群容错
TFS可以配置主辅集群,一般主辅集群会存放在两个不同的机房。主集群提供所有功能,辅集群只提供读。主集群会把所有操作重放到辅集群。这样既提供了负载均衡,又可以在主集群机房出现异常的情况不会中断服务或者丢失数据。
2. NameServer容错
Namserver主要管理了DataServer和Block之间的关系。如每个DataServer拥有哪些Block,每个Block存放在哪些
DataServer上等。同时,NameServer采用了HA结构,一主一备,主NameServer上的操作会重放至备NameServer。如果
主NameServer出现问题,可以实时切换到备NameServer。
另外NameServer和DataServer之间也会有定时的heartbeat,DataServer会把自己拥有的Block发送给NameServer。NameServer会根据这些信息重建DataServer和Block的关系。
3. DataServer容错
TFS采用Block存储多份的方式来实现DataServer的容错。每一个Block会在TFS中存在多份,一般为3份,并且分布在不同网段的不同
DataServer上。对于每一个写入请求,必须在所有的Block写入成功才算成功。当出现磁盘损坏DataServer宕机的时候,TFS启动复制
流程,把备份数未达到最小备份数的Block尽快复制到其他DataServer上去。
TFS对每一个文件会记录校验crc,当客户端发现crc和文件内容不匹配时,会自动切换到一个好的block上读取。此后客户端将会实现自动修复单个文
件损坏的情况。
并发机制
TFS现在只支持小文件,对于同一个文件来说,多个用户可以并发读。
现有TFS并不支持并发写一个文件。一个文件只会有一个用户在写。这在TFS的设计里面对应着是一个block同时只能有一个写或者更新操作。
TFS文件名的结构
TFS的文件名由块号和文件号通过某种对应关系组成,最大长度为18字节。文件名固定以T开始,第二字节为该集群的编号(可以在配置项中指定,取值范围
1~9)。余下的字节由Block ID和File ID通过一定的编码方式得到。文件名由客户端程序进行编码和解码,它映射方式如下图:
TFS客户程序在读文件的时候通过将文件名转换为BlockID和FileID信息,然后可以在NameServer取得该块所在DataServer信
息(如果客户端有该Block与DataServere的缓存,则直接从缓存中取),然后与DataServer进行读取操作。
TFS性能数据
1. 软件环境描述
【测试机软件情况描述】
(1) Red Hat Enterprise Linux AS release 4 (Nahant Update 8)
(2) gcc (GCC) 3.4.6 20060404 (Red Hat 3.4.6-11)
(3) 部署了TFS客户端程序
【服务器软件情况描述】
(1) Red Hat Enterprise Linux Server release 5.4 (Tikanga)
(2) gcc (GCC) 3.4.6 20060404 (Red Hat 3.4.6-9)
(3) 部署了2台DataServer程序。
【服务器软件情况描述】
(1) Red Hat Enterprise Linux Server release 5.4 (Tikanga)
(2) gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-46)
(3) 部署了2台NameServer(HA)程序。
2. 硬件环境描述
【测试机硬件情况描述】
(1) 一枚八核Intel(R) Xeon(R) CPU E5520 @ 2.27GHz
(2) 内存总数8299424 kB
【服务器硬件情况描述】cpu/memory等
(1) 一枚八核Intel(R) Xeon(R) CPU E5520 @ 2.27GHz
(2) 内存总数8165616 kB
3. 随机读取1K~50K大小的文件性能
Read的TPS随着线程数的增加而增加,增长逐渐趋缓,到90线程的时候达到第一个高峰,此时再增加读线程,则TPS不再稳定增长。
4. 随机写入1K~50K大小的文件
Write的TPS在线程数60左右达到高峰,此时再增加写入线程,TPS不再稳定增长。
5. 在不同线程写压力下的读文件性能
可以看出随着写压力的增加,读文件的TPS会大幅下滑。当写压力达到一定程度时读文件TPS趋缓。
同时,对平均大小为20K的文件进行了测试,测试中读:写:更新:删除操作的比率为100:18:1:1时,在!DataServer服务器磁盘util访问达到80%以上时,响应时间如下:
TYPE | SUCCCOUNT | FAILCOUNT | AVG(us) | MIN(us) | MAX(us) |
read | 100000 | 0 | 20886 | 925 | 1170418 |
write | 18000 | 0 | 17192 | 2495 | 1660686 |
update | 1000 | 0 | 48489 | 5755 | 1205119 |
delete | 1000 | 0 | 14221 | 382 | 591651 |
TYPE:操作类型
SUCCCOUNT:成功个数
FAILCOUNT:失败个数
AVG:平均响应时间
MIN:最短响应时间
MAX: 最大响应时间
整体介绍
TFS是一个分布式文件系统,目前主要支持对小文件的存储。整个系统包括nameserver,dataserver和client等模块,其中 nameserver是管理元数据的服务器,代码存放于src/nameserver目录,dataserver是数据真正存储的服务器,代码存放于 src/dataserver目录,client提供对tfs文件操作的服务,代码存放于src/client目录。
nameserver
nameserver是文件系统的元数据管理中心。nameserver主要负责管理自己所在集群的信息,维护dataserver的相关信息,实现dataserver的负载均衡。具体有以下几个功能:
(1) 负责对dataserver 的检查,通过dataserver发送的心跳消息,监控dataserver的加入或者退出,管理所在集群的dataserver信息列表。
(2) 维护每个dataserver的状态信息,包括总容量,已用容量,当前负载,Block数量等,发起对Block的新建或删除等操作。
(3) 维护dataserver上的Block元数据信息,包括Block是否可用,文件数等,读文件的时候负责定位dataserver的位置,写文件的时候负责分配某dataserver的可写block。
(4) 管理所有block在dataserver中的分布,block的副本复制,以及均衡。
dataserver
dataserver是文件系统的最终存储设备。 dataserver最主要的功能就是维护自己拥有的BLOCK列表,及BLOCK中的文件列表,提供数据的读写。负责具体文件的创建,读写删改。具体有以下几个功能:
(1) 维护和nameserver之间的消息通信,向nameserver发送心跳信息,报告自己的BLOCK列表及状态(如机器Load, 硬盘使用情况)。
(2) 提供dataserver上BLOCK的创建和删除,并更新nameserver上的block信息。
(3) 提供BLOCK上文件的创建、删除、读写、重命名等。
(4) 提供dataserver本身的信息查询,例如BLOCK及FILE的信息查询。
(5) 实现和镜像的数据同步,提供BLOCK复制和压缩功能。
dataserver在EXT4文件系统之上预分配物理块。每个主物理块
64M(可配置),由这些物理块组成的Block上存放多个小文件。使用BlockID标识Block,Block内部使用FileID标识文件。当出现
该文件修改后出现block容量不够时,dataserver将自动申请扩展块存放。
adminserver
管理工具,可用于启动nameserver和dataserver,监控nameserver和dataserver的运行状态。当nameserver
或dataserver挂掉时,自动重启。客户端为用户使用分布式文件系统提供一层接口封装,提供tfs上文件打开,读写,删除,修改,状态查询,关闭等
功能。
目前的客户端主要支持JAVA,C++两种。
common
提供基础数据结构和组件,主要用于定义配置信息、错误信息,系统参数等数据结构,提供目录操作、锁服务等基本服务。
tools
提供对dataserver和nameserver等的工具使用,具体使用细节请参照工具介绍。
TFS读操作流程
获得Block ID和File ID
根据TFS文件名解析出Block ID和block中的File ID.
获取dataserver地址
向nameserver发送查询请求得到Block ID所在的dataserver地址。
由于nameserver中维护了block和dataserver的对应关系,所以nameserver能够提供相应的信息。
Note: 由于TFS是把大量小文件放在一个block里面,
所以TFS的文件复制是基于block的,而且复制出来的block的block id应该是一致的
请求文件
通过发送Block_ID、File_ID和offset为参数的读请求到对应的dataserver,得到文件内容。
dataserver会根据本地记录的信息来得到File ID所在block的偏移量,从而读取到正确的文件内容.
TFS写操作数据流
TFS系统中,nameserver会保证一个文件有多个副本存储于不同的dataserver上以保证冗余。当由于dataserver服务器宕机或由 于其他原因退出系统导致某些文件副本数量下降时,nameserver将会调度新的dataserver节点存储文件备份。同样为了保证数据一致性,当写 入一个文件时,只有所有参与的dataserver均写入成功时,该操作才算成功。TFS的写操作数据流图如下所示:
客户端首先向nameserver发起写请求,nameserver需要根据dataserver上的可写块,容量和负载加权平均来选择一个可写的
block。并且在该block所在的多个dataserver中选择一个作为写入的master,这个选择过程也需要根据dataserver的负载以
及当前作为master的次数来计算,使得每个dataserver作为master的机会均等。master一段选定,除非master宕机,不会更
换,一旦master宕机,需要在剩余的dataserver中选择新的master。返回一个dataserver列表。
客户端向master dataserver开始数据写入操作。master
server将数据传输为其他的dataserver节点,只有当所有dataserver节点写入均成功时,master
server才会向nameserver和客户端返回操作成功的信息。
淘宝网成立于2003年,在整个系统的构建和规划上也做过相当多的尝试和探索。
下图是淘宝网2007年之前的图片存储系统。淘宝网之前一直采用的商用存储系统,应用NetApp公司的文件存储系统。随着淘宝网的图片文件数量以 每年2倍(即原来3倍)的速度增长,淘宝网后端NetApp公司的存储系统也从低端到高端不断迁移,直至2006年,即时是NetApp公司最高端的产品 也不能满足淘宝网存储的要求。
淘宝网2007年以前的图片存储系统架构图,由于淘宝网图片速度已每年2倍的速度增长,商用系统已经完全不能满足其存储需求,目前淘宝网采用自主研发的TFS集群文件系统来解决海量小图片的读取和访问问题
从2006年开始,淘宝网决定自己开发一套针对海量小文件存储难题的文件系统,用于解决自身图片存储的难题。到2007年6月,TFS(淘宝文件系 统,Taobao File System)正式上线运营。在生产环境中应用的集群规模达到了200台PC Server(146G*6 SAS 15K Raid5),文件数量达到上亿级别;系统部署存储容量: 140 TB;实际使用存储容量: 50 TB;单台支持随机IOPS 200+,流量3MBps。
淘宝集群文件系统TFS 1.0第一版的逻辑架构,TFS最大的特点就是将一部分元数据隐藏到图片的保存文件名上,大大简化了元数据,消除了管理节点对整体系统性能的制约,这一理念和目前业界流行的“对象存储”较为类似。
图为淘宝集群文件系统TFS 1.0第一版的逻辑架构:集群由一对Name Server和多台Data Server构成,Name Server的两台服务器互为双机,就是集群文件系统中管理节点的概念。
· 每个Data Server运行在一台普通的Linux主机上
· 以block文件的形式存放数据文件(一般64M一个block)
· block存多份保证数据安全
· 利用ext3文件系统存放数据文件
· 磁盘raid5做数据冗余
· 文件名内置元数据信息,用户自己保存TFS文件名与实际文件的对照关系–使得元数据量特别小。
淘宝TFS文件系统在核心设计上最大的取巧的地方就在,传统的集群系统里面元数据只有1份,通常由管理节点来管理,因而很容易成为瓶颈。而对于淘宝 网的用户来说,图片文件究竟用什么名字来保存实际上用户并不关心,因此TFS在设计规划上考虑在图片的保存文件名上暗藏了一些元数据信息,例如图片的大 小、时间、访问频次等等信息,包括所在的逻辑块号。而在元数据上,实际上保存的信息很少,因此元数据结构非常简单。仅仅只需要一个fileID,能够准确 定位文件在什么地方。
由于大量的文件信息都隐藏在文件名中,整个系统完全抛弃了传统的目录树结构,因为目录树开销最大。拿掉后,整个集群的高可扩展性极大提高。实际上, 这一设计理念和目前业界的“对象存储”较为类似,淘宝网TFS文件系统已经更新到1.3版本,在生产系统的性能已经得到验证,且不断得到了完善和优化,淘 宝网目前在对象存储领域的研究已经走在前列。
到2009年6月,TFS 1.3版本上线,集群规模大大扩展,部署到淘宝的图片生产系统上,整个系统已经从原有200台PC服务器扩增至440台PC Server(300G*12 SAS 15K RPM) + 30台PC Server (600G*12 SAS 15K RPM)。支持文件数量也扩容至百亿级别;系统部署存储容量:1800TB(1.8PB);当前实际存储容量:995TB;单台Data Server支持随机IOPS 900+,流量15MB+;目前Name Server运行的物理内存是217MB(服务器使用千兆网卡)。
TFS 1.3版本逻辑结构图
图为TFS1.3版本的逻辑结构图,在TFS1.3版本中,淘宝网的软件工作组重点改善了心跳和同步的性能,最新版本的心跳和同步在几秒钟之内就可完成切换,同时进行了一些新的优化:包括元数据存内存上,清理磁盘空间,性能上也做了优化,包括:
完全扁平化的数据组织结构,抛弃了传统文件系统的目录结构。
在块设备基础上建立自有的文件系统,减少EXT3等文件系统数据碎片带来的性能损耗
单进程管理单块磁盘的方式,摒除RAID5机制
带有HA机制的中央控制节点,在安全稳定和性能复杂度之间取得平衡。
尽量缩减元数据大小,将元数据全部加载入内存,提升访问速度。
跨机架和IDC的负载均衡和冗余安全策略。
完全平滑扩容。
在后面“图片服务器部署与缓存”一页中详细介绍了淘宝网整个图片处理系统的拓扑图。我们可以看到:TFS在淘宝的部署环境中前端有两层缓冲,到达TFS系统的请求非常离散,所以TFS内部是没有任何数据的内存缓冲的,包括传统文件系统的内存缓冲也不存在。
TFS主要的性能参数不是IO吞吐量,而是单台PCServer提供随机读写IOPS。由于大家硬件型号不同,当然也是因为一些技术保密的原因,淘 宝网很难给出一个参考值来说明性能。但基本上可以达到单块磁盘随机IOPS理论最大值的60%左右,整机的输出随盘数增加而线性增加。
TFS 2.0已经在开发过程中,主要解决的问题是大文件存储的难题。TFS最早开发的时候针对小文件频繁并发读取的难题而开发,设计的块大小是64MB,意味着每个文件小于64MB,这对于一般的图片存储来说完全足够用了,但对于大文件存储还有一些瓶颈。
TFS 2.0将重点针对大文件跨越块的存储进行优化。此外,还包括SSD、SAS硬盘不同硬盘特性的应用优化。根据淘宝网的资料数据,SSD的存储成本大约是 20¥每GB左右,SAS硬盘的存储成本约在 5-6¥每GB,SATA盘的每GB成本不到1¥。随着对应用性能的要求提升,应用SSD是未来的趋势,针对不同硬盘的存取特性进行优化是十分必要的。
下图为淘宝网整体系统的拓扑图结构。整个系统就像一个庞大的服务器一样,有处理单元、缓存单元和存储单元。前面已经详细介绍过了后台的TFS集群文件存储系统,在TFS前端,还部署着200多台图片文件服务器,用Apatch实现,用于生成缩略图的运算。
这里需要补充一点,根据淘宝网的缩略图生成规则,缩略图都是实时生成的。这样做的好处有两点:一是为了避免后端图片服务器上存储的图片数量过多,大 大节约后台存储空间的需求,淘宝网计算,采用实时生成缩略图的模式比提前全部生成好缩略图的模式节约90%的存储空间,也就是说,存储空间只需要后一种模 式的10%;二是,缩略图可根据需要实时生成出来,更为灵活。
淘宝网图片存储与处理系统全局拓扑,图片服务器前端还有一级和二级缓存服务器,尽量让图片在缓存中命中,最大程度的避免图片热点,实际上后端到达TFS的流量已经非常离散和平均
图片文件服务器的前端则是一级缓存和二级缓存,前面还有全局负载均衡的设置,解决图片的访问热点问题。图片的访问热点一定存在,重要的是,让图片尽 量在缓存中命中。目前淘宝网在各个运营商的中心点设有二级缓存,整体系统中心店设有一级缓存,加上全局负载均衡,传递到后端TFS的流量就已经非常均衡和 分散了,对前端的响应性能也大大提高。
根据淘宝的缓存策略,大部分图片都尽量在缓存中命中,如果缓存中无法命中,则会在本地服务器上查找是否存有原图,并根据原图生成缩略图,如果都没有命中,则会考虑去后台TFS集群文件存储系统上调取,因此,最终反馈到TFS集群文件存储系统上的流量已经被大大优化了。
淘宝网将图片处理与缓存编写成基于Nginx的模块,淘宝网认为Nginx是目前性能最高的HTTP服务器(用户空间),代码清晰,模块化非常好。 淘宝网使用GraphicsMagick进行图片处理,采用了面向小对象的缓存文件系统,前端有LVS+Haproxy将原图和其所有缩略图请求都调度到 同一台Image Server。
文件定位上,内存用hash算法做索引,最多一次读盘。写盘方式则采用Append方式写,并采用了淘汰策略FIFO,主要考虑降低硬盘的写操作,没有必要进一步提高Cache命中率,因为Image Server和TFS在同一个数据中心,读盘效率还是非常高的。