You need to enable JavaScript to run this app.
导航
Proton SDK调优指南
最近更新时间:2024.07.29 15:16:08首次发布时间:2024.05.15 16:05:56

在火山引擎创建EMR或者将Proton应用到自建Hadoop集群后,可以根据使用场景的不同进行针对性性能优化。

1 写大文件场景

Proton在写大文件时,会基于对象存储MPU机制进行异步分片上传,在客户端每写满一个分片之前,默认会优先写到本地磁盘,一个分片写满之后,会异步上传到对象存储,并清除磁盘上的分片数据。所以文件写入速度可能会受限于本地磁盘写入带宽和上传网络带宽,默认情况下,前者远高于后者。因此写入流程可以充分利用多块本地磁盘来提升数据写入性能,可以通过修改core-site.xml中的fs.tos.multipart.staging-dir进行多盘配置,比如:

<property>
    <name>fs.tos.multipart.staging-dir</name>
    <value>/data01/stagingdir,/data02/stagingdir,/data03/stagingdir</value>
</property>

说明

EMR场景下已经默认根据EMR节点的磁盘挂载情况进行了配置,无需再额外配置。手动配置该参数时,需要注意写数据的任务有这些配置目录的读写权限。

同时,基于MPU上传大文件时,由于MPU有10000分片个数的限制,所以需要设置合适的分片值。以写一个100G的对象为例,分片的最小值为10.24MB,这种情况下建议将对应的参数fs.tos.multipart.size设置为2^n, 即16MB。

<property>
    <name>fs.tos.multipart.size</name>
    <value>16777216</value>
    <description>默认值为8MB</description>
</property>

同时也可以增大并发上传分片的线程数,来加速文件的写操作。

<property>
    <name>fs.tos.multipart.thread-pool-size</name>
    <value>64</value>
    <description>默认值为所在ECS节点核数的2倍,不建议超过超过ECS节点核数的4倍</description>
</property>

2 高并发写小文件场景

与写大文件类似,客户端会写一批数据到本地之后,再上传到对象存储。高并发写小文件场景下,客户端可以直接将数据写入内存中,然后上传到对象存储,没有必要写到本地磁盘。因此可以提升小文件的上传速度。可以通过设置fs.tos.multipart.staging-buffer-size参数的值,作为将数据写入哪种存储介质的阈值,当写入的数据量小于该值时,会写入内存,否则会写入本地磁盘。生产实践中,增大该值时,建议同时调整JVM堆的参数,避免内存不足导致频繁GC影响性能以及OOM问题。

<property>
    <name>fs.tos.multipart.staging-buffer-size</name>
    <value>4096</value>
    <description>默认值为4k,单位为byte</description>
<property>

同时,在上传数据到对象存储时,可以选择MPU多分片上传或者直接PUT两种上传模式。对于小文件场景,直接PUT的方式有利于提升写入性能,可以通过设置fs.tos.multipart.threshold参数配置阈值,如果写入的对象大小大于该值时,会采用MPU分片异步上传的方式,小于该值时,使用直接PUT的方式。

<property>
    <name>fs.tos.multipart.threshold</name>
    <value>10485760</value>
    <description>默认值为10M,不建议将该指设置的特别大,同时如果启用Job Committer场景下,会直接使用MPU</description>
</property>

3 Rename大目录场景

当我们需要对一个大目录执行Rename/MV操作时,客户端首先会批量的list该目录下的子文件/子目录,然后再并行对子文件/子目录并行执行Rename操作,可以通过增大并发数fs.tos.task.thread-pool-size来提升Rename子目录/子文件的速度。

<property>
    <name>fs.tos.task.thread-pool-size</name>
    <value>64</value>
    <description>默认值为所在ECS节点核数的2倍</description>
</property>

Proton默认通过Copy + Delete来执行对一个文件的Rename操作,火山引擎TOS原生支持Rename语义,所以直接使用TOS的Rename语义可以极大的提升Rename的性能。使用Rename语义需要执行以下两个操作:

  1. 进入TOS控制台 -> 选择对象桶 -> 概览 -> RenameObject -> 开启
  2. 修改core-site.xmlfs.tos.rename.enabled参数
<property>
    <name>fs.tos.rename.enabled</name>
    <value>true</value>
    <description>默认false,开启后直接使用Rename语义代替Copy+Delete操作</description>
</property>

说明

  1. 由于对象存储本身不支持文件、目录的概念,所以上述的Rename语义主要指Rename单个对象,业务场景中Reanme大目录的场景下,依然需要先list出所有需要rename的对象,然后再并发地执行Reanme操作。如果期望直接对目录执行Rename操作,需要创建TOS 分层桶(Preview)。
  2. TOS开启Rename功能之后,依然可以对特定时间点(开启之前)之后创建的对象执行Rename操作,在该时间点之前创建的对象,没法执行Rename操作。具体时间点如下:
    华北2:2024-07-11 11:00
    华东2:2024-07-04 15:00
    华南1:2024-07-04 15:00
    柔佛:2024-07-11 11:00

4 获取文件元数据场景

大数据场景下,调用Filesystem.getFileStatus(path)获取目录或者文件的状态信息是一个非常普遍的使用场景。由于对象存储本身不存在文件或者目录的概念,所以我们将对象存储当做文件系统使用时,往往会将对象名称是否以/结尾来判断一个对象是一个文件还是目录,同时以/结尾的对象往往是一个空对象。比如对象a/b/c是一个文件,a/b/c/是一个目录。
基于对象存储实现Filesystem.getFileStatus(path)时,可能需要2次headObject + 1次listObject操作,才能得到该path在对象存储上的元数据,这个过程存在RPC次数放大的问题,特别是path对应的对象不存在时。由于Filesystem.getFileStatus(path)是一个高频操作,所以RPC次数放大问题会随着调用次数的增长而加剧,极端情况下,会打到对象存储QPS流控上限配额,导致性能下降。
火山引擎TOS针对该场景,提供了对应的getFileStatus接口,可以将3次RPC请求合并为1次RPC请求,解决RPC访问次数放大的问题。通过Proton访问对象存储时,需要在core-site.xml中添加或修改fs.tos.get-file-status.enabled参数,才能使用getFileStatus功能。

<property>
    <name>fs.tos.get-file-status.enabled</name>
    <value>true</value>
</property>