如果您在上传大量文件时,在命名上使用了顺序前缀(如时间戳或字母顺序),可能会出现大量文件索引集中存储于存储空间中的某个特定分区的情况。此时如果您的请求次数过多,会导致请求速率下降。出现这种问题时,建议您为Object的名称增加随机前缀。

背景信息

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

  • 该分区成为热点分区,导致分区的I/O能力被耗尽,或被系统自动限制请求速率。
  • 热点分区的存在会触发系统进行持续的分区数据再均衡,这个过程可能会延长请求处理时间。
    说明 分区数据再均衡是依赖于对当前系统状态、处理能力等信息做各种智能分析后进行的,并不是某个固定的拆分规则。所以分区数据再均衡后,使用了顺序前缀的文件可能还会处于高热点的分区当中。

以上情况会降低OSS的水平扩展效果,导致客户的请求速率受限。

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

解决方案

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

  • 向文件名添加十六进制哈希前缀

    如下所示,若您使用日期与客户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),并取若干字符的哈希前缀作为文件名的前缀。假如取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~9以及a~f共16种取值,4个字符共有16 4 =65536种可能的字符组合。那么在存储系统中,这些数据理论上会被持续划分至最多65536个分区,以每个分区操作2000次/秒的性能瓶颈标准,再结合您业务的请求速率,可以评估hash桶的个数是否合适。

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

  • 反转文件名

    如下所示,若您使用了毫秒精度的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秒钟就会改变一次。以此类推,反转文件名后,极大地增强了前缀的随机性,从而将负载压力均匀地分摊在各个分区上,避免出现性能瓶颈。