Shortcuts

3FS vNext 新特性

3FS 是为深度学习训练场景研发设计的高速文件系统,如今第二代 3FS vNext 发布上线,其拥有更好的 meta 性能和更高的小块读吞吐,减少了服务端和和客户端升级时对用户的影响,增强了硬件出故障时集群的可用性和性能,功能和参数配置更加机动灵活,为深度学习场景量身定制。同时 3FS vNext 还支持了用户空间下的文件系统(Filesystem in Userspace,简写为 FUSE),使其安全性、可维护性进一步提高。

本文将为大家介绍,如何配置操作 3FS vNext。

通过 FUSE 直接操作 3FS vNext

过去,3FS 只提供内核态客户端,升级客户端需要从内核卸载客户端模块。3FS vNext 提供了特殊的用户态文件系统 FUSE,在用户空间提供 3FS vNext 的 POSIX 接口。用户空间下调试工具丰富,出问题不会导致系统崩溃,升级客户端用户无感知。

FUSE 支持 lsmdkirrm 等 POSIX 文件操作命令,但因为 FUSE 的性能受限,这种使用方式一般只推荐用于日常的文件管理。

使用 FUSE 挂载后的目录前缀会变为 /hf3fs-jd

开发容器中添加 FUSE 挂载

打开 Studio,如需创建新容器,请点击创建容器(蓝底白字按钮);如需编辑容器,请先点击“停止”(红色字体),等待容器停止后出现“编辑”,再点击“编辑”(蓝色字体)

在创建开发容器或编辑容器时,勾选要访问的 3FS 集群,默认就会配置 FUSE 挂载。

如果从 CPU 集群、CPU 开发机或独占机访问 3FS,单选 3FS CPU;如果从 GPU 集群、GPU 开发机访问 3FS,单选 3FS PROD;不建议交叉选择

注:3FS CPU 用户用命令行和接口提交任务到 CPU 分组会自动开启 sidecar fffs_cpu(不需要再指定 options.sidecar.fffs_cpu)和 fuse,前端页面还没更新,但符合条件的任务和开发容器,无论是否勾选 sidecar,实际都会打开(3FS PROD 正式上线后也会同样自动开启 fffs_prod,同时会隐藏 UI 上的所有 sidecar 选项)。

启动 GPU 开发容器后便能在终端访问 3FS vNext。(下图以单选 3FS PROD 为例:/hf3fs-jd/prod)

~$ ls -l /hf3fs-jd/prod/private/$USER
total 0
-rw-r--r-- 1 qjj qjj 0 May 29 14:34 hello-world-from-3fs-vnext

启动 CPU 开发容器后便能在终端访问 3FS vNext。(下图以单选 3FS CPU 为例:/hf3fs-jd/cpu)

~$ ls -l /hf3fs-jd/cpu/bigger-storage/private/$USER
total 0
-rw-r--r-- 1 qjj qjj 0 May 29 14:34 hello-world-from-3fs-vnext

训练任务指定 3FS FUSE

您可以在任务提交的 UI 或 Yaml 文件中配置,或通过 hfai 工具提交任务时指定参数配置。

UI 配置

通过 UI 配置。如下图所示:

Logo

Yaml 配置

在任务提交 Yaml 文件里添加 options,fffs_enable_fuse: true, 示例如下:

name: sleep.py
options:
  fffs_enable_fuse: true  # 开启fuse挂载
  py_venv: py38-202111
  sidecar:
  - fffs_prod  # 为了能实际看到挂载点,这里至少要指定一个fffs_prod
priority: 30
resource:
  group: jd_a100
  image: ubuntu2004-cu113
  node_count: 1
spec:
  entrypoint: sleep.py
  parameters: ''
  workspace: /weka-jd/prod/jupyter/qjj/notebooks
version: 2

hfai 配置

在命令行提交训练任务,可以在 hfai 命令后增加 options。如下所示:

hfai python sleep.py -- -g jd_a100 -p 30 -n 1 --image=ubuntu2004-cu113 --options sidecar=["fffs_prod"] --options fffs_enable_fuse=true --options py_venv=py38-202111

虚拟目录和非posix操作

老3fs的用户在使用过程中遇到了一些不便,新版3fs也对此作出了一些改进,提供一些非标准的操作方法来完成普通文件系统上无法做到的功能。hf3fs的根目录下,有一个3fs-virt目录,里面是一些虚拟目录,通过这些目录,可以完成以下操作:

  1. 快速删除一个目录树(不需要递归删除目录树里的文件就直接删除顶层目录)

  2. 跨挂载点移动同一个hf3fs集群上的文件/目录(比如从private目录直接移动到team目录而不需要拷贝数据)

考虑到3fs-virt目录本身也是一个独立的挂载点,所以操作都是通过symlink来完成的。(symlink万岁!)

快速删除目录树

ln -s /hf3fs-jd/{cluster}/path/to/dir/to/rm -t /hf3fs-jd/{cluster}/3fs-virt/rm-rf

或者

os.symlink('/hf3fs-jd/{cluster}/path/to/dir/to/rm', '/hf3fs-jd/{cluster}/3fs-virt/rm-rf/whatever-dir-name')

注意到,如果要用代码来实现这个功能,需要在最后加上一个目录名。因为操作完成后这个目录是被彻底删除,不会在原来位置或者虚拟目录下出现,所以这个目录名随便用啥都可以。不过如果要并发操作的话,需要用不同的目录名,否则操作系统会直接拒绝同时建立两个同名的symlink。

源路径必须使用绝对路径。

跨挂载点移动

ln -s mv:/hf3fs-jd/{cluster}/path/to/src -t /hf3fs-jd/{cluster}/path/to/dst/parent/dir

或者

os.symlink('mv:/hf3fs-jd/{cluster}/path/to/src', '/hf3fs-jd/{cluster}/path/to/dst/parent/dir/dst-name')

这个操作实际上不需要用到虚拟目录,而是在源路径前加了mv:前缀。源路径必须是绝对路径。

用代码来操作时,目标路径必须在目标目录后面加上一个目标名称,这个名称就是最后移动过去的目录/文件名称。在命令行/bash脚本里操作时,ln也是支持给出带最终名称的目标路径的,假如移动之后的名称和源的名称不一样的话。