JFS
日志文件系统 (JFS) 是一个 日志文件系统,由 IBM 于 1999 年开源,自 2002 年起在 Linux 内核中提供支持。
本文向读者介绍 JFS 文件系统。 特别是,将介绍关于文件系统本身的一些背景信息以及关于不稳定的实现的注意事项,以及实现、维护和优化的程序。
背景
- 1990 年,JFS1(当时简称为 JFS)发布,用于 AIX 3.1 版本。 该文件系统与其目标硬件(IBM 的 AIX UNIX 服务器系列)紧密相连,是一种专有设计。
- 1995 年,开始大力开发改进 JFS,重点是可扩展性和扩展功能。
- 1997 年,并行开发开始将改进后的 JFS 源代码移回 AIX。
- 1999 年,改进后的 JFS 设计发布用于 OS/2。
- 2001 年,改进后的文件系统(新术语为 JFS2)发布用于 AIX 5L。
- 当前的 GNU/Linux 版本是基于 OS/2 的 JFS 移植。
虽然很难对 JFS 和 UNIX 以及类 UNIX 操作系统上可用的其他文件系统进行一般性比较,但据称 JFS 比其他 GNU/Linux 文件系统使用的 CPU 资源更少 [2]。 通过某些优化,与其他 GNU/Linux 文件系统相比,JFS 在某些文件操作方面也被认为更快(参见基准测试)。
GNU/Linux 开发团队
GNU/Linux JFS 移植的开发由以下人员领导:
- Dave Kleikamp (dave dot kleikamp at oracle dot com)
- HP: https://jfs.sourceforge.net/
技术特性
JFS 是一个现代文件系统,支持许多特性,此处列出其中一些。
- 完全 64 位。
- i 节点动态空间分配,即在具有大量小文件的文件系统上不会耗尽 i 节点。
- 为速度和效率而设计的目录结构
- 包含八个或更少条目的目录将其内容内联存储在该目录的 i 节点中。
- 包含超过八个条目的目录将其内容存储在以名称为键的 B+ 树中。
- JFS 利用区段为大文件分配块。
- 除了标准的 Unix 样式权限之外,还支持扩展属性。
- 支持内部和外部日志(见下文)。
- 极具可扩展性; 从最小文件大小到 4PB 均具有一致的性能。
- 为超大型系统上的高性能而设计的算法。
- 针对 GNU/Linux 调整了性能。
- 从头开始设计以提供事务/日志(不是附加组件)。
- 系统故障后重启 < 1 秒。
- 经过验证的日志文件系统技术(在 AIX 中超过 10 年)。
- 原始设计目标:性能、稳健性、SMP。
- 来自原始 AIX JFS 设计/开发团队的成员开发了这个文件系统。
- 设计为在 SMP 硬件上运行,代码针对至少 4 路 SMP 机器进行了优化。
- TRIM 支持(自内核 3.7 起)。
有关 JFS 功能的更全面(和技术性)的概述,请参阅开发者 Steve Best 撰写的 JFS 概述。
安装
JFS 驱动程序在标准 Arch 内核软件包中构建为模块。
必须jfsutils软件包安装才能执行所有与文件系统相关的任务。
可以使用以下任一命令创建 JFS 文件系统
# mkfs.jfs /dev/target_dev
或
# jfs_mkfs /dev/target_dev
这两个命令是等效的。
优化
可以使用 JFS 文件系统实施几个概念来提高其性能
- 文件系统的定期碎片整理。
- 使用 Deadline I/O 调度器。
- 利用外部日志。
JFS 碎片整理
像所有文件系统一样,由于文件碎片,JFS 的性能会随着时间的推移而下降 [5]。 虽然 JFS 实用程序中存在就地碎片整理代码,但此代码是从 OS/2 移植过来的,尚未实现 [6]。 对于可以离线一段时间的文件系统,可以执行如下脚本来整理其 JFS 文件系统碎片
umount /dev/hdc1 dd bs=4k if=/dev/hdc1 of=/dev/hdj1 jfs_fsck /dev/hdj1 mount -o ro /dev/hdj1 /fs/hdj1 jfs_mkfs /dev/hdc1 mount -o rw /dev/hdc1 /fs/hdc1 (cd /fs/hdj1 && tar -cS -b8 --one-file-system -f - .) | (cd /fs/hdc1 && tar -xS -b8 -p -f -) umount /dev/hdj1
在此示例中,/dev/hdc1
是包含需要备份的数据的设备,/dev/hdj1
是保存备份的设备。
基本上,此脚本将数据从 JFS 文件系统复制到备份驱动器,格式化原始 JFS 文件系统,最后以 JFS 将以碎片整理方式写入其分配树的方式将数据从备份写回新格式化的驱动器。
Deadline I/O 调度器
当内核配置为使用Deadline I/O 调度器时,JFS 似乎表现更好。 实际上,当采用此特定调度器时,JFS 的性能似乎超过了其他 GNU/Linux 文件系统 [7]。
外部日志
与任何日志文件系统一样,日志会根据磁盘活动不断被访问。 因此,将日志记录在与其对应的文件系统相同的设备上可能会导致 I/O 吞吐量下降。 通过将日志记录放在完全独立的设备上可以缓解这种性能下降。
要制作日志设备,首先创建一个 128MB 的分区。 根据 mkfs.jfs,使用大于 128MB 的分区会导致超出部分被忽略。 您可以为现有的 JFS 文件系统创建一个外部日志,方法是执行以下操作
# mkfs.jfs -J journal_dev /dev/external_journal # creates a journal on device /dev/external_journal # mkfs.jfs -J device=/dev/external_journal /dev/jfs_device # attaches the external journal to the existing file # system on /dev/jfs_device
或者可以发出命令来创建新的外部日志及其对应的 JFS 文件系统
# mkfs.jfs -j /dev/external_journal /dev/jfs_device
最后一条命令会格式化外部日志和 JFS 文件系统。
noatime fstab 属性
每次访问(读取或写入)文件时,大多数文件系统的默认设置是将与该文件关联的元数据附加更新的访问时间。 因此,即使是读取操作也会产生与文件系统写入相关的开销。 这可能会导致某些使用场景中的性能显着下降。 将 noatime 附加到 JFS 文件系统的 fstab 行会阻止此操作发生。 由于访问时间在大多数情况下并不重要,因此这种更改已被广泛认为是快速简便地提高硬件性能的方法。 甚至 Linus Torvalds 似乎也是这种优化的支持者 [8]。
- 还可以指定 relatime 选项,如果之前的访问时间比修改时间或更改时间旧,则该选项会更新访问时间 [9]。 在性能方面,这不如 noatime 挂载选项快,但如果使用需要知道文件上次读取时间的应用程序(如 mutt),则很有用。
- 使用 noatime/relatime 选项可以提高任何文件系统(而不仅仅是 JFS)的磁盘性能。
这是一个带有 noatime 标签的 /etc/fstab
条目的示例
/dev/sdb1 /media/backup jfs rw,users,noauto,noatime 0 0
也可以通过调用类似于以下命令的方式使用 noatime 属性挂载文件系统
# mount -o noatime -t jfs /dev/jfs_dev /mnt/jfs_fs
日志模式
JFS 不支持像 ext3 那样的各种日志模式。 因此,使用 mount 或在 /etc/fstab
中传递挂载选项 data=writeback 对 JFS 文件系统无效。 JFS 当前的日志模式类似于 Ext3 的默认日志模式:ordered [10]。
可变块大小
虽然 OS/2 移植的 JFS 支持 512、1024、2048 和 4096 字节的块大小,但 Linux 移植的 JFS 只能使用 4k 块。 即使 JFS 实用程序中存在与使用可变大小块的文件系统相对应的代码,但这尚未实现 [11]。 由于较大的块大小往往有利于性能(较小的块大小有利于有效的空间利用率),因此 JFS 开发人员已将为 Linux 中的 JFS 实现较小的块大小的优先级设定为较低。
fsck 和恢复
如果在断电之前文件系统未正确卸载,则通常必须在 JFS 文件系统上运行 fsck 才能重新挂载它。 此过程通常仅需几秒钟,除非日志已损坏。 如果运行 fsck 返回无法识别的文件系统错误,请尝试在目标设备上运行 fsck.jfs。 通常,fsck 就足够了。
注意事项
虽然 JFS 在当前开发阶段非常稳定,但在使用此文件系统时仍需注意一些事项。
JFS 根挂载在启动时为只读
有时,JFS 根分区将无法以正常的读写模式挂载。 这通常是由于 JFS 根文件系统在不干净的关机后未能通过 fsck 导致的。 JFS 很少在 fsck 中失败,通常是由于 JFS 日志本身已损坏。
在这种情况下,只需使用相对较新的 Arch Linux LiveCD 启动您的机器即可。 启动 Arch Linux livecd 将使您可以访问所有 JFS 实用程序,并将加载能够识别 JFS 文件系统的内核。 启动 CD 后,只需在您的 JFS 根目录上运行 fsck(或可能是 fsck.jfs),它应该可以正常恢复(即使 fsck 可能会比正常情况花费更长的时间,因为日志可能已损坏)。 fsck 完成后,您应该可以像往常一样启动您的机器。
JFS 和安全删除
通过用随机数据覆盖文件系统块来删除文件(即使用像 shred 这样的工具)的有效性无法得到保证 [12]。 考虑到日志文件系统的设计、维护问题和性能责任;可靠地粉碎文件作为一种删除方法,在任何日志文件系统上的实现优先级都不高。
在 JFS 根文件系统上强制执行 fsck
可以通过输入以下命令在根文件系统上强制执行 fsck (file system check)
# touch /forcefsck
并重启。 在 Arch Linux 系统上,如果 JFS 根目录位于受 device-mapper 控制的分区上(即根设备是 lvm 或 LUKS 加密设备),强制执行 fsck 有时会删除 /usr/man/man3/
目录。 此问题的原因尚不清楚,但该问题已被重现 [13]。
建议通过发出类似于以下命令来获取使用 /usr/man/man3/
的 Arch 软件包列表
# find /var/lib/pacman/local/ -name files | xargs grep -F "/man/man3/" | cut -d: -f1 | sort -u | awk -F/ '{print $6}' > man3_pkg_list
在尝试在 JFS 根分区上强制执行 fsck 之前 [14]。 如果 /usr/man/man3
确实消失了,只需重新安装 man3_pkg_list 中列出的所有软件包。
/usr/man/man3/
的软件包似乎可以解决该问题 [15]。如上所述,此问题的原因目前尚不清楚;但这可能与以下事实有关:强制执行 fsck 会运行更高阶段的文件系统检查,而这些检查仅在 JFS 日志在分区的不正确卸载中损坏时才会发生。
JFS 文件丢失
在 JFS 中;日志写入被无限期地推迟,直到出现另一个触发器,例如内存压力或卸载操作。 这种无限的写入延迟限制了可靠性,因为即使对于几分钟或几小时前写入的数据,崩溃也可能导致数据丢失。[16]
基准测试
由于衡量文件系统性能的基准测试往往侧重于特定类型的磁盘使用情况,因此很难解读评估 JFS 相对于其他文件系统性能的良好通用比较。 如前所述,有人指出,JFS 比其他 GNU/Linux 文件系统更倾向于使用更少的 CPU 资源,并且(通过正确的优化)在某些类型的文件操作中比其他 GNU/Linux 文件系统更快。 有人指出,JFS 在处理大量文件时速度会变慢,但是[17][18]。 参考资料中包含一些基准测试的链接;但与往常一样,最好进行测试,看看哪种方法最适合您自己的系统和工作负载。
结论
JFS 是一个稳定、功能丰富的文件系统,但与其他一些 Linux 文件系统相比,其知名度不高。 通过优化,JFS 是稳定、CPU 高效且快速的。 特别是,VMWare 会话将从经过适当优化和碎片整理的底层 JFS 文件系统中获益匪浅。
参见
- 更技术性的 JFS 概述
- 使用 JFS 的 30 天
- JFS Sourceforge 页面
- 关于 JFS 文件系统碎片整理的说明
- JFS 恢复 Sourceforge 页面
- Steve Best 提供的关于 JFS 的演示文稿 (pdf)
- Debian 文件系统比较
- 维基百科:JFS (文件系统)
- 一些文件系统基准测试