目前,在我们的应用程序中,我们正在将二进制数据保存到数据库中(我知道这很糟糕;但这是遗留的东西,这不是我的决定)。我们试图将这些数据迁移到外部设备,并且试图提出一种保存这些文件的方案。
我们有多个租户,我希望每个租户都有一个目录。我的方案是使用租户的前三个字母来构建路径。因此,如果您有一个名为apple
的租户,则其文件将位于/a/p/p/apple
。在这些目录中,我将保存文件。对于文件,我想生成一个随机的6个字符的字母数字名称(由于内部原因,暂时仅使用小写字母)。因此,如果我们生成一个名为6a8jxo
的文件名,它将被存储为<tenant>/6/a/6/6a8jxo
。通过这种策略,每个租户最多可以拥有大约9,160亿个唯一文件(不是我们要保存那么多文件),每个目录最多可以有46,656个文件。如果我使用5个字符的名称,则最多将有605亿个唯一文件,每个目录有1,296个文件。
这种方法有什么缺点吗?我意识到某些目录可能只包含一个或两个文件,但是在我看来这不是一个大问题。
我的同事不想这样做。他想使用数据库中的自动递增字段,然后将目录结构基于该字段的十六进制值(我假设为32位),而不是使用租户。按照他的策略,十六进制值将按以下方式使用:文件将存储在<tenant>/aa/bbb
的目录中,其中aa
是十六进制值的前两个字符(最高有效半字节),而bbb
是后三个字符。他的理由是,他只想在一个目录填满时创建新目录,而不要拥有多个部分填充的目录。
这种方法在代码方面带来了许多困难,我认为没有完全填充的目录作为证明这样做所需的额外努力的理由。
我还有没有考虑过的其他策略或方法?
最佳答案
我认为您尚未考虑的主要问题是随机文件名中发生冲突的可能性。
这么小的名字,您只有36 ^ 6 = 2,176,782,336
唯一文件,这意味着您很可能在击中50,000个文件(http://en.wikipedia.org/wiki/Birthday_problem)之前会发生冲突-数量不多(当然,总是有可能更早地获得一个文件)。
我喜欢您同事的方法,只是因为它可以保证唯一的名称,而不管它如何影响文件系统。
如果您绝对不想依靠数据库来生成一致的序列,则可以使用UUIDs作为名称。
您似乎还在计划非常深的树-您希望拥有多少文件(和租户)?一个合理的经验法则是每个目录有10,000个文件(实际上,不仅是可能的),现代文件系统可能有更多文件。几乎可以肯定,三个级别的子目录是过大的。
另外,如果您确实需要将租户分成多个目录,请先对它们进行哈希处理(或使用数据库ID)-使用自然名称可能会导致非常不平衡的“存储桶”(这在这里可能不是一个大问题,但不会花费任何费用)正确地做)。
最后,文件有多大?根据您的实际用例,将它们存储在数据库中可能是一种完全合理的方法。
关于java - 二进制数据存储方案(保存用户上传的文件),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20501610/