LAMP系統性能調優 理解LAMP架構

如今,使用 LAMP(Linux ®、Apache、MySQLPHP /Perl )架構的應用程序不斷被開發和部署。但是,服務器 管理員對應用程序本身幾乎沒有控制能力,因爲應用程序是別人編寫的。這份共三部分的系列文章將討論許多服務器配置問題,這些配置會影響應用程序的性能。第一篇文章討論 LAMP 架構、一些性能度量技術以及一些基本的 Linux 內核、硬盤和文件系統調節。後續的文章將研究 Apache、MySQL 和 PHP 組件的調優。

Linux、 Apache、MySQL 和 PHP(或 Perl)是許多 Web 應用程序的基礎 —— 從 to-do 列表到 blog,再到電子商務站點。WordPress 和 Pligg 是兩個支持大容量 Web 站點的常用軟件包。這種架構簡稱爲 LAMP。幾乎每個 Linux 發佈版都包含 Apache、MySQL、PHP 和 Perl,所以安裝 LAMP 軟件是非常容易的。

安裝的簡便性使人誤以爲這些軟件會自行順利地運行,但是實際情況並非如此。最終,應用程序的負載會超出後端服務器自帶設置的處理能力,應用程序的性能會降低。LAMP 安裝需要不斷監控、調優和評估。

系統調優對於不同的人有不同的含義。本系列主要關注 LAMP 組件(Linux、Apache、MySQL 和 PHP)的調優。對應用程序本身進行調優是另一個複雜的問題。應用程序和後端服務器之間存在一種共生關係:未能適當調優的服務器甚至會使最好的應用程序在負載之下崩潰,而藉助充分的調優,完全可以避免編寫得很糟糕的應用程序使服務器緩慢如牛。幸運的是,正確的系統調優和監視可以指出應用程序中的問題。

LAMP 架構

對任何系統進行調優的第一步都是瞭解它的工作原理。按照最簡單的形式,基於 LAMP 的應用程序是用 PHP 這樣的腳本語言編寫的,它們作爲 Linux 主機上運行的 Apache Web 服務器的一部分運行。

PHP 應用程序通過請求的 URL、所有表單數據和已捕獲的任意會話信息從客戶機獲得信息,從而確定應該執行什麼操作。如有必要,服務器會從 MySQL 數據庫 (也在 Linux 上運行)獲得信息,將這些信息與一些 Hypertext Markup Language(HTML)模板組合在一起,並將結果返回給客戶機。當用戶在應用程序中導航時,這個過程重複進行;當多個用戶訪問系統時,這個過程會併發進行。但是,數據流不是單向的,因爲可以用來自用戶的信息更新數據庫,包括會話數據、統計數據(包括投票)和用戶提交的內容(比如評論或站點更新)。除了動態元素之外,還有靜態元素,比如圖像、Java Script 代碼和層疊樣式表(CSS)。

在研究 LAMP 系統中的請求流之後,就來看看可能出現性能瓶頸的地方。數據庫提供許多動態信息,所以數據庫對查詢的響應延遲都會反映在客戶機中。Web 服務器必須能夠快速地執行腳本,還要能夠處理多個併發請求。最後,底層操作系統 必須處於良好的狀態才能支持應用程序。通過網絡在不同服務器之間共享文件的其他設置也可能成爲瓶頸。

LAMP 的變體

LAMP 最初是指 Linux、Apache、MySQL 和 PHP(或 Perl)。但是,如果管理員不擅長 Linux,那麼可以在 Microsoft® Windows ® 上運行 Apache、MySQL 和 PHP,這並非一種少見的情況。同樣,也可以將 Apache 換成別的系統,比如 lighttpd,產生的仍然是 LAMP 風格的系統,但是首字母縮寫不再是 LAMP 了。也可以改用另一種開放源碼數據庫(比如 PostgreSQL 或 SQLite)、商業數據庫(比如 IBM® DB2®)或者免費的商業引擎(比如 IBM DB2 Express-C)。

本文主要關注傳統的 LAMP 架構,因爲這種架構是最常見的,而且它的組件都是開放源碼的。

度量性能

持續地對性能進行度量在兩個方面有幫助。首先,度量可以幫助瞭解性能趨勢,包括好壞兩方面的趨勢。作爲一個簡單的方法,查看一下 Web 服務器上的中央處理單元(CPU)使用率,就可以瞭解 CPU 是否負載過重。同樣,查看過去使用的總帶寬並推斷未來的變化,可以幫助判斷什麼時候需要進行網絡升級。這些度量最好與其他度量和觀測結合考慮。例如,當用戶抱怨應用程序太慢時,可以檢查磁盤操作是否達到了最大容量。

性能度量的第二個用途是,判斷調優是對系統性能有幫助,還是使它更糟糕了。方法是比較修改之前和之後的度量結果。但是,爲了進行有效的比較,每次應該只修改一個設置,然後對適當的指標進行比較以判斷修改的效果。每次只修改一個設置的原因應該是很明顯的:同時做出的兩個修改很可能會相互影響。選擇用來進行比較的指標比較微妙。

選擇的指標必須能夠反映應用程序用戶感覺到的響應。如果一項修改的目標是減少數據庫的內存佔用量,那麼取消各種緩衝區肯定會有幫助,但是這會犧牲查詢速度和應用程序性能。所以,應該選擇應用程序響應時間這樣的指標,這會使調優向着正確的方向發展,而不僅僅是針對數據庫內存使用量。

可以以許多方式度量應用程序響應時間。最簡單的方法可能是使用 curl 命令,見清單 1。

清單 1. 使用 cURL 度量 Web 站點的響應時間

  1. $ curl -o /dev/null -s -w %{time_connect}:%{time_starttransfer}:%{time_total}/
  2.     http://www.canada.com
  3. 0.081:0.272:0.779
複製代碼

清單 1 給出對一個流行的新聞站點執行 curl 命令的情況。輸出通常是 HTML 代碼,通過 -o 參數發送到 /dev/null。-s 參數去掉所有狀態信息。-w 參數讓 curl 寫出表 1 列出的計時器的狀態信息:

表 1. curl 使用的計時器

計時器 描述
time_connect 建立到服務器的 TCP 連接所用的時間
time_starttransfer 在發出請求之後,Web 服務器返回數據的第一個字節所用的時間
time_total 完成請求所用的時間



這些計時器都相對於事務的起始時間,甚至要先於 Domain Name Service(DNS)查詢。因此,在發出請求之後,Web服務器處理請求並開始發回數據所用的時間是 0.272 - 0.081 = 0.191 秒。客戶機從服務器下載數據所用的時間是 0.779 -0.272 = 0.507 秒。

通過觀察 curl 數據及其隨時間變化的趨勢,可以很好地瞭解站點對用戶的響應性。

當然,Web 站點不僅僅由頁面組成。它還有圖像、JavaScript 代碼、CSS 和 cookie 要處理。curl 很適合瞭解單一元素的響應時間,但是有時候需要了解整個頁面的裝載速度。

用於 Firefox 瀏覽器 的 Tamper Data 擴展可以在日誌中記錄 Web 瀏覽器發出的每個請求,並顯示每個請求所用的下載時間。使用這個擴展的方法是,選擇 Tools > Tamper Data 來打開 Ongoing requests 窗口。裝載要考察的頁面,然後就會看到瀏覽器發出的每個請求的狀態和裝載每個元素所用的時間。圖 1 給出裝載 developerWorks 主頁的結果。

圖 1. 用於裝載 developerWorks 主頁的請求細目
tamper1.jpg



每一行描述一個元素的裝載情況。顯示的數據包括髮出請求的時間、裝載所用的時間、大小和結果。Duration 欄列出裝載元素本身所用的時間,Total Duration 欄列出所有子元素所用的時間。在圖 1 中,裝載主要頁面所用的時間是 516 毫秒(ms),但是裝載所有東西並顯示整個頁面所用的時間是 5101 ms。

Tamper Data 擴展有一種有用的模式,將頁面裝載數據的輸出繪製成圖形。右擊 Ongoing requests 窗口上半部分的任何地方,並選擇 Graph all。圖 2 顯示圖 1 中數據的圖形化視圖。

圖 2. 用於裝載 developerWorks 主頁的請求的圖形化視圖
tamper2.jpg



在圖 2 中,每個請求的持續時間顯示爲深藍色,並相對於頁面裝載的啓始時間顯示。所以,可以看出哪些請求使整個頁面的裝載變慢了。

儘管關注的重點是頁面裝載時間和用戶體驗,但是也不要忽視核心系統指標,比如磁盤、內存和網絡。有許多實用程序可以捕獲這些信息;其中最有幫助的可能是 sar、vmstat 和 iostat。

基本系統調節

在對系統的 Apache、PHP 和 MySQL 組件進行調優之前,應該花一些時間確保底層 Linux 組件的運行正常。還應該對正在運行的服務進行縮減,只運行需要的那些服務。這不但是一種良好的安全實踐,而且可以節省內存和 CPU 時間。

一些快速的內核調優措施

大多數 Linux 發佈版都定義了適當的緩衝區和其他 Transmission Control Protocol(TCP)參數。可以修改這些參數來分配更多的內存,從而改進網絡性能。設置內核參數的方法是通過 proc 接口,也就是通過讀寫 /proc 中的值。幸運的是,sysctl 可以讀取 /etc/sysctl.conf 中的值並根據需要填充 /proc,這樣就能夠更輕鬆地管理這些參數。清單 2 展示在互聯網服務器上應用於 Internet 服務器的一些比較激進的網絡設置。

清單 2. 包含較爲激進的網絡設置的 /etc/sysctl.conf

  1. # Use TCP syncookies when needed
  2. net.ipv4.tcp_syncookies = 1
  3. # Enable TCP window scaling
  4. net.ipv4.tcp_window_scaling: = 1
  5. # Increase TCP max buffer size
  6. net.core.rmem_max = 16777216
  7. net.core.wmem_max = 16777216
  8. # Increase Linux autotuning TCP buffer limits
  9. net.ipv4.tcp_rmem = 4096 87380 16777216
  10. net.ipv4.tcp_wmem = 4096 65536 16777216
  11. # Increase number of ports available
  12. net.ipv4.ip_local_port_range = 1024 65000
複製代碼

將這些設置添加到 /etc/sysctl.conf 的現有內容中。第一個設置啓用 TCP SYN cookie。當從客戶機發來新的 TCP 連接時,數據包設置了 SYN 位,服務器就爲這個半開的連接創建一個條目,並用一個 SYN-ACK 數據包進行響應。在正常操作中,遠程客戶機用一個 ACK 數據包進行響應,這會使半開的連接轉換爲全開的。有一種稱爲 SYN 氾濫(SYN flood) 的網絡攻擊,它使 ACK 數據包無法返回,導致服務器用光內存空間,無法處理到來的連接。SYN cookie 特性可以識別出這種情況,並使用一種優雅的方法保留隊列中的空間(細節參見 參考資料 一節)。大多數系統都默認啓用這個特性,但是確保配置這個特性更可靠。

啓用 TCP 窗口伸縮使客戶機能夠以更高的速度下載數據。TCP 允許在未從遠程端收到確認的情況下發送多個數據包,默認設置是最多 64 KB,在與延遲比較大的遠程客戶機進行通信時這個設置可能不夠。窗口伸縮會在頭中啓用更多的位,從而增加窗口大小。

後面四個配置項增加 TCP 發送和接收緩衝區。這使應用程序可以更快地丟掉它的數據,從而爲另一個請求服務。還可以強化遠程客戶機在服務器繁忙時發送數據的能力。

最後一個配置項增加可用的本地端口數量,這樣就增加了可以同時服務的最大連接數量。

在下一次引導系統時,或者下一次運行 sysctl -p /etc/sysctl.conf 時,這些設置就會生效。

配置磁盤來提高性能

磁盤在 LAMP 架構中扮演着重要的角色。靜態文件、模板和代碼都來自磁盤,組成數據庫的數據表和索引也來自磁盤。對磁盤的許多調優(尤其是對於數據庫)集中於避免磁盤訪問,因爲磁盤訪問的延遲相當高。因此,花一些時間對磁盤硬件進行優化是有意義的。

首先要做的是,確保在文件系統上禁用 atime 日誌記錄特性。atime 是最近訪問文件的時間,每當訪問文件時,底層文件系統必須記錄這個時間戳。因爲系統管理員很少使用 atime,禁用它可以減少磁盤訪問時間。禁用這個特性的方法是,在 /etc/fstab 的第四列中添加 noatime 選項。清單 3 給出了一個配置示例。

清單 3. 演示如何啓用 noatime 的 fstab 示例

  1. /dev/VolGroup00/LogVol00 /                      ext3    defaults,noatime        1 1
  2. LABEL=/boot             /boot                   ext3    defaults,noatime        1 2
  3. devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
  4. tmpfs                   /dev/shm                tmpfs   defaults        0 0
  5. proc                    /proc                   proc    defaults        0 0
  6. sysfs                   /sys                    sysfs   defaults        0 0
  7. LABEL=SWAP-hdb2         swap                    swap    defaults        0 0
  8. LABEL=SWAP-hda3         swap                    swap    defaults        0 0
複製代碼

在清單 3 中只修改了 ext3 文件系統,因爲 noatime 只對駐留在磁盤上的文件系統有幫助。爲讓這一修改生效,不需要重新引導;只需重新掛裝每個文件系統。例如,爲了重新掛裝根文件系統,運行 mount / -o remount。

有多種磁盤硬件組合,而且 Linux 不一定能夠探測出訪問磁盤的最佳方式。可以使用 hdparm 命令查明和設置用來訪問 IDE 磁盤的方法。hdparm -t /path/to/device 執行速度測試,可以將這個測試結果作爲性能基準。爲了使結果儘可能準確,在運行這個命令時系統應該是空閒的。清單 4 給出在 hda 上執行速度測試的結果。

清單 4. 在 /dev/hd 上執行的速度測試

  1. # hdparm -t /dev/hda
  2. /dev/hda:
  3. Timing buffered disk reads:  182 MB in  3.02 seconds =  60.31 MB/sec
複製代碼

這一測試說明,在這個磁盤上讀取數據的速度是大約每秒 60 MB。

在嘗試一些磁盤調優選項之前,必須注意一個問題。錯誤的設置可能損害文件系統。有時候會出現一個警告,指出這個選項與硬件不兼容;但是,有時候沒有警告消息。因此,在將系統投入生產之前,必須對設置進行徹底的測試。在所有服務器上都採用標準的硬件也會有所幫助。

表 2 列出比較常用的一些選項。

表 2. hdparm 的常用選項

選項 描述
-vi 向磁盤查詢它支持的設置以及它正在使用的設置。
-c 查詢/啓用 (E)IDE 32 位 I/O 支持。hdparm -c 1 /dev/hda 啓用這個設置。
-m 查詢/設置每中斷多扇區模式。如果設置大於零,設置值就是每個中斷可以傳輸的最大扇區數量。
-d 1 -X 啓用直接內存訪問(DMA)傳輸並設置 IDE 傳輸模式。hdparm 手冊頁詳細說明了在 -X 後面可以設置的數字。只有在 -vi 說明目前並未使用最快速的模式的情況下,才需要進行這個設置。



不幸的是,對於 Fiber Channel and Small Computer Systems Interface(SCSI)系統,調優依賴於具體的驅動器。

必須將有幫助的設置添加到啓動腳本中,比如 rc.local。

網絡文件系統調優

網絡文件系統(NFS)是一種通過網絡共享磁盤的方法。NFS 可以幫助確保每個主機具有相同數據的拷貝,並確保修改反映在所有節點上。但是,在默認情況下,NFS 的配置不適合大容量磁盤。

每個客戶機應該用 rsize=32768,wsize=32768,intr,noatime 掛裝遠程文件系統,從而確保:

    * 使用大的讀/寫塊(數字指定最大塊大小,在這個示例中是 32KB)。
    * 在掛起時 NFS 操作可以被中斷。
    * 不持續更新 atime。


可以將這些設置放在 /etc/fstab 中,見 清單 3。如果使用自動掛裝器,那麼應該將這些設置放在適當的 /etc/auto.* 文件中。

在服務器端,一定要確保有足夠的 NFS 內核線程來處理所有客戶機。在默認情況下,只啓動一個線程,但是 Red Hat 和 Fedora 系統會啓動 8 個線程。對於繁忙的 NFS 服務器,應該提高這個數字,比如 32 或 64。可以用 nfsstat -rc 命令評估客戶機,瞭解是否有阻塞的現象,這個命令顯示客戶機遠程過程調用(RPC)統計數據。清單 5 顯示一個 Web 服務器的客戶機統計數據。

清單 5. 顯示 NFS 客戶機的 RPC 統計數據

  1. # nfsstat -rc
  2. Client rpc stats:
  3. calls      retrans    authrefrsh
  4. 1465903813   0          0
複製代碼

第二列 retrans 是零,這表示從上一次重新引導以來沒有出現需要重新傳輸的情況。如果這個數字比較大,就應該考慮增加 NFS 內核線程。設置方法是將所需的線程數量傳遞給 rpc.nfsd,比如 rpc.nfsd 128 會啓動 128 個線程。任何時候都可以進行這種設置。線程會根據需要啓動或銷燬。同樣,這個設置應該放在啓動腳本中,尤其是在系統上啓用 NFS 的腳本。

關於 NFS,最後要注意一點:如果可能的話,應該避免使用 NFSv2,因爲 NFSv2 的性能比 v3 和 v4 差得多。在現代的 Linux 發行版中這應該不是問題,但是可以在服務器上檢查 nfsstat 的輸出,瞭解是否有任何 NFSv2 調用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章