高效存储数亿个小文件。 自托管解决方案

高效存储数亿个小文件。 自托管解决方案

亲爱的社区,本文将重点讨论如何有效地存储和检索数亿个小文件。 现阶段,最终的解决方案是针对 POSIX 兼容的文件系统提出的,完全支持锁,包括集群锁,而且看起来甚至不需要拐杖。

所以我为此目的编写了自己的自定义服务器。
在实现这个任务的过程中,我们成功地解决了主要问题,同时节省了磁盘空间和RAM,而我们的集群文件系统无情地消耗了磁盘空间和RAM。 实际上,如此多的文件对于任何集群文件系统都是有害的。

这个想法是这样的:

简单来说,小文件通过服务器上传,直接保存到存档中,也可以从中读取,大文件并排放置。 方案:1个文件夹=1个档案,总共有几百万个小文件档案,而不是几亿个文件。 所有这一切都是完全实现的,无需任何脚本或将文件放入 tar/zip 存档中。

我会尽量保持简短,如果帖子很长,我提前道歉。

这一切都始于这样一个事实:我在世界上找不到合适的服务器,可以将通过 HTTP 协议接收的数据直接保存到档案中,而没有传统档案和对象存储固有的缺点。 而搜索的原因是由10台服务器组成的Origin集群已经发展到了相当大的规模,其中已经积累了250,000,000亿个小文件,而且增长的趋势还没有停止。

对于那些不喜欢阅读文章的人来说,一些文档会更容易:

这里 и 这里.

同时还有 docker,现在有一个选项仅包含 nginx,以防万一:

docker run -d --restart=always -e host=localhost -e root=/var/storage 
-v /var/storage:/var/storage --name wzd -p 80:80 eltaline/wzd

下一篇:

如果有很多文件,则需要大量资源,最糟糕的是其中一些资源被浪费了。 例如,当使用集群文件系统(在本例中为 MooseFS)时,无论文件的实际大小如何,它始终至少占用 64 KB。 也就是说,对于大小为 3、10 或 30 KB 的文件,磁盘上需要 64 KB。 如果有 2 亿个文件,我们就会丢失 10 到 1 TB。 不可能无限期地创建新文件,因为 MooseFS 有一个限制:每个文件的一个副本不能超过 XNUMX 亿个文件。

随着文件数量的增加,元数据需要大量 RAM。 频繁的大型元数据转储也会导致 SSD 驱动器的磨损。

wZD 服务器。 我们把东西按顺序放在磁盘上。

服务器是用 Go 编写的。 首先,我需要减少文件数量。 怎么做? 由于存档,但在这种情况下没有压缩,因为我的文件只是压缩图片。 BoltDB 来救援,但它的缺点仍然需要消除,这在文档中得到了反映。

总的来说,在我的例子中,Bolt 档案只剩下 10 万个,而不是 1 亿个。 如果我有机会改变当前的目录文件结构,就有可能将其减少到大约 XNUMX 万个文件。

所有小文件都打包到 Bolt 存档中,Bolt 存档会自动接收它们所在目录的名称,所有大文件都保留在存档旁边;打包它们没有意义,这是可定制的。 小的被存档,大的保持不变。 服务器与两者透明地工作。

wZD 服务器的架构和功能。

高效存储数亿个小文件。 自托管解决方案

该服务器在 Linux、BSD、Solaris 和 OSX 操作系统下运行。 我只在 Linux 下测试了 AMD64 架构,但它应该适用于 ARM64、PPC64、MIPS64。

主要特点:

  • 多线程;
  • 多服务器,提供容错和负载均衡;
  • 为用户或开发者提供最大的透明度;
  • 支持的 HTTP 方法:GET、HEAD、PUT 和 DELETE;
  • 通过客户端标头管理读写行为;
  • 支持高度可配置的虚拟主机;
  • 读写时支持CRC数据完整性;
  • 半动态缓冲区可实现最小内存消耗和最佳网络性能调整;
  • 延迟数据压缩;
  • 此外,还提供多线程归档程序 wZA,用于在不停止服务的情况下迁移文件。

真实体验:

我已经在实时数据上开发和测试服务器和存档器很长时间了,现在它可以在一个集群上成功运行,该集群包含位于单独 SATA 驱动器上 250,000,000 个目录中的 15,000,000 个小文件(图片)。 由 10 台服务器组成的集群是安装在 CDN 网络后面的源服务器。 为了提供服务,使用了 2 个 Nginx 服务器 + 2 个 wZD 服务器。

对于那些决定使用此服务器的人来说,明智的做法是在使用之前规划好目录结构(如果适用)。 让我立即做出保留,服务器并不打算将所有内容都塞进 1 Bolt 存档中。

性能测试:

压缩文件的大小越小,对其执行 GET 和 PUT 操作的速度就越快。 让我们比较一下 HTTP 客户端写入常规文件和 Bolt 档案以及读取的总时间。 对大小为 32 KB、256 KB、1024 KB、4096 KB 和 32768 KB 的文件进行了比较。

使用 Bolt 档案时,会检查每个文件的数据完整性(使用 CRC),在记录之前和记录之后,会发生即时读取和重新计算,这自然会带来延迟,但最主要的是数据安全。

我在 SSD 驱动器上进行了性能测试,因为在 SATA 驱动器上的测试没有显示出明显的差异。

根据测试结果绘制图表:

高效存储数亿个小文件。 自托管解决方案
高效存储数亿个小文件。 自托管解决方案

正如您所看到的,对于小文件,归档文件和非归档文件之间的读写时间差异很小。

当测试读取和写入 32 MB 大小的文件时,我们得到了完全不同的情况:

高效存储数亿个小文件。 自托管解决方案

读取文件的时间差在5-25ms以内。 如果进行录音,情况会更糟,差异约为 150 毫秒。 但在这种情况下,不需要上传大文件;这样做根本没有意义;它们可以与档案分开保存。

*从技术上讲,您可以使用此服务器来执行需要 NoSQL 的任务。

使用wZD服务器的基本方法:

加载常规文件:

curl -X PUT --data-binary @test.jpg http://localhost/test/test.jpg

将文件上传到 Bolt 存档(如果未超过服务器参数 fmaxsize,该参数决定存档中可以包含的最大文件大小;如果超过,则文件将照常上传到存档旁边):

curl -X PUT -H "Archive: 1" --data-binary @test.jpg http://localhost/test/test.jpg

下载文件(如果磁盘上和存档中存在同名文件,则下载时默认优先下载未存档的文件):

curl -o test.jpg http://localhost/test/test.jpg

从 Bolt 存档下载文件(强制):

curl -o test.jpg -H "FromArchive: 1" http://localhost/test/test.jpg

其他方法的描述在文档中。

wZD 文档
wZA 文档

服务器目前仅支持 HTTP 协议;尚不支持 HTTPS。 也不支持POST方法(尚未决定是否需要)。

谁深入源码就会发现那里有奶油糖,不是每个人都喜欢它,但我没有将主要代码与Web框架的功能绑定在一起,除了中断处理程序,所以将来我可以快速重写它以适应几乎任何引擎。

TODO:

  • 开发您自己的复制器和分发器 + geo,以便在没有集群文件系统的大型系统中使用的可能性(成人的一切)
  • 如果元数据完全丢失,则可以完全反向恢复元数据(如果使用分发器)
  • 本机协议能够使用持久网络连接和不同编程语言的驱动程序
  • 使用 NoSQL 组件的高级可能性
  • 对 Bolt 档案内的文件或值以及常规文件进行不同类型的压缩(gzip、zstd、snappy)
  • 对 Bolt 档案内的文件或值以及常规文件进行不同类型的加密
  • 服务器端视频转换延迟,包括 GPU 上的视频转换

我拥有一切,我希望这个服务器对某人有用,BSD-3许可证,双重版权,因为如果没有我工作的公司,服务器就不会被编写。 我是唯一的开发者。 对于您发现的任何错误和功能请求,我将不胜感激。

来源: habr.com

添加评论