MinIO 中的小文件归档

Small File Archives in MinIO

MinIO RELEASE.2021-06-14 添加了一个“s3zip”扩展,允许从 ZIP 存档中下载单个文件。我们将探讨与下载普通对象相比,使用此功能的用例,并说明如何使用它。

背景

我们之前已经描述了 MinIO 如何在内部优化 小对象。但是,在内部存储单个对象仍然会带来文件系统限制,例如较慢的列出和最小块大小。

通过反馈,我们发现,在某些情况下,希望能够引用小数据段而无需完整的单个对象功能集。为了使其尽可能易于使用,我们添加了 ZIP 文件索引。

此功能允许检索上传到 MinIO 的 ZIP 文件中的单个文件。使用此功能,可以上传包含数千个文件的单个 ZIP 文件。然后,MinIO 索引工具 确保可以以与单个对象相同的性能访问 ZIP 文件中的文件。所有这些操作都是透明的。

ZIP 文件在大多数开发平台上都是众所周知的并且得到良好支持,并且具有完善的可用工具。在大多数语言中,ZIP 格式允许流式写入,因此在创建存档时不需要所有数据都存储在内存中。我们选择了一种常用格式而不是自定义格式,因为它提供了我们需要的功能。其他格式(如 TAR)不满足此要求,因此我们预计不会实现其他格式。

用例

此功能的主要目标是允许快速上传大量不会更改的小数据片段,并允许快速下载单个文件。这也有额外的好处,即占用更少的空间,因为所有数据都存储为单个文件。

一个主要的用例可能是需要按用户基础进行访问的每周/每天/每小时报告。您可能有一个数据湖,您可以在其中存储要分析的文件的 ZIP 存档。文件名将是您想要执行查找操作的 ID。对于普通对象,这将为每个用户每个间隔创建一个对象。相反,给定时间间隔的所有内容都可以上传,并且可以通过 ID 访问单个记录。

无法更新 ZIP 文件中的单个文件。因此,这应该仅用于预计不会更改的数据。如果覆盖 ZIP 文件,则所有文件将同时原子替换。如果知道要修改 ZIP 文件的内容,则不要使用 ZIP 文件,而是将文件保存为普通对象。

ZIP 文件中的文件没有单独的元数据,只有名称和大小。修改时间继承自父 ZIP 对象。这意味着,ILM 规则保留 适用于整个 ZIP 对象。

ZIP 压缩是次要的,通常建议将 ZIP 文件中的文件保持未压缩状态。这可以在压缩文件时设置。单个文件可以存储为未压缩或使用 deflate 压缩。

存档的大小(以字节为单位)对检索单个文件的响应能力几乎没有影响。为了保持单个请求的响应能力,建议将每个 ZIP 文件中的单个文件数量保持在 100,000 个以下。如果您计划超过此数量,建议将您的输入拆分为多个文件,每个文件目标为 10,000 个文件。

基准测试表明,对于包含 10,000 个文件的 ZIP 文件,每次访问大约需要 1 毫秒。这是线性扩展的,因此,对于 100,000 个文件,假设 CPU 资源可用,每次操作应该额外增加 10 毫秒。

基本用法

对现有 S3 API 的扩展使得可以使用索引的 ZIP 文件。为了确保不会出现任何意外的副作用,所有使用都受到必须存在以启用新功能的标头的保护。要启用扩展,标头 x-minio-extract 的值必须设置为 true

以下 API 请求类型支持 s3zip 扩展:HeadObjectGetObjectListObjectsV2。这将允许列出存档中的文件并检索它们。

ZIP 文件中的文件引用为 /prefix/file.zip/path-in-zip/file.ext。ZIP 文件必须具有 zip 扩展名,并且 ZIP 文件中的路径用于引用每个文件。

例如,要列出上传为 prefix/file.zip 的文件中所有文件,请使用 GetObject 并设置前缀 prefix/file.zip/。请注意,正斜杠指示 ZIP 文件中的内容。前缀、标记和分隔符按常规 ListObjectsV2 调用操作。

上传文件

上传文件通过常规函数完成。上传文件不需要任何特殊操作,只是对象键必须以 .zip 结尾。

要触发上传时的立即索引,可以通过将 x-minio-extract 标头设置为 true 来触发它。如果没有设置,索引将由上面提到的第一个检索或列出 ZIP 文件中文件的请求创建。

完全支持 Zip64(大于 4GB 的 ZIP 文件)。不支持使用 zip 加密的 ZIP 文件。

支持 Unicode 名称,应使用 UTF-8 编码。但是,确实存在依赖于本地代码页才能工作的非兼容压缩器。如果您计划使用 Unicode 名称,请检查文件名是否正确解码。通常建议坚持使用通用的 对象键命名指南

列出文件

常规列出操作将返回 ZIP 文件作为普通对象。

要列出 ZIP 文件的内容,请发送包含 ZIP 文件作为前缀和上面描述的标头的前缀。例如 prefix/file.zip/ 将列出具有键 prefix/file.zip 的 ZIP 文件的所有内容。支持常规 ListObjectV2 参数,如附加前缀、标记和分隔符。

例如,使用前缀 = prefix/file.zip/folder/,分隔符 = / 将仅列出指定文件夹中的内容。

为了降低复杂性,实施了一些限制:必须使用 ListObjectV2。每次调用只能列出单个 ZIP 文件,并且只能列出 ZIP 文件的最新版本。

下载单个文件

如上所述,访问单个文件需要一个标头和一个路径来指示 ZIP 文件和其中的文件。要获取路径,可以使用 ListObjectsV2。还可以通过手动组合对象路径和 ZIP 文件中的路径来构造对象名称。

有关如何下载文件的示例…

单个文件被视为单个请求处理。这将以与单独对象相同的速度生成单个文件。如果您需要访问存档中的许多文件的内容,则下载整个 ZIP 存档并在本地对其进行处理会更快。

MC 支持

mc RELEASE.2022-02-16 添加了对远程访问 ZIP 文件中的文件的支持。具体来说,ls、cp 和 cat 命令支持源为远程 ZIP 文件的操作。这些命令有一个“--zip”参数,用于指示您打算对 ZIP 文件执行操作。

要列出 ZIP 文件中的所有文件,请使用

λ mc ls --zip -–recursive play/test/test.zip/

这将列出所有文件作为普通对象。也可以列出单个文件夹

λ mc ls --zip play/test/test.zip/folder/

…将列出文件夹中的所有文件和文件夹。

可以使用 cp 命令提取文件

λ mc cp --zip play/test/test.zip/file.txt

也可以从文件夹中递归提取文件,使用常规语法

λ mc cp --zip —-recursive play/test/test.zip/folder/ ./extracted/

最后,可以显示 ZIP 文件中的单个文件

λ mc cat --zip play/test/test.zip/file.txt

这仅在远程服务器为在分布式或单驱动器单磁盘模式下运行的 MinIO 服务器时有效。

结论

s3zip 功能允许您以紧凑的方式存储许多小的单个文件。这可以替代许多单个对象,这将减少存储开销和 ILM 等操作的处理时间。

与任何扩展一样,通常的注意事项适用。虽然从技术上讲,可以使用本地索引和使用 HTTP 范围请求来提供类似的功能,而无需任何服务器端支持,但这需要大量的努力,而且结果不会像我们使用扩展所实现的那样简化。

出于归档目的,此扩展通过 mc 命令界面提供了更节省空间和带宽的方法来检索很少访问的存档数据。这可以是存储仅偶尔需要访问的日志数据的有效方法。它可以用于快速上传多个数据片段,这些片段需要通过 ID 进行快速访问。

考虑具有 userid -> json 映射的每日用户统计信息。使用普通对象时,这可以实现为 yyyy/mm/dd/user_id/file.json 对象命名。这将需要每天为每个用户上传一个对象。

相反,可以每天创建一个 ZIP 文件,并且可以通过读取 yyyy-mm-dd.zip/user_id.json 来查找用户统计信息,这将更快上传、维护并且占用更少的空间,所有这些对于在数据湖中工作都是好事。

如果用户很多,使用确定性拆分方法,例如 yyyy-mm-dd/user0-10000.zip/user_id.json 将允许扩展到数十亿用户,并且对象数量减少 5 个数量级。

使用 MinIO 在 ZIP 文件中搜索 ZIP 文件

下载 MinIO 并利用能够从 ZIP 文件中列出和下载单个文件的功能。如果您有任何问题,或者想告诉我们您使用 MinIO 构建的出色应用程序,请访问 hello@min.io 或加入 Slack 社区