FastDFS是一款开源的轻量级分布式文件系统、纯C实现,支持Linux, FreeBSD等UNIX系统类google FS, 不是通用的文件系统,只能够通过专有API访问,目前提供了C,Java和PHP API为互联网应用量身定做,解决大容量文件存储问题,追求高性能和高扩展性。
FastDFS可以看做是基于文件的key-value存储系统,称为分布式文件存储服务更为合适。
FastDFS提供的功能
upload 上传文件
download 下载文件
delete 删除文件
心得:一个合适的(不需要选择最复杂的,而是最满足自己的需求。复杂的自己因为理解问题,导致无法掌控。当在出现一些突发性问题时,因为无法及时解决导致灾难性的后果)文件系统需要符合什么样的哲学,或者说应该使用什么样的设计理念?
一个好的分布式文件系统最好提供Nginx的模块,因为对于互联网应用来说,象文件这种静态资源,一般是通过HTTP的下载,此时通过容易扩展的Nginx来访问Fastdfs,能够让文件的上传和下载变得特别简单。另外,网站型应用在互联网领域中的比例是非常高,因此PHP这种语言作为非常成熟,性能也完全能够让人满意的网站开发语言,提供相应的扩展,也是非常重要的。所以在应用领域上,Fastdfs是非常合适的。
文件系统天生是静态资源,因此象可修改或者可追加的文件看起来就没有太大的意义了。文件属性也最好不要支持,因为可以通过文件扩展名和尺寸等属性,通过附加在文件名称上,来避免出现存储属性的信息。另外,通过添加属性支持,还不如用其他的东西, 例如redis等来支持,以避免让此分布式文件系统变得非常复杂。
之所以说FastDFS简单,在于其架构中,只有两种角色,一个是storage, 一个是tracker。但从实现上讲,实际上有三个模块:tracker, storage和fastdfs client。fastdfs纯粹是协议的解析,以及一些简单的策略。关键还是在于tracker和storage。
在设计FastDFS时,除了如上的哲学外,很重要的就是上传,下载,以及删除。以及如何实现同步,以便实现真正的分布式,否则的话这样和普通的单机文件系统就没有什么区别了。
如果是我们自己来设计一下分布式的文件系统,如果我们要上传。那么,必然要面临着下面的一些选择:
上传到哪里去?难道由客户端来指定上传的服务器吗?
只上传一台服务器够吗?
上传后是原样保存吗?(chunk server比较危险,没有把握不要去做)
对于多IDC如何考虑?
对于使用者来说,当需要上传文件的时候,他/她关心什么?
1- 上传的文件必须真实地保留着,不能够有任何的加工。虽然chunk server之类的看起来不错,但是对于中小型组织来说,一旦因为一些技术性的bug,会导致chunk server破坏掉原来的文件内容,风险比较大
2- 上传成功后,能够立马返回文件名称,并根据文件名称马上完整地下载。原始文件名称我们不关心(如果需要关心,例如象论坛的附件,可以在数据库中保存这些信息,而不应该交给DFS来处理)。这样的好处在于DFS能够更加灵活和高效,例如可以在文件名称中加入很多的附属信息,例如图片的尺寸等。
3- 上传后的文件不能够是单点,一定要有备份,以防止文件丢失
4- 对于一些热点文件,希望能够做到保证尽可能快速地大量访问
上面的需求其实是比较简单的。首先让我们回到最原始的时代,即磁盘来保存文件。在这个时代,当我们需要管理文件的时候,通常我们都是在单机的磁盘上创建一个目录,然后在此目录下面存放文件。因为用户往往文件名称是很随意的,所以使用用户指定的文件名称可能会错误地覆盖其他的文件。因此,在处理的时候,绝对不能够使用用户指定的名称,这是分析后得到的第一个结论。
如果用户上传文件后,分配一个文件名称(具体文件名称的分配策略以后再考虑),那么如果所有的文件都存储在同一个目录下面,在做目录项的遍历时将非常麻烦。根据网上的资料,一般单目录下的文件个数一般限制不能够超过3万;同样的,一个目录下面的目录数也最好不要超过这个数。但实际上,为了安全考虑,一般都不要存储这么多的内容。假定,一个目录下面,存储1000个文件,每个文件的平均大小为10KB,则单目录下面可存储的容量是10MB。这个容量太小了,所以我们要多个目录,假定有1000个目录,每个目录存储10MB,则可以存储10GB的内容;这对于目前磁盘的容量来说,利用率还是不够的。我们再想办法,转成两级目录,这样的话,就是第一层目录有1000个子目录,每一级子目录下面又有1000级的二级子目录,每个二级子目录,可以存储10MB的内容,此时就可以存储10T的内容,这基本上超过了目前单机磁盘的容量大小了。所以,使用二级子目录的办法,是平衡存储性能和利用存储容量的办法。
这样子的话,就回到了上面的问题,如果我们开始只做一个单机版的基于文件系统的存储服务,假如提供TCP的服务(不基于HTTP,因为HTTP的负载比太低)。很简单,客户端需要知道存储服务器的地址和端口。然后,指定要上传的文件内容;服务器收到了文件内容后,如何选择要存储在哪个目录下呢?这个选择要保证均衡性,即尽量保证文件能够均匀地分散在所有的目录下。
负载均衡性很重要的就是哈希,例如,在PHP中常用的md5,其返回一个32个字符,即16字节的输出,即128位。哈希后要变成桶,才能够分布,自然就有了如下的问题:
1- 如何得到哈希值?md5还是SHA1
2- 哈希值得到后,如何构造哈希桶
3- 根据文件名称如何定位哈希桶
首先来回答第3个问题,根据文件名称如何定位哈希桶。很简单,此时我们只有一个文件名称作为输入,首先要计算哈希值,只有一个办法了,就是根据文件名称来得到哈希值。这个函数可以用整个文件名称作为哈希的输入,也可以根据文件名称的一部分来完成。结合上面说的两级目录,而且每级目录不要超过1000.很简单,如果用32位的字符输出后,可以取出实现上来说,由于文件上传是防止唯一性,所以如果根据文件内容来产生哈希,则比较好的办法就是截取其中的4位,例如:
md5sum fdfs_storaged.pid
52edc4a5890adc59cec82cb60f8af691 fdfs_storaged.pid