分区与命名约定

OSS按照文件名UTF-8编码的顺序对用户数据进行自动分区,从而能够处理海量文件,以及承载高速率的客户请求。不过,如果客户在上传大量对象时,在命名上使用了顺序前缀(如时间戳或字母顺序),可能会导致大量文件索引集中存储于某个特定分区。这样,当用户的请求速率超过2000操作/秒时(下载、上传、删除、拷贝、获取元数据信息等操作算1次操作,批量删除N个文件、列举N个文件等操作算N次操作),会带来如下后果:

  • 该分区成为热点分区,导致分区的I/O能力被耗尽,或被系统自动限制请求速率。
  • 热点分区的存在会触发系统进行持续的分区数据再均衡,这个过程可能会延长请求处理时间。

从而降低OSS的水平扩展效果,导致客户的请求速率受限。

要解决这个问题,根本上,要消除文件名中的顺序前缀。我们可以在文件名前缀中引入某种随机性,这样文件索引(以及 I/O 负载)就会均匀分布在多个分区。

下面提供了几个将顺序前缀改为随机性前缀的方法案例。

  • 示例 1:向文件名添加十六进制哈希前缀

    如下例所示,用户使用了日期与客户ID生成文件名,包含了顺序时间戳前缀:

    sample-bucket-01/2017-11-11/customer-1/file1
    sample-bucket-01/2017-11-11/customer-2/file2
    sample-bucket-01/2017-11-11/customer-3/file3
    ...
    sample-bucket-01/2017-11-12/customer-2/file4
    sample-bucket-01/2017-11-12/customer-5/file5
    sample-bucket-01/2017-11-12/customer-7/file6
    ...

    针对这种情况,我们可以对客户ID计算哈希,即MD5(customer-id),并取若干字符的哈希前缀作为文件名的前缀。假如取4个字符的哈希前缀,结果如下所示:

    sample-bucket-01/2c99/2017-11-11/customer-1/file1
    sample-bucket-01/7a01/2017-11-11/customer-2/file2
    sample-bucket-01/1dbd/2017-11-11/customer-3/file3
    ...
    sample-bucket-01/7a01/2017-11-12/customer-2/file4
    sample-bucket-01/b1fc/2017-11-12/customer-5/file5
    sample-bucket-01/2bb7/2017-11-12/customer-7/file6
    ...

    加入4个字符组成的十六进制哈希作为前缀,每个字符有0-f共16种取值,因此4个字符共有16^4=65536种可能的字符组合。那么在存储系统中,这些数据理论上会被持续划分至最多65536个分区,以每个分区2000操作/秒的性能瓶颈标准,再结合您的业务的请求速率,以此您可以评估hash桶的个数是否合适。

    如果您想要列出文件名中带有特定日期的文件,例如列出sample-bucket-01里带有2017-11-11的文件,您只要对sample-bucket-01进行列举(即通过多次调用List Object接口,分批次地获得sample-bucket-01下的所有文件),然后合并带有该日期的文件即可。

  • 示例 2:反转文件名

    如下例所示,用户使用了毫秒精度的UNIX时间戳生成文件名,同样属于顺序前缀:

    sample-bucket-02/1513160001245.log
    sample-bucket-02/1513160001722.log
    sample-bucket-02/1513160001836.log
    sample-bucket-02/1513160001956.log
    ...
    sample-bucket-02/1513160002153.log
    sample-bucket-02/1513160002556.log
    sample-bucket-02/1513160002859.log
    ...

    由前面的分析,我们知道,这种顺序前缀命名,在请求速率超过一定阈值时,会引发性能问题。我们可以通过反转时间戳前缀来避免,这样文件名就不包含顺序前缀了。反转后结果如下:

    sample-bucket-02/5421000613151.log
    sample-bucket-02/2271000613151.log
    sample-bucket-02/6381000613151.log
    sample-bucket-02/6591000613151.log
    ...
    sample-bucket-02/3512000613151.log
    sample-bucket-02/6552000613151.log
    sample-bucket-02/9582000613151.log
    ...

    由于文件名中的前3位数字代表毫秒时间,会有1000种取值。而第4位数字,每1秒钟就会改变一次。同理第5位数字每10秒钟就会改变一次…以此类推,因此,反转文件名后,极大地增强了前缀的随机性,从而将负载压力均匀地分摊在各个分区上,避免出现性能瓶颈。