阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

FastDFS 分布式系统需求分析

475次阅读
没有评论

共计 5640 个字符,预计需要花费 15 分钟才能阅读完成。

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


上面,这个 fdfs_storage.pid 中,取出最前面的 4 个字符,即 52 和 ed。这样的话,假如 52 是一级目录的名称,ed 是二级目录的名称。因为每一个字符有 16 个取值,所以第一级目录就有 16 * 16 = 256 个。总共就有 256 * 256 = 65526 个目录。如果每个目录下面存放 1000 个文件,每个文件 30KB,都可以有 1966G,即 2TB 左右。这样的话,足够我们用好。如果用三个字符,即 52e 作为一级目录,dc4 作为二级目录,这样子的目录数有 4096,太多了。所以,取二个字符比较好。

这样的话,上面的第 2 和第 3 个问题就解决了,根据文件名称来得到 md5,然后取 4 个字符,前面的 2 个字符作为一级目录名称,后面的 2 个字符作为二级目录的名称。服务器上,使用一个专门的目录来作为我们的存储根目录,然后下面建立这么多子目录,自然就很简单了。

这些目录可以在初始化的时候创建出来,而不用在存储文件的时候才建立。

也许你会问,一个目录应该不够吧,实际上很多的廉价机器一般都配置 2 块硬盘,一块是操作系统盘,一块是数据盘。然后这个数据盘挂在一个目录下面,以这个目录作为我们的存储根目录就好了。这样也可以很大程度上减少运维的难度。

现在就剩下最后一个问题了,就是上传文件时候,如何分配一个唯一的文件名称,避免同以前的文件产生覆盖。

如果没有变量作为输入,很显然,只能够采用类似于计数器的方式,即一个 counter,每次加一个文件就增量。但这样的方式会要求维护一个持久化的 counter,这样比较麻烦。最好不要有历史状态的纪录。

string md5 (string $str [, bool $raw_output = false] )
Calculates the MD5 hash of str using the » RSA Data Security, Inc. MD5 Message-Digest Algorithm, and returns that hash.

raw_output
If the optional raw_output is set to TRUE, then the md5 digest is instead returned in raw binary format with a length of 16.
Return Values 

Returns the hash as a 32-character hexadecimal number.

为了尽可能地生成唯一的文件名称,可以使用文件长度(假如是 100MB 的话,相应的整型可能会是 4 个字节,即不超过 2^32, 即 uint32_t,只要程序代码中检查一下即可)。但是长度并不能够保证唯一,为了填充尽可能有用的信息,CRC32 也是很重要的,这样下载程序后,不用做额外的交互就可以知道文件的内容是否正确。一旦发现有问题,立马要报警,并且想办法修复。这样的话,上传的时候也要注意带上 CRC32,以防止在网络传输和实际的硬盘存储过程中出现问题(文件的完整性至关重要)。再加上时间戳,即 long 型的 64 位,8 个字节。最后再加上计数器,因为这个计数器由 storage 提供,这样的话,整个结构就是:len + crc32 + timestamp + uint32_t = 4 + 4 + 8 + 4 = 20 个字节,这样生成的文件名就算做 base64 计算出来,也就不是什么大问题了。而且,加上计数器,每秒内只要单机不上传超过 1 万的文件,就都不是问题了。这个还是非常好解决的。

 
【文件长度 +CRC32+TimeStamp+Counter】

// TODO 如何避免文件重复上传?md5 吗?还是文件的计算可以避免此问题?这个信息存储在 tracker 服务器中吗?
FastDFS 中给我们一个非常好的例子,请参考下面的代码:

// 参考 FastDFS 的文件名称生成算法

/**
1 byte: store path index
8 bytes: file size 
FDFS_FILE_EXT_NAME_MAX_LEN bytes: file ext name, do not include dot (.)
file size bytes: file content
**/
static int storage_upload_file(struct fast_task_info *pTask, bool bAppenderFile)
 
根据上面分析的结果,我们看到,当上传一个文件的时候,我们会获取到如下的信息
1- 文件的大小(通过协议中包的长度字段可以知道,这样的好处在于服务端实现的时候简单,不用过于担心网络缓冲区的问题)
2- CRC32(也是协议包中传输,以便确定网络传输是否出错)
3- 时间戳(获取服务器的当前时间)
4- 计数器(服务器自己维护)

根据上面的 4 个数据,组织成 base64 的编码,然后生成此文件名称。根据此文件名称的唯一性,就不会出现被覆盖的情况。同时,唯一性也使得接下来做 md5 运算后,得到的 HASH 值离散性得么保证。得到了 MD5 的哈希值后,取出最前面的 2 部分,就可以知道要定位到哪个目录下面去。哈希桶的构造是固定的,即二级 00-ff 的目录情况。
 
补充说明 Base64 编码

Base64 编码要求把 3 个 8 位字节(3*8=24)转化为 4 个 6 位的字节(4*6=24),之后在 6 位的前面补两个 0,形成 8 位一个字节的形式。如果剩下的字符不足 3 个字节,则用 0 填充,输出字符使用 ’=’,因此编码后输出的文本末尾可能会出现 1 或 2 个 ’=’。

为了保证所输出的编码位可读字符,Base64 制定了一个编码表,以便进行统一转换。编码表的大小为 2^6=64,这也是 Base64 名称的由来。

Base64 编码表

码值 字符
 
码值 字符
 
码值 字符
 
码值 字符
0 A 16 Q 32 g 48 w
1 B 17 R 33 h 49 x
2 C 18 S 34 i 50 y
3 D 19 T 35 j 51 z
4 E 20 U 36 k 52 0
5 F 21 V 37 l 53 1
6 G 22 W 38 m 54 2
7 H 23 X 39 n 55 3
8 I 24 Y 40 o 56 4
9 J 25 Z 41 p 57 5
10 K 26 a 42 q 58 6
11 L 27 b 43 r 59 7
12 M 28 c 44 s 60 8
13 N 29 d 45 t 61 9
14 O 30 e 46 u 62 +
15 P 31 f 47 v 63 /


标准的 Base64 并不适合直接放在 URL 里传输,因为 URL 编码器会把标准 Base64 中的“/”和“+”字符变为形如“%XX”的形式,而这些“%”号在存入数据库时还需要再进行转换,因为 ANSI SQL 中已将“%”号用作通配符。
改进 Base64 编码,它不仅在末尾填充 ’=’ 号,并将标准 Base64 中的“+”和“/”分别改成了“-”和“_”,这样就免去了在 URL 编解码和数据库存储时所要作的转换。
 

Base64 的原理很简单,首先,准备一个包含 64 个字符的数组:

['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/'] 就是上面那张表格

然后,对二进制数据进行处理,每 3 个字节一组,一共是3x8=24bit,划为 4 组,每组正好 6 个 bit(这样子 2^6 才能查表)

 

FastDFS 分布式系统需求分析

 

这样我们得到 4 个数字作为索引,然后查表,获得相应的 4 个字符,就是编码后的字符串。

所以,Base64 编码会把 3 字节的二进制数据编码为 4 字节的文本数据,长度增加 33%,好处是编码后的文本数据可以在邮件正文、网页等直接显示。

如果要编码的二进制数据不是 3 的倍数,最后会剩下 1 个或 2 个字节怎么办?Base64 用 \x00 字节在末尾补足后,再在编码的末尾加上 1 个或 2 个 = 号,表示补了多少字节,解码的时候,会自动去掉。

本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-09/134991.htm

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-21发表,共计5640字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19350
评论数
4
阅读量
7968470
文章搜索
热门文章
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
我用AI做了一个1978年至2019年中国大陆企业注册的查询网站

我用AI做了一个1978年至2019年中国大陆企业注册的查询网站

我用 AI 做了一个 1978 年至 2019 年中国大陆企业注册的查询网站 最近星哥在 GitHub 上偶然...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
终于收到了以女儿为原型打印的3D玩偶了

终于收到了以女儿为原型打印的3D玩偶了

终于收到了以女儿为原型打印的 3D 玩偶了 前些日子参加某网站活动,获得一次实物 3D 打印的机会,于是从众多...
恶意团伙利用 PHP-FPM 未授权访问漏洞发起大规模攻击

恶意团伙利用 PHP-FPM 未授权访问漏洞发起大规模攻击

恶意团伙利用 PHP-FPM 未授权访问漏洞发起大规模攻击 PHP-FPM(FastCGl Process M...
多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞定

多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞定

多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地

把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地

把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地 大家好,我是星哥,今天教大家在飞牛 NA...
手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板 前言 大家好,我是星哥。星哥发现很多新手刚接触服务器时,都会被“选购...
300元就能买到的”小钢炮”?惠普7L四盘位小主机解析

300元就能买到的”小钢炮”?惠普7L四盘位小主机解析

  300 元就能买到的 ” 小钢炮 ”?惠普 7L 四盘位小主机解析 最近...
星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定!

星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定!

星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定! 前言 作为 NAS 玩家,你是否总被这些...
多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞定

多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞定

多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞...