Leer en inglés

Compartir a través de

从 Linux 客户端访问大型目录时优化文件共享性能

本文提供有关如何使用包含大量文件的目录的建议。 通常,将文件分散到多个目录来减少单个目录中的文件数是一个良好做法。 但是,在某些情况下,无法避免使用大型目录。 在处理装载在 Linux 客户端上的 Azure 文件共享上的大型目录时,请考虑以下建议。

适用于

管理模型 计费模式 媒体层 冗余 中小型企业 (SMB) 网络文件系统(NFS)
Microsoft.Storage 预配版本 v1 SSD(高级) 本地 (LRS) 否 是的
Microsoft.Storage 预配版本 v1 SSD(高级) 区域 (ZRS) 否 是的
Microsoft.Storage 即用即付 HDD(标准) 本地 (LRS) 否 否
Microsoft.Storage 即用即付 HDD(标准) 区域 (ZRS) 否 否
Microsoft.Storage 即用即付 HDD(标准) 异地 (GRS) 否 否
Microsoft.Storage 即用即付 HDD(标准) GeoZone (GZRS) 否 否

增加哈希桶数

执行枚举的系统上存在的 RAM 总量会影响 NFS 和 SMB 等文件系统协议的内部工作。 即使用户没有遇到高内存使用率的情况,可用内存量也会影响系统具有的 Inode 哈希桶的数量,从而影响/提高大型目录的枚举性能。 可以修改 inode 哈希桶的数量,以减少大型枚举工作负荷期间可能发生的哈希冲突。

若要增加 inode 哈希存储桶的数量,请修改启动配置设置:

  1. 使用文本编辑器编辑 /etc/default/grub 文件。

    sudo vim /etc/default/grub
    
  2. 将以下文本添加到 /etc/default/grub 文件。 此命令将 128MB 设置为 inode 哈希表大小,最多增加系统内存消耗 128MB。

    GRUB_CMDLINE_LINUX="ihash_entries=16777216"
    

    如果 GRUB_CMDLINE_LINUX 已存在,则添加以空格分隔的 ihash_entries=16777216,如下所示:

    GRUB_CMDLINE_LINUX="<previous commands> ihash_entries=16777216"
    
  3. 若要应用更改,请运行:

    sudo update-grub2
    
  4. 重启系统:

    sudo reboot
    
  5. 若要验证更改在重新启动后是否有效,请检查内核 cmdline 命令:

    cat /proc/cmdline
    

    如果 ihash_entries 可见,则表明系统已应用该设置,枚举性能应呈指数级提高。

    还可以检查 dmesg 输出,看内核命令行是否已应用:

    dmesg | grep "Inode-cache hash table"
    Inode-cache hash table entries: 16777216 (order: 15, 134217728 bytes, linear)
    

以下装载选项特定于枚举,可在处理大型目录时降低延迟。

actimeo

actimeo 装载选项指定客户端在向服务器请求属性信息之前缓存文件或目录的属性的时间(以秒为单位)。 在此期间,服务器上发生的更改将保持未检测到状态,直到客户端再次检查服务器。 对于 SMB 客户端,默认属性缓存超时设置为 1 秒。

在 NFS 客户端上,指定 actimeo 将所有 acregminacregmaxacdirminacdirmax 设置为相同的值。 如果未指定 actimeo,则客户端会为这些选项中的每一个使用默认值。

建议在处理大型目录时将 actimeo 设置为 30 到 60 秒。 将值设置在此范围内,可使属性在客户端的属性缓存中保持较长的有效时间,从而允许操作从缓存中获取文件属性,而不是通过网络提取它们。 这可以在缓存属性过期而操作仍在运行的情况下减少延迟。

下图比较了在单个目录中有 100 万个文件的工作负载中,使用默认挂载和设置 actimeo 值为 30 完成不同操作所需的总时间。 在我们的测试中,某些操作的总完成时间缩短了高达 77%。 所有操作都是用未别名化的 ls 完成的。

将完成不同操作的时间与默认装载时间进行比较,而不是为具有 100 万文件的工作负荷将 30 actimeo 值设置为 30。

NFS nconnect

NFS nconnect 是 NFS 文件共享的客户端装载选项,可用于在客户端与 NFS 文件共享之间使用多个 TCP 连接。 建议使用 nconnect=4 的最佳设置,以减少延迟并提高性能。 nconnect 功能对于使用来自多个线程的异步或同步 I/O 的工作负荷尤其有用。 了解详细信息

命令和操作

指定命令和操作的方式也可能会影响性能。 使用 ls 命令列出大型目录中的所有文件是一个很好的示例。

Nota

某些操作(如递归 lsfinddu)需要文件名和文件属性,因此它们将目录枚举(用于获取条目)与每个条目的统计信息(用于获取属性)组合在一起。 建议在可能运行此类命令的装入点上为 actimeo 使用更高的值。

使用未别名化的 ls

在某些 Linux 分发版中,shell 会自动为 ls 命令(如 ls --color=auto)设置默认选项。 这会更改 ls 通过网络工作的方式,并将更多操作添加到 ls 执行。 为了避免性能降低,我们建议使用未别名化的 ls。 可以通过以下三种方式之一实现该操作:

  • 作为仅影响当前会话的临时解决方法,可以使用命令 unalias ls删除别名。

  • 对于永久更改,可以在用户的 ls 文件中编辑 bashrc/bash_aliases 别名。 在 Ubuntu 中,编辑 ~/.bashrc 以移除 ls 的别名。

  • 你可以直接调用 ls 二进制文件,例如 ls,而不是调用 /usr/bin/ls。 这允许你使用 ls,而无需任何可能位于别名中的选项。 可以通过运行命令 which ls 找到二进制文件的位置。

防止 ls 对其输出进行排序

在与其他命令一起使用 ls 时,如果不在意 ls 返回文件的顺序,则可以防止 ls 对其输出进行排序,从而提高性能。 对输出进行排序会增加巨大开销。

可以使用具有 ls -l | wc -l-f-U 选项来防止对输出排序,而不是运行 ls 来获取文件总数。 区别在于, -f 还显示隐藏的文件,并且 -U 不显示。

例如,如果在 Ubuntu 中直接调用 ls 二进制文件,则会运行 /usr/bin/ls -1f | wc -l/usr/bin/ls -1U | wc -l

下图比较了使用未别名化、未排序 ls 与已排序 ls 的输出结果所需的时间。

已排序 Is 与未排序 ls 操作的总时间(以秒为单位)比较图。

文件复制和备份操作

从文件共享复制数据或从文件共享备份到另一个位置时,为了获得最佳性能,我们建议使用共享快照作为源,而不是使用具有活动 I/O 的实时文件共享。 备份应用程序应直接在快照上运行命令。 有关详细信息,请参阅将共享快照与 Azure 文件存储配合使用

应用程序级建议

开发使用大型目录的应用程序时,请遵循这些建议。

  • 跳置文件属性。 如果应用程序只需要文件名而不需要文件属性(如文件类型或上次修改时间),则可以通过多次调用系统调用,例如 getdents64,并设置合适的缓冲区大小来获取指定目录中的条目,而无需文件类型,从而促进更快的操作速度,并避免不必要的额外操作。

  • 交错统计信息调用。 如果应用程序需要属性和文件名,我们建议将统计信息调用与 getdents64 交错进行,而不是使用 getdents64 获取文件结束前的所有条目,然后对所有返回的条目执行 statx。 让统计信息调用交错在一起会指示客户端同时请求文件及其属性,从而减少对服务器的调用数。 当与较高的 actimeo 值结合使用时,交错的 stat 调用可以显著提高性能。 例如,在每个 [ getdents64, getdents64, ... , getdents64, statx (entry1), ... , statx(n) ] 后放置 statx 调用,而不是 getdents64[ getdents64, (statx, statx, ... , statx), getdents64, (statx, statx, ... , statx), ... ]

  • 增加 I/O 深度。 如果可能,我们建议将 nconnect 配置为非零值(大于 1),并在多个线程之间分配操作,或使用异步 I/O。 这使得异步操作能够从与文件共享的多个并发连接中受益。

  • 强制使用缓存。 如果应用程序正在查询仅装载了一个客户端的文件共享上的文件属性,请使用具有 AT_STATX_DONT_SYNC 标志的 statx 系统调用。 此标志可确保从缓存中检索缓存属性,而无需与服务器同步,从而避免为了获取最新数据而进行的额外网络往返来。

另请参阅