12.12. 调整磁盘
上一页 | 第 12 章 设置和调整 | 下一页

## 12.12. 调整磁盘

### 12.12.1. Sysctl 变量

#### 12.12.1.1. `vfs.vmiodirenable`

`vfs.vmiodirenable` sysctl 变量可以设置成0(关)或者1(开)；默认是1。 这个变量控制目录是否被系统缓存。大多数目录是小的， 在系统中只使用单个片断(典型的是1K)并且在缓存中使用的更小 (典型的是512字节)。当这个变量设置为关闭 (`0`) 时， 缓存器仅仅缓存固定数量的目录，即使您有很大的内存。 而将其开启 (设置为1) 时， 则允许缓存器用 VM 页面缓存来缓存这些目录，让所有可用内存来缓存目录。 不利的是最小的用来缓存目录的核心内存是大于 512 字节的物理页面大小(通常是 4k)。 我们建议如果您在运行任何操作大量文件的程序时保持这个选项打开的默认值。 这些服务包括 web 缓存，大容量邮件系统和新闻系统。 尽管可能会浪费一些内存，但打开这个选项通常不会降低性能。 但还是应该检验一下。

#### 12.12.1.2. `vfs.write_behind`

`vfs.write_behind` sysctl 变量默认是 `1` (打开)。 它告诉文件系统簇被收集满的时候把内容写进介质， 典型的是在写入大的连续的文件时。 主要的想法是， 如果可能对 I/O 性能会产生负面影响时， 应尽量避免让缓冲缓存被未同步缓冲区充满。 然而它可能降低处理速度并且在某些情况下您可能想要关闭它。

#### 12.12.1.3. `vfs.hirunningspace`

`vfs.hirunningspace` sysctl 变量决定了在任何给定情况下， 有多少写 I/O 被排进队列以给系统的磁盘控制器。 默认值一般是足够的，但是对有很多磁盘的机器来说您可能需要把它设置成 4M 或 5M。注意这个设置成很高的值(超过缓存器的写极限)会导致坏的性能。 不要盲目的把它设置太高！高的数值会导致同时发生的读操作的迟延。

sysctl 中还有许多与 buffer cache 和 VM页面 cache 有关的值， 一般不推荐修改它们。 虚拟内存系统已经能够很好地进行自动调整了。

#### 12.12.1.4. `vm.swap_idle_enabled`

`vm.swap_idle_enabled` sysctl 变量在有很多用户进入、离开系统和有很多空闲进程的大的多用户系统中很有用。 这些系统注重在空闲的内存中间产生连续压力的处理。通过 `vm.swap_idle_threshold1` 和 `vm.swap_idle_threshold2` 打开这个特性并且调整交换滞后 (在空闲时)允许您降低内存页中空闲进程的优先权，从而比正常的出页 (pageout)算法更快。这给出页守护进程带来了帮助。 除非您需要否则不要把这个选项打开，因为您所权衡的是更快地进入内存， 因而它会吃掉更多的交换和磁盘带宽。在小的系统上它会有决定性的效果， 但是在大的系统上它已经做了合适的页面调度这个选项允许 VM 系统容易的让全部的进程进出内存。

#### 12.12.1.5. `hw.ata.wc`

FreeBSD 4.3 中默认将 IDE 的写缓存关掉了。 这会降低到 IDE 磁盘用于写入操作的带宽， 但我们认为这有助于避免硬盘厂商所引入的， 可能引致严重的数据不一致问题。 这类问题实际上是由于 IDE 硬盘就写操作完成这件事的不诚实导致的。 当启用了 IDE 写入缓存时， IDE 硬盘驱动器不但不会按顺序将数据写到盘上， 而且当磁盘承受重载时， 它甚至会自作主张地对推迟某些块的实际写操作。 这样一来， 在系统发生崩溃或掉电时， 就会导致严重的文件系统损坏。 基于这些考虑， 我们将 FreeBSD 的默认配置改成了更为安全的禁用 IDE 写入缓存。 然而不幸的是， 这样做导致了性能的大幅降低， 因此在后来的发行版中这个配置又改为默认启用了。 您可以通过观察 `hw.ata.wc` sysctl 变量， 来确认您的系统中所采用的默认值。 如果 IDE 写缓存被禁用， 您可以通过将内核变量设置为 1 来启用它。 这一操作必须在启动时通过 boot loader 来完成。 在内核启动之后尝试这么做是没有任何作用的。

要了解更多的信息，请查阅 ata(4)。

#### 12.12.1.6. `SCSI_DELAY` (`kern.cam.scsi_delay`)

`SCSI_DELAY` 内核配置会缩短系统启动时间。 默认值在系统启动过程中有 `15` 秒的迟延时间， 这是一个足够多且可靠的值。把它减少到 `5` 通常也能工作(特别是现代的驱动器)。 您可以在系统引导时调整引导加载器变量 `kern.cam.scsi_delay` 来改变它。 需要注意的是， 此处使用的单位是 毫秒 而 不 是 秒 。

### 12.12.2. Soft Updates

tunefs(8) 程序能够用来很好的调整文件系统。 这个程序有很多不同的选项，但是现在只介绍 Soft Updates 的打开和关闭，这样做：

`#` `tunefs -n enable /filesystem` `#` `tunefs -n disable /filesystem`

在文件系统被挂载之后不能用 tunefs(8) 来修改。打开 Soft Updates 的最佳时机是在单用户模式下任何分区被挂载前。

Soft Updates 极大地改善了元数据修改的性能， 主要是文件创建和删除，通过内存缓存。我们建议您在所有的文件系统上使用 Soft Updates。应该知道 Soft Updates 的两点：首先， Soft Updates 保证了崩溃后的文件系统完整性，但是很可能有几秒钟 (甚至一分钟！) 之前的数据没有写到物理磁盘。如果您的系统崩溃了您可能会丢失很多工作。 第二，SoftUpdates 推迟文件系统块的释放时间。如果在文件系统 (例如根文件系统)快满了的情况下对系统进行大规模的升级比如 `make installworld`， 可能会引起磁盘空间不足从而造成升级失败。

#### 12.12.2.1. Soft Updates 的详细资料

有两种传统的方法来把文件系统的元数据 (meta-data) 写入磁盘。 (Meta-data更新是更新类似 inodes 或者目录这些没有内容的数据)

从前，默认方法是同步更新这些元数据(meta-data)。 如果一个目录改变了，系统在真正写到磁盘之前一直等待。 文件数据缓存(文件内容)在这之后以非同步形式写入。 这么做有利的一点是操作安全。如果更新时发生错误，元数据(meta-data) 一直处于完整状态。文件要不就被完整的创建要不根本就不创建。 如果崩溃时找不到文件的数据块，fsck(8) 可以找到并且依靠把文件大小设置为 0 来修复文件系统。 另外，这么做既清楚又简单。缺点是元数据(meta-data)更新很慢。例如 `rm -r` 命令，依次触及目录下的所有文件， 但是每个目录的改变(删除一个文件)都要同步写入磁盘。 这包含它自己更新目录，inode 表和可能对文件分散的块的更新。 同样问题出现大的文件操作上(比如 `tar -x`)。

第二种方法是非同步元数据更新。这是 Linux/ext2fs 和 *BSD ufs 的 `mount -o async` 默认的方法。所有元数据更新也是通过缓存。 也就是它们会混合在文件内容数据更新中。 这个方法的优点是不需要等待每个元数据更新都写到磁盘上， 所以所有引起元数据更新大的操作比同步方式更快。同样， 这个方法也是清楚且简单的，所以代码中的漏洞风险很小。 缺点是不能保证文件系统的状态一致性。如果更新大量元数据时失败 (例如掉电或者按了重启按钮)，文件系统会处在不可预知的状态。 系统再启动时没有机会检查文件系统的状态；inode 表更新的时候可能文件的数据块已经写入磁盘了但是相关联的目录没有，却不能用 `fsck` 命令来清理(因为磁盘上没有所需要的信息)。 如果文件系统修复后损坏了，唯一的选择是使用 newfs(8) 并且从备份中恢复它。

这个问题通常的解决办法是使用 dirty region logging 或者 journaling 尽管它不是一贯的被使用并且有时候应用到其他的事务纪录中更好。 这种方法元数据更新依然同步写入，但是只写到磁盘的一个小区域。 过后他们将会被移动到正确的位置。因为纪录区很小， 磁盘上接近的区域磁头不需要移动很长的距离，所以这些比写同步快一些。 另外这个方法的复杂性有限，所以出现错误的机会也很少。缺点是元数据要写两次 (一次写到纪录区域，一次写到正确的区域)。正常情况下， 悲观的性能可能会发生。从另一方面来讲， 崩溃的时候所有未发生的元数据操作可以很快的在系统启动之后从记录中恢复过来。

Kirk McKusick，伯克利 FFS 的开发者，用 Soft Updates 解决了这个问题：元数据更新保存在内存中并且按照排列的顺序写入到磁盘 (“有序的元数据更新”)。这样的结果是，在繁重的元数据操作中， 如果先前的更新还在内存中没有被写进磁盘，后来的更新就会捕捉到。 所以所有的目录操作在写进磁盘的时候首先在内存中执行 (数据块按照它们的位置来排列，所以它们不会在元数据前被写入)。 如果系统崩溃了这将导致一个固定的 “日志回朔”： 所有不知如何写入磁盘的操作都像没有发生过一样。文件系统的一致性保持在 30 到 60 秒之前。它保证了所有正在使用的资源被标记例如块和 inodes。崩溃之后， 唯一的资源分配错误是一个实际是“空闲”的资源的资源被标记为“使用”。 fsck(8) 可以认出这种情况并且释放不再使用的资源。它对于忽略崩溃后用 `mount -f` 强制挂上的文件系统的错误状态是安全的。 为了释放可能没有使用的资源，fsck(8) 需要在过后的时间运行。一个主意是用 后台 fsck：系统启动的时候只有一个文件系统的 快照 被记录下来。`fsck` 可以在过后运行。所有文件系统可以在“有错误”的时候被挂接， 所以系统可以在多用户模式下启动。接着，后台 `fsck` 可以在所有文件系统需要的时候启动来释放可能没有使用的资源。 (尽管这样，不用 Soft Updates 的文件系统依然需要通常的 `fsck`。)

它的优点是元数据操作几乎跟非同步一样快 (也就是比需要两次元数据写操作的 logging 更快)。缺点是代码的复杂性(意味着对于丢失用户敏感数据有更多的风险) 和高的内存使用量。另外它有些特点需要知道。崩溃之后， 文件系统状态会“落后”一些。同步的方法用 `fsck` 后在一些地方可能产生一些零字节的文件， 这些文件在用 Soft Updates 文件系统之后不会存在， 因为元数据和文件内容根本没有写进磁盘(可能发生在运行 `rm` 之后)。这可能在文件系统上安装大量数据时候引发问题， 没有足够的剩余空间来两次存储所有文件。

上一页 | 上一级 | 下一页
12.11. 用 sysctl 进行调整 | 起始页 | 12.13. 调整内核限制

本文档和其它文档可从这里下载： ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

如果对于FreeBSD有问题，请先阅读 文档，如不能解决再联系 <questions@FreeBSD.org>.
关于本文档的问题请发信联系 <doc@FreeBSD.org>.