第九章 系统调校

FreeBSD 是一个高效能的操作系统,预设的系统参数已符合大多数应用的需求。然而,针对不同的系统服务及软件应用,我们可以使用系统内附的工具来进行细部的调校。

本章包含下列关于效能调校的几个主题:

9.1 监看系统效能

在进行调校之前,我们可以先使用一些系统内附的工具来查看目前系统效能。我们之前已经介绍过 top 这个指令,它可以让我们看目前系统中所有行程的状况、CPU、内存、及虚拟内存的使用情形。这里我们介绍另一个好用的工具 systatsystat 可以用来显示网络使用情形、硬盘 I/O、CPU 等信息,可以说是最完整的系统监看工具。它的使用方法如下:

systat [-display] [refresh-interval]

其中 display 为我们所要显示的信息项目,我们也可以在进入 systat 后变更显示项目,而 refresh-interval 为多久要更新一次屏幕,单位是秒。以下为可用的 display 参数:

显示模式 意义
pigs 显示目前系统中使用 CPU 最多的行程名称。如果所有行程的 CPU 使用量未满 100%,则多出来的部份显示为 IDLE。
icmp 统计目前 ICMP 封包的进出情形。
icmp6 显示 IPv6 的 ICMP 封包进出情形。
ip 显示 IP 层的封包统计及 UDP 封包信息。
ip6 和 IP 一样,但只显示 IPv6 的封包。
tcp 显示 TCP 的封包统计。
iostat 显示 I/O 状况统计,并分类为各种模式显示。
swap 显示目前各个储存空间上的虚拟内存的使用情形。
mbufs 显示 mbufs 被使用的状态。
vmstat 这是我们最常用的显示模式,它显示了最多的信息,包含 I/O、虚拟内存、mbufs、网络等信息。
netstat 显示网络的使用情形。
ifstat 显示各个网络适配卡的使用情形。

进行 systat 之后,我们可以先按冒号「:」再打上述各种显示模式来变更显示的信息,如果要离开,则先按冒号,再按 quit 即可,或者也可以直接打「:q」。

让我们来看一下 vmstat 的情形,并指定每一秒钟更新一次画面:

# systat -vm 1
   4 users    Load  0.02  0.02  0.00                   6 11 13:35

Mem:KB    REAL            VIRTUAL                     VN PAGER  SWAP PAGER
        Tot   Share      Tot    Share    Free         in  out     in  out
Act   39068    4900   130008    10864   80100 count
All  182200    7440  2692520    17828         pages
                                                                Interrupts
Proc:r  p  d  s  w    Csw  Trp  Sys  Int  Sof  Flt        cow     368 total
             48       751    2  467  543   20       58304 wire    100 0: clk
                                                    66744 act         1: atkb
 2.3%Sys   0.0%Intr  0.8%User  0.0%Nice 96.9%Idl    47532 inact   128 8: rtc
|    |    |    |    |    |    |    |    |    |      10760 cache    71 9: vr0
=>                                                  69340 free     69 11: vr1
                                                          daefr       12: psm
Namei         Name-cache    Dir-cache                     prcfr       13: npx
   Calls     hits    %     hits    %                      react       14: ata
                                                          pdwak       15: ata
                                          zfod            pdpgs
Disks   ad0                               ofod            intrn
KB/t   0.00                               %slo-z    35664 buf
tps       0                               tfree        54 dirtybuf
MB/s   0.00                                         17812 desiredvnodes
% busy    0                                         16909 numvnodes
                                                     8706 freevnodes

如果您对于 systat 所显示的各个字段有疑问,请 man systat

9.2 使用 sysctl 调校

sysctl 是一个用来在系统运作中查看及调整系统参数的工具。有的 sysctl 参数只是用来回报目前的系统状况,例如回报目前已开机时间、所使用的操作系统版本、核心名称等等;而有的可以让我们修改参数以调整系统运作的行为,例如网络暂存内存的大小、最大的上线人数等等。而这些可以调整的参数中必须在一开机系统执行其它程序前就设定好,有的可以在开机完后任意调整。

首先我们可以使用下列指令来查看目前所有的 sysctl 参数及其状况:

# sysctl -a | more
kern.ostype: FreeBSD
kern.osrelease: 5.2.1-RELEASE
kern.osrevision: 199506
kern.version: FreeBSD 5.2.1-RELEASE #0: Sun Apr 11 16:16:08 CST 2004
   alex@alexwang.com:/usr/src/sys/i386/compile/ALEX

kern.maxvnodes: 17812
kern.maxproc: 2020
kern.maxfiles: 4040
kern.argmax: 65536
kern.securelevel: -1
kern.hostname: alexwang.com
kern.hostid: 0
kern.clockrate: { hz = 100, tick = 10000, profhz = 1024, stathz = 128 }
kern.posix1version: 200112
kern.ngroups: 16
kern.job_control: 1
kern.saved_ids: 0
kern.boottime: { sec = 1081672724, usec = 885137 } Sun Apr 11 16:38:44 2004
kern.domainname:
kern.osreldate: 502010
kern.bootfile: /boot/kernel/kernel
kern.maxfilesperproc: 3636
kern.maxprocperuid: 1818
kern.ipc.maxsockbuf: 262144
kern.ipc.sockbuf_waste_factor: 8
kern.ipc.somaxconn: 128
kern.ipc.max_linkhdr: 16
kern.ipc.max_protohdr: 60
kern.ipc.max_hdr: 76
kern.ipc.max_datalen: 132
kern.ipc.nmbclusters: 9024
………略………

我们也可以使用 sysctl 显示单一的参数值,例如:

# sysctl kern.ipc.maxsockbuf
kern.ipc.maxsockbuf: 262144

并非所有的参数都可以使用 sysctl 进行调整,而且有的参数对于效能的影响并不大。我们仅在此说明一些影响较明显的设定。

9.2.1 kern.ipc.maxsockets

这是用来设定系统最大可以开启的 socket 数目。如果您的服务器会提供大量的 FTP 服务,而且常快速的传输一些小档案,您也许会发现常传输到一半就中断。因为 FTP 在传输档案时,每一个档案都必须开启一个 socket 来传输,但关闭 socket 需要一段时间,如果传输速度很快,而档案又多,则同一时间所开启的 socket 会超过原本系统所许可的值,这时我们就必须把这个值调大一点。除了 FTP 外,也许有其它网络程序也会有这种问题。

然而,这个值必须在系统一开机就设定好,所以如果要修改这项设定,我们必须修改 /boot/loader.conf 才行。例如,我们要将它改成最多同时可以有 16424 个 socket,则必须在 /boot/loader.conf 中加入下列这一行:

kern.ipc.maxsockets="16424"

9.2.2 net.inet.ip.portrange.*

net.inet.ip.portrange.* 是用来控制 TCP 及 UDP 所使用的 port 范围,这个范围被分成三个部份,低范围、预设范围、及高范围。让我们看一下目前各范围 port 的情形:

# sysctl -a|grep portrange
net.inet.ip.portrange.lowfirst: 1023
net.inet.ip.portrange.lowlast: 600
net.inet.ip.portrange.first: 1024
net.inet.ip.portrange.last: 5000
net.inet.ip.portrange.hifirst: 49152
net.inet.ip.portrange.hilast: 65535

一般的网络程序都会用到预设范围的 port,然而,这个预设范围只从 1024 到 5000,这对于一台忙碌的 FTP server 或 proxy server 可能会有不足的情形。所以我们可以手动调整一下 net.inet.ip.portrange.last 这个值,将它调为 10000、20000、甚至 40000 都是合理的。如果要在一开机就调整这个值,我们可以修改 /etc/sysctl.conf,并增加下列这一行:

net.inet.ip.portrange.last=40000

9.2.3 kern.ipc.shm_use_phys

kern.ipc.shm_use_phys 这个选项预设为 0 (关闭),我们可以将它设为 1 (打开)。如果我们将它设成 1,则所有 System V 共享内存 (share memory,一种程序间沟通的方式)部份都会被留在实体的内存 (physical memory) 中,而不会被放到硬盘上的 swap 空间。我们知道物理内存的存取速度比硬盘快许多,而当物理内存空间不足时,部份数据会被放到虚拟的内存上,从物理内存和虚拟内存之间移转的动作就叫作 swap。如果时常做 swap 的动作,则需要一直对硬盘作 I/O,速度会很慢。因此,如果我们有大量的程序 (数百个) 需要共同分享一个小的共享内存空间,或者是共享内存空间很大时,我们可以将这个值打开。

这个值可以在开机完成后才设定,因此只要放在 /etc/sysctl.conf 中即可:

kern.ipc.shm_use_phys=1

9.2.4 vfs.vmiodirenable

这个选项预设被设为 1,也就是打开的状态。它被用来决定一个目录中的结构 (目录下的其它文件名称等等) 被快取在内存中的行为。一般的目录结构可能都不大,而这些目录结构会被快取在物理内存中。物理内存中所存放的目录结构快取有限,所以不管我们的物理内存有多大,预设都只会快取一定大小的目录结构。如果我们将这个选项打开,系统将 buffer cache 放在虚拟内存的快取中,目录结构也就会被存放在虚拟内存中。这样的好处是所有的内存空间都可以被拿来做目录的快取,而缺点是最小用来存放目录结构的快取会从 512 bytes 变成 4K。

如果您的系统物理内存空间有限,建议您将这个选项关闭。但如果您的系统需要进行大量档案操作,例如 proxy、多人使用的邮件服务器、或是 news server 等,建议将这个选项打开。

9.2.5 vfs.write_behind

这个选项预设为 1,也就是打开的状态。在打开时,在系统需要写入数据在硬盘或其它储存设备上时,它会等到收集了一个 cluster 单位的数据后再一次写入,否则会在一个暂存区空间有写入需求时就立即写到硬盘上。这个选项打开时,对于一个大档案写入速度非常有帮助。但如果您遇到有很多行程延滞在等待写入动作时,您可能必须关闭这个功能。

9.2.6 vfs.hirunningspace

这个值决定了系统可以将多少数据放在写入储存设备的等候区。通常使用默认值即可,但当我们有多颗硬盘时,我们可以将它调大为 4MB 或 5MB。但必须注意的是,太大的值反而会造成效能低落。

9.2.7 net.inet.tcp.sendspace 及 net.inet.tcp.recvspace

这二个选项分别控制了网络 TCP 联机所使用的传送及接收暂存区的大小。预设的传送暂存区为 32K,而接收暂存区为 64K。如果需要加速 TCP 的传输,可以将这二个值调大一点,但缺点是太大的值会造成系统核心占用太多的内存。如果我们的机器会同时服务数百或数千个网络联机,那么这二个选项最好维持默认值,否则会造成系统核心内存不足。但如果我们使用的是 gigabite 的网络,将这二个值调大会有明显效能的提升。传送及接收的暂存区大小可以分开调整,例如,假设我们的系统主要做为网页服务器,我们可以将接收的暂存区调小一点,并将传送的暂存区调大,如此一来,我们就可以避免占去太多的核心内存空间。

还有要注意的是,除了这二个选项可以控制网络传输暂存区大小外,route 这个指令也可以用来依路由路径的不同指定暂存区大小。另外 ipfw 等防火墙软件也可以用来限制每个联机所能使用的网络频宽。

如果我们将传送或接收的暂存区设为大于 65535,除非我们的服务器本身及客户端所使用的操作系统支持 TCP 协议的 windows scaling extension (请参考 RFC 1323 文件)。FreeBSD 预设已支援 rfs1323 (即 sysctl 的 net.inet.tcp.rfc1323 选项)。

9.2.8 net.inet.tcp.always_keepalive

当这个选项打开时,系统会定期送出「keepalives」以检查一个 TCP 联机是否中断。在打开的状况下,所有运作的网络程序都会有定时检查联机是否中断的功能,否则只有当应用程序本身支持时才有此功能。这个选项打开的好处是让系统更便于管理网络联机,尤其是当我们系统中常有一些莫名其妙就中断联机的使用者时。例如,当一个使用者利用拨接连到系统时,很可能在完成一个完整的 TCP 联机之前,就因为拨接中断而造成联机异常中断。当然,在某些情况下,也有可能会造成系统误判网络联机已中断而结束这个 TCP 联机。

9.2.9 net.inet.tcp.delayed_ack

TCP 协议有一个特性,就是当收到客户端的数据时,会传回一个 ACK (acknowledgement) 的封包,以确认已收到数据。然而,我们也可以将 ACK 封包和所要回传的资料一起送出。例如,当我使用 telnet 进入系统时,在输入指定时,当我们在键盘上敲打一个字符,系统会送回一个表示已接收到该字符的 ACK 封包,并传回一个含有该字符的封包以在终端机上显示。当 net.inet.tcp.delayed_ack 打开时,系统会将 ACK 和显示该字符的封包一传送,而不需分成二个封包。所以这个选项打开时,可以将封包数量减少一半,以加速网络传输。其它的网络服务,例如,WWW、SMTP、POP3 等也都具有这种特性。

9.2.10 kern.ipc.somaxconn

这个选项控制了 TCP 联机等候区最多可以等待的联机数量,其默认值为 128,不过这个值对于一台忙碌的服务器而言可能小了点。例如大型的网页服务器、邮件服务器,我们可以将它设为 1024。要注意的是在一些网络服务的程序中,如 Apache 及 sendmail 也有自己的等待数量设定,我们可能也要在那些软件上做一些设定才会让 kern.ipc.somaxconn 发生作用。将这个选项的值调大一点还有一个好处,就是在面对 Denial of service 的攻击时,有较好的防卫能力。

9.2.11 kern.maxfiles

这个选项控制了系统中支持最多开启的档案数量,这个值通常是几千个档,但对于一台忙碌的数据库系统或是会开启许多档案的服务器而言,我们可以将它调高为一、二万。

9.2.12 kern.maxusers

这是用来控制系统内部表格(internal system tables)大小的参数,它的值大约是您期望系统同一时间会上线使用的使用者数量。我们在核心设定档中有一个 maxusers 的选项,如果您使用的是 FreeBSD 4.5 以上的版本,建议您只要在核心设定档中将它 0 即可,系统会在一开机时自动依您的内存大小调整这个值。如果我们使用的是 FreeBSD 4.5 以后的版本,要调整这个值时,我们可以在 /boot/loader.conf 中加入该选项的设定,例如:

kern.maxusers=256

如果您使用 FreeBSD 4.4 以前的版本,则只能重新编译核心以改变这项设定。

这个值一定要设定大于四,maxusers 的值决定了处理程序所容许的最大值,20+16*maxusers 就是你将得到的所容许处理程序。系统一开机就必须要有 18 个处理程序 (process),即便是简单的执行指令 man 又会产生 9 个 process,所以将这个值设为 64 应该是一个合理的数目。如果你的系统会出现 proc table full 的讯息的话,可以就把它设大一点,例如 128。除非您的系统会需要同时开启很多档案,否则请不要设定超过 256。

9.2.13 kern.ipc.nmbclusters

这个值用来调整系统在开机后所要分配给网络 mbufs 的 cluster 数量,由于每个 cluster 大小为 2K,所以当这个值为 1024 时,也是会用到 2MB 的核心内存空间。我们可以简单的估计出大约需要的大小,例如,假设我们的网页同时约有 1000 个联机,而 TCP 传送及接收的暂存区大小都是 16K,则最糟的情况下,我们会需要 (16K+16K) * 1024,也就是 32MB 的空间,然而所需的 mbufs 大概是这个空间的二倍,也就是 64MB,所以所需的 cluster 数量为 64MB/2K,也就是 32768。对于内存有限的机器,建议值是 1024 到 4096 之间,而当拥有海量存储器空间时,我们可以将它设定为 4096 到 32768 之间。我们可以使用 netstat 这个指令并加上参数 -m 来查看目前所使用的 mbufs 数量。

当我们要修改这个值是,必须在一开机就修改,所以只能在 /boot/loader.conf 中加入修改的设定,例如:

kern.ipc.nmbclusters=16384

9.2.14 hw.ata.wc

这个选项用来打开 IDE 硬盘快取。当打开时,如果有数据要写入硬盘时,硬盘会假装已完成写入,并将数据快取起来。这种作法会加速硬盘的存取速度,但当系统异常关机时,比较容易造成数据遗失。不过由于关闭这个功能所带来的速度差异实在太大,建议您还是保留原本打开的状态吧。

9.3 调整硬盘参数

磁盘空间的配置对于系统效能影响很大,当我们在分割磁盘时,应该分割一个小型的空间给根目录,接着再分割一个空间给 swap,让这二个空间放在硬盘最外圈,以加速存取速度。最后再慢慢的分割其它的空间,并将最大的空间放到最后。例如,我们在建立磁盘空间时,可以依序建立以下的空间:/ (256MB)、Swap (512MB)、/tmp (512MB)、/var (256MB)、/usr (4GB)、/home (25GB),让最大的空间放到最后。

在分割硬盘时,我们可以依我们所提供的服务来决定各个分割区的大小。将整个硬盘只分割一个大的 / 分割区往往不一个好主意。首先,对于主要作为读取用途的目录和以写入为主的目录最好分开为不同的分割区,如此一来,我们可以针对这些不同用途的分割区进行调校。例如,/var 及 /var/tmp 常会被写入数据,而 /usr 通常只用来读取,在分割磁盘时,我们将最常写入的 /var、/var/tmp 放在最大的磁盘分割区 /home 之前,将有助于速度的提升。另外,我们将 / 独立分割成一个只会做读取动作的空间,在异常关机时,磁盘空间也比较不会损毁。分割成多个磁盘空间可以让我们使用 newfs 或 tunefs 等工具来进行调效,这也是只分割一个单一的空间所做不到的事。

FreeBSD 的档案系统在 block size 为 8K 或 16K 时有最好的表现,而使用 newfs 进行格式化时,预设的 block size 为 16K。然而,当我们的服务器是做为数据库用途时,由于数据库的存取是随机存取,所以在 block size 为 8K 时会有比较好的表现。如果我们将 block size 设为 16K 以上,比较容易造成空间浪费及空间破碎的问题,进而造成效能低落。
当我们的分割区主要存放大量小型档案时,例如 BBS 或 news server,我们会将 block size 调小一点,如 8K 或是 4K。而在 newfs 时,我们也会指定 fragment size,它的值最好是 block size 的八分之一,例如当 block size 为 8K 时,我们会使用 newfs -b 8192 -f 1024 来格式化硬盘。如果您使用的是 /stand/sysinstall 来分割硬盘,您可以在分割硬盘时按 N 来设定 newfs option。

当我们的分割区主要用来存放少量大文件时,例如数据库,我们可以使用 newfs 参数 -i 设定 inode 所占空间大一点以减少 inode 的数量 (也就是可以建立的档案及目录数量),让系统在不正常关机后,开机时进行 fsck 时可以快一点。不过在修改 inode 数量时要注意,否则您可能会遇到硬盘空间明明未满却无法新增档案的窘境。若要使用大型的 inode,FreeBSD 建议的 inode 大小为 32768、65536、或 262144,再大的话只会降低效能。

我们在使用 /stand/sysinstall 新增一个分割区时,您会发现在 Newfs 字段中,除了 / 及 swap 外,其它的分割区 newfs 字段都有一个 UFS2+S 的设定,如图 9-1 所示:

图 9-1

您所看到的 S 表示使用 Soft Updates。Soft Updates 可以用来加速系统写入档案及目录的系统数据,对于新增及删除档案的速度有明显的提升。Soft Updates 可以让我们在写入资料时保有完整性,在面临系统不正常关机时,能让所写入的数据尽量完整。而其缺点是在删除或更新档案时,硬盘空间的释放较慢,这个缺点在于一个快要满的分割区中比较明显。例如,当我们的 / 目录快满时,我们更新该分割区的数据时,可能会因为分割区在删除数据后空间释放较慢而使空间不足而失败,进而造成某些档案无法使用。所以 FreeBSD 预设并未在 / 目录中使用 Soft Updates。

Soft Update 除了可以在格式化硬盘时就将它启动外,FreeBSD 有一个用来调整硬盘参数的指令 tunefs 可以在分割完硬盘后启用 Soft Updates。不过 tunefs 只能在该储存空间尚未被挂入前使用,所以如果您要使用 tunefs,只能在单人模式下使用。

9.4 虚拟内存管理

如果您的内存很小,或者是您会跑一些需要用到海量存储器的程序时,您可能常常使用到虚拟内存 (swap partition)。当我们在分割 Swap 空间时,它的大小最少必须是物理内存的2.5 倍。例如,当我们有 128 MB RAM 时,最小应该要有 384MB 的 Swap。因为 FreeBSD 核心对于虚拟内存的管理上,当 Swap 有物理内存二倍以上时有最佳的效能。 现在的内存价格都不高,建议您最好让内存大一点以免使用到硬盘做为虚拟内存。如果一定会用到虚拟内存,太小的 swap 空间会造成效能低落,即使您不必用到那么大的空间,因为目前硬盘都很大,建议您还是将它的值调大一点。另外,当我们有多颗硬盘时,建议将 Swap 空间分别存放在每一个硬盘上,而且每颗硬盘上的 Swap 空间大小要一致,虽然大小不一致时,FreeBSD 还是可以处理,但效能会差很多。