第九章 系統調校

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 還是可以處理,但效能會差很多。