我有一个相当大的目录,其中包含许多缓存文件,我想重新组织这些文件以获得最佳性能(访问时间)。
- 2x 2TB SATA III 硬盘,软件 RAID 1(镜像)
- 操作系统:Ubuntu 12.04 LTS
- 文件系统:ext4
- 500 GB od 数据
- 约 1600-1700 万个文件
- 平均文件大小:30KB
- 文件名是 MD5 哈希值
文件由 PHP/Perl 脚本随机访问。这些脚本生成绝对路径并读取文件。没有目录列表:几乎只是fopen
文件的绝对路径。
当前目录层次结构为:cacheDir/d4/1d/d41d8cd98f00b204e9800998ecf8427e.dat
因此,有 256 个一级子目录(d4
在示例中),以及 256 个二级子目录(1d
在示例中)。平均而言,每个二级目录中大约有 200-300 个文件。
fopen
问题:当出现网络流量高峰且中有大量 时cacheDir
,iowait
会不断增长,从而减慢系统速度,导致负载非常高且延迟明显。只有cacheDir
访问 中的文件时才会出现这种高负载。如果我以相同的频率访问其他目录/文件,磁盘和系统运行正常。
我想知道更改缓存目录结构是否会提高性能?更改为(例如):(cacheDir/d/4/1/d/8/d41d8cd98f00b204e9800998ecf8427e.dat
16 个子目录:第 1、2、3、4 级,并且(平均)每个第 4 级子目录有 15 个文件)。
我知道在简单的桌面 SATA III 驱动器上,软件 RAID 1 并不是速度怪物,但也许有一些优化文件系统的好方法?
请注意:
- 文件系统已启用
dir-index
- 文件系统挂载了
noatime
- 文件系统进行了优化
e2fsck -Df
答案1
这可能听起来很愚蠢,但事实是你的真实性)是基准测试结果。可能存在在每种情况下都比其他文件系统更快的文件系统,但最佳结构很可能取决于磁盘的速度特性、RAM 数量和缓存效率。
如果您使用具有更深层次结构的较小目录,会发生什么情况?需要读取更少的数据来查找目录条目,但也许(如果该目录在其父目录中的条目不再缓存)。假设目录条目为 50 字节。对于包含 300 个文件的整个目录,这为 15K。在进行连续读取时,您的磁盘可能提供 150+ MiB/s。因此,读取 300 个文件或 600 个文件之间的差异为 0.1 毫秒。定位时间最多为 4 毫秒(如果不是 SSD)。即,对于每个保存的目录查找,您可以读取至少 12,000 个文件的条目。这让我假设您的目录相当小。但也许您的所有目录条目都在缓存中(我不知道如何监控它,不过会很有趣),所以这个计算无关紧要。也许在后台保留一个脚本会有所帮助,该脚本每隔几秒钟访问一次所有目录,这样就不会将它们从缓存中丢弃。
我认为问题不在于文件 inode 的查找时间。可能有很多进程尝试同时执行 I/O。如果这导致文件在多个步骤中被读取,那么性能当然会下降。文件碎片也是如此。查看filefrag
和您的缓存文件。并查看blockdev --setra
。您应该将其调整为您的平均文件大小(或超过 90% 文件的大小)并检查这是否有任何影响。我还发现了一个提示(虽然已经有好几年了),将除最顶层设备之外的所有设备的此值设置为零:
/dev/sdx -> ra=0
/dev/mdx -> ra=0
/dev/lvm/ -> ra=xxxx
我不知道您愿意做多少,但我可以想象 FUSE 模块会对您的情况有所帮助(取决于文件大小和预读效率):此模块必须确保文件在一个步骤中被读取,并且(在用户空间的限制内)这些访问不会被中断。下一步是按磁盘上的位置对文件访问进行排序,即在文件级别执行内核(和磁盘本身)对单个 I/O 操作所做的事情。您可以创建较小的 LV,而不是使用带有目录的大型文件系统。因此,您可以按名称对文件访问进行排序,并获得按磁盘区域排序的访问。
如果你愿意更换硬件,那么这可能会很有趣:仅将元数据放在 SSD 上。并且您应该尝试从缓存磁盘中获取写访问权限。这可能主要是日志文件。它们通常并不真正重要,因此将它们放在具有较长提交时间的文件系统上可能会有所帮助data=writeback
。
如果(部分)缓存数据是静态的(并且您不需要 ACL),那么您可以测试将其从 ext4 移至 squashfs(压缩的只读 FS)的性能。如果问题是分几步读取文件,ext4 中的透明压缩(FUSE)也可能有帮助。文件系统(和磁盘内部)预读将获取更多文件(如果文件可压缩)。