许多供应商在其存储解决方案中提供压缩和重复数据删除功能。我们通过考察这两种减少原始磁盘使用的方法,对这些说法进行了严格的评估。
压缩概述
总的来说,压缩通过减少上传数据的冗余来实现其优势。这意味着重复或其他可预测的数据可以缩减尺寸。随着数据作为流传入,先前的数据可以作为上下文用作参考。如果传入数据未使用所有字节值(0->255)以相等的量,这也可用于实现通常较小的压缩增益。
压缩挑战
压缩的速度对于所有操作至关重要。这意味着压缩和解压缩速度。如果其中任何一个受到限制,这将是一个足以让人们不希望压缩的问题,即使它节省了一些空间。因此,所有压缩算法都是速度和效率之间的权衡。
压缩效率通常会接近“最大值”,此时增益在计算方面非常昂贵。没有“从中间开始”的压缩方法能够神奇地提高压缩率。在大多数情况下,可以使用具有某种先验数据知识的特定于领域的算法来提高压缩率。但在大多数情况下,应用程序已经利用了这一点并在输出数据时应用了它。
需要记住的第二件事是查找。与 S3 兼容的对象存储必须支持查找,以满足从对象内部开始的 HTTP 范围请求。对于几乎所有压缩算法,查找必须单独处理。压缩数据的流在大多数情况下不可查找,有些必须从第一个字节到第一个请求字节完全读取和解压缩。这意味着为了实现高效的查找,输入必须被分割成单独的块。

进行独立的块意味着上下文必须在每个块之间重置,并且需要保留每个块的索引。这些都将降低可能的最大压缩率。
重复数据删除
重复数据删除听起来非常像压缩,但它在更高的级别上运行,并对更大的数据块进行重复数据删除,通常跨越整个命名空间。
重复数据删除将输入分成块,为每个块创建散列。如果它再次遇到具有相同散列的块,它只是插入对先前块的引用。如果您考虑一个输入,它看起来会像这样

虽然这听起来像普通的压缩,但它有一些关键的区别。首先,只检查完整的块。在像 deflate、snappy 等压缩中,您正在寻找每个单独字节的匹配项,在一个有限的窗口内,例如 32KB-1MB。重复数据删除将在千兆字节甚至太字节的数据上运行。
实际上,每个块都通过散列函数运行,该函数提供了一个足够强的散列,以至于您不期望它容易受到冲突的影响。然后将每个块写入磁盘,以便可以通过其散列值找到它。
因此,对象流是一串散列
[xxxx][yyyy][zzzz][vvvv][wwww]...
要读取回数据,然后按顺序检索每个块并返回。由于块是唯一的,因此它们可以在不同的对象之间共享。这意味着如果多次上传相同的数据,它只需要为第二次上传存储散列,因为数据已经包含在磁盘上的块中。
重复数据删除挑战
重复数据删除有一些挑战。一个主要的挑战是读取和写入将始终被拆分成更小的块。这意味着旋转磁盘从顺序读/写速度变为随机 IO 速度。通常,随机读取和顺序读取之间的差异大约是一个数量级,加上在底层存在文件系统时打开每个文件所需的时间。

块大小之间存在效率的权衡。较小的块允许对只有少量差异的数据进行更多匹配 - 但会导致较小的 IO 操作,并且流传输将远低于硬件所能提供的水平。令人惊讶的是,即使对于 NVME 驱动器,每次唯一写入也存在开销。每个块还会产生固定的散列大小开销 - 通常至少为 32 字节。
第二个主要障碍是重复数据删除需要跟踪对每个块的引用。这可以通过多种方式完成,但所有方法都需要一个数据库来保存引用并维护锁,以便在进行删除操作时新对象无法引用它们。
无论哪种方式,都需要昂贵的维护工作 - 并且删除操作会扩展成许多单独的操作,以便实际清除数据。通常,基准测试会忽略此清理操作,因此只有在系统部署后很长时间才能发现它。
最后,重复数据删除会导致潜在的数据泄漏。重复数据删除的本质是允许您将已上传的数据与任意数据进行比较。它需要非常仔细的工程设计,才能不泄漏关于数据块是否经过重复数据删除的信息。验证这一点是否属实需要非常仔细的审核。
压缩 + 重复数据删除
将压缩和重复数据删除结合起来会带来有趣的挑战。
首先,重复数据删除强制执行固定的压缩块大小。对重复数据删除的块的压缩不能引用先前的数据,因为这将对于每个块都是不同的。这意味着压缩将仅限于在重复数据删除的块内进行压缩。然而,这类似于查找所需的索引。
由于重复数据删除的块也是独立存储的,这也意味着,在几乎所有情况下,压缩块的输出大小可变都会导致每个块的存储效率低下,通常会将输出大小向上舍入到最接近的 4KB 大小,实际上会浪费每个块的存储空间。如果块紧密打包,这会导致非常分散的清理操作,随着时间的推移,性能会显著下降。
这意味着,为了实现有效的压缩,重复数据删除的块必须足够大,以避免在存储时产生过高的开销。这意味着,实际上,重复数据删除只会对完全重复的数据或在其他文件中具有相同块偏移量的较大块进行重复数据删除。实际上,这意味着只有完全重复的数据才会被重复数据删除。
重复数据删除 + 加密
使用重复数据删除对数据进行加密会带来新的挑战。首先,我们需要比较传入的数据是否与磁盘上加密的数据相匹配。这将始终损害安全性。
首先,拥有未加密数据的散列是一个很大的禁忌,因为您泄露了有关存储数据的的信息。虽然我们无法确定,但我们不认为有人实际这样做,但您应该始终与您的存储供应商核实。
然后,您可以加密散列或存储加密数据的散列。在这两种情况下,这意味着您必须使用相同的密钥对整个命名空间进行加密。虽然可以使用加密散列进行密钥轮换,但这将是不可行地慢,因为需要同时轮换数十亿个散列并将它们存储回可搜索结构中。
一个更基本的问题是,重复数据删除数据不可避免地会导致侧信道攻击。为了使重复数据删除有效,您希望命名空间尽可能大。但是,如果您与攻击者共享命名空间,一个经过重复数据删除的块几乎肯定会比一个未经过重复数据删除的块具有不同的响应时间。这意味着攻击者很可能能够确认具有给定内容的对象是否存在于命名空间中。
因此,声称将重复数据删除和压缩结合起来的那些对象存储供应商可能在玩弄事实。如果他们真的做了这些事情,他们将无法提供高性能或安全的系统。我们乐于接受这方面的教育,但我们对自己的评估很有信心。
MinIO 方法
体系结构中的重复数据删除是一个基本决定。除非您想要在系统基础上创建两个完全独立的代码路径,否则将重复数据删除作为“可选”是不切实际的。MinIO 决定不实现重复数据删除,原因如上所述。对于纯存储速度来说,这将是一个过于负面的权衡。
我们将对象部分作为磁盘上的单个连续流保留,这意味着对象读取是顺序读取。
但是,我们已经实现了透明数据压缩。它旨在非常快,并且可以在所有情况下安全使用。我们实现了一个查找索引,允许在任何 1MB 边界处开始解压缩。这意味着查找通常只有不到一毫秒的解压缩时间,并且只需要读取少量额外数据。
我们优化了速度,使其能够用单个流饱和即使是最快的 NIC,无论是上传还是下载。
当然,在可行的情况下,可以在客户端应用更强的压缩。这也会减少上传和下载所需的带宽,因此,只要可行,我们建议使用这种方法。
仍然想要重复数据删除吗?
重复数据删除可能很有价值,但我们认为它只应该存在于应用程序级别,并且只有在您可以预期获得收益时才应该使用它。像完整镜像备份这样的工作负载通常只会在每次备份之间看到一小部分块发生变化
这也具有额外的优势,即您无需首先将重复的块传输到服务器。应用程序还可以选择保留块的索引,因此可以在无需检查块是否远程存在的情况下执行重复数据删除。
更高级的应用程序甚至可以利用zip 存档来批量上传块,这也可以简化对过时数据的清理,方法是忽略旧存档并在 n 天周期结束后重新添加引用的块。
结论
MinIO 致力于榨取您的硬件所能提供的最佳性能。因此,我们提供高吞吐量压缩,可以超越您的网卡速度,并且在服务器端不使用任何重复数据删除。我们坚信,这是充分利用硬件投资的正确方法。我们认为,用理论上的重复数据删除和压缩数字来夸大原始存储空间数字是不诚实的,您应该向任何这样做提供商提出质疑。
安装 MinIO,了解更多关于 透明数据压缩 的信息。如果您对可疑供应商的声明有任何疑问,请联系我们的 sales@min.io - 如果您对压缩和如何配置它有任何疑问,请随时在 Slack 上联系我们!