支援人員分析師們常常接到使用者對伺服器高負載的控訴。事實上cPanel軟體及其安裝的應用很少引發伺服器高負載情況。伺服器擁有者、系統管理員或者伺服器供應商應當對高負載狀況進行初步調查,並在確認情況複雜後再向分析人士求助。
伺服器高負載因何而起?
下列項目的過度使用會直接導致高負載問題:
該如何檢查這些項目?
這取決於大家是要審查當前資源使用方式還是曆史資源使用方式。當然,在本文中我們將從這兩方面進行探討。
關於sar的簡要說明
曆史資源使用方式可通過sar工具查看,該工具在預設情況下應該通過sysstat軟體包安裝在所有cPanel伺服器當中。只要通過cron命令對sysstat進行周期性執行(/etc/cron.d/sysstat),伺服器的運行狀態資料就會被收集起來。如果cron沒有運行,sysstat將無法收集曆史統計結果。
要在sar中查看曆史資源使用方式,我們必須為檔案提供與統計資料相符的路徑。
舉例來說,如果大家打算查看本月23號以來伺服器的平均負載狀況,可以運行以下命令:
代碼:
[user@host ~]$ sar -q -f /var/log/sa/sa23
以上命令中的-q用於擷取平均負載資訊,而-f則用於指定sar從哪個檔案中擷取資訊。請注意,sar可能無法使用一周之前乃至更早的運行資訊。
如果大家打算查看當前日期的統計資訊,則不必為其指令具體時間。輸入以下命令即可顯示今天的平均負載情況:
代碼:
[user@host ~]$ sar -q
我們強烈建議大家閱讀sar說明文檔:
代碼:
[user@host ~]$ man sar
它所提供的統計資訊能夠協助我們確切掌握伺服器的運行狀態。
當前CPU使用方式
運行top,並在Cpu(s)一行中檢查%id部分所顯示的閑置CPU百分比。該數字越高結果越好,說明CPU的工作負載不強。處於99%閑置狀態下的CPU幾乎沒有處理任何實際任務,而處於1%閑置狀態下的CPU則意味著接近滿載。
代碼:
[user@host ~]$ top c
提示:可加寫P根據消耗CPU資源的多少對進程加以分類。
曆史CPU使用方式
查看“%idle”列:
代碼:
[user@host ~]$ sar -p
當前記憶體使用量情況
代碼:
[user@host ~]$ free -m
提示:運行top c並加寫M可查看哪個進程佔用的記憶體量最大。
曆史記憶體使用量情況
根據sar版本的不同,命令內容也有所區別。早期版本通過添加“-r”參數顯示記憶體使用量百分比與虛擬記憶體使用百分比,但新版本則改用“-s”參數顯示虛擬記憶體使用百分比。
Check %memused and %swpused:
代碼:
[user@host ~]$ sar -r
或者:
代碼:
[user@host ~]$ sar -r
代碼:
[user@host ~]$ sar -S
記憶體使用量情況提示:伺服器記憶體佔用量較高的情況其實非常正常。這是因為記憶體的讀寫速度及效率遠高於伺服器磁碟,因此作業系統傾向於將記憶體作為緩衝機制預先載入資料,從而提高資料讀取速度。
同樣,記憶體使用量百分比也並不是什麼大問題(除非大家沒有設定虛擬記憶體分區,但這也與記憶體本身無關)。大家真正需要關注的是虛擬記憶體使用百分比,因為只有在伺服器的實體記憶體被全部佔用後、虛擬記憶體才會接替而上發揮作用。這一數字越低,就說明伺服器的運行狀態越好。如果虛擬記憶體使用率為0%,則意味著我們的伺服器能夠完全利用實體記憶體執行任務。
那麼虛擬記憶體使用率達到多少才算過高?這取決於大家自己的感覺。一般來說,如果虛擬記憶體使用率一直不高、那麼我們的伺服器的運行狀態還是比較理想的。如果大家發現虛擬記憶體使用率隨時間不斷提升(例如由1%到7%再到32%),這就代表格服務器上的某些進程正在瘋狂吞噬記憶體,我們需要及時展開調查以瞭解具體情況(而不該直接安裝更多記憶體)。一旦伺服器用盡了所有實體記憶體與虛擬記憶體,那麼整套系統的運行將變得極為緩慢,需要經過重啟才能暫時恢複正常。
當前磁碟I/O使用方式
注意:這一項對於OpenVZ/Virtuozzo容器不起作用。
以下命令將以每秒一次的頻率連續顯示十次磁碟使用率統計。請大家關注顯示結果中的%util列:
代碼:
[user@host ~]$ iostat -x 1 10
曆史磁碟I/O使用方式
代碼:
[user@host ~]$ sar -d
優秀的系統管理員能夠準確把握伺服器負載的基準線,並在當前負載超出基準時立即做出判斷。這樣做的主要目的(除了防止伺服器陷入半癱瘓並不得不重新啟動之外)是為了及時瞭解負載高企時伺服器正在運行哪些項目。快速反應能協助大家在發現問題後第一時間進行故障排查。
如果伺服器負載過高的狀況出現在淩晨兩點到四點之間,那麼正在熟睡中的我們肯定無法馬上展開調查。雖然sar會一直守護在伺服器身邊,幫我們收集這段時間內到底哪些資源的使用率居高不下,但卻無法揭示問題出現的實際原因。引發負載過高的原因多種多樣,其中包括DoS攻擊、垃圾郵件攻擊、php指令碼設計不當、網路蜘蛛在繪製網狀圖譜時太過積極、硬體故障、針對使用者MySQL資料庫的磁碟寫入量暴增等等。
好訊息是,大家可以利用工具收集這些資訊,並在負載過高後將結果自動發送過來。如何??從進程列表入手:
代碼:
[user@host ~]$ ps auxwwwf
我建立了一個shell指令碼,以我曾經管理過的伺服器上的一套perl指令碼為基礎。這套指令碼與其它伺服器監控工具(例如Nagios)配合起來給我的工作帶來諸多便利。它能檢查六種不同項目(下面將詳細介紹),並在進程列表中的條目超出閾值時向我發送郵件通知。
注意:cPanel公司對該指令碼的開發、維護或支援人員不承擔責任。請不要就這款指令碼提出服務申請。如果您在使用中遇到任何問題,請到相關論壇上發帖或請教有經驗的系統管理員。cPanel不提供與此指令碼相關的任何支援。
它所檢查的具體資來源物件如下:
- 一分鐘平均負載
- 虛擬記憶體使用數量(單位為KB)
- 記憶體使用量數量(單位為KB)
- 每秒接收資料包數量
- 每秒發出資料包數量
- 進程總數
如何使用指令碼
要自動運行此指令碼,大家需要設定一項cron任務並根據實際情況設定運行頻率。我發現每五分鐘運行一次是個不錯的選擇。該指令碼無需使用root身份運行,既然如此我們也就不必為其分配高許可權。
如果上述監控資來源物件中的某一項超過使用者自訂的閾值,指令碼會自動發送一封電子郵件,其中包含當前進程列表內容。
電子郵件的主旨列如下所示:
代碼:
server.example.com [L: 35] [P: 237] [Swap Use: 1% ] [pps in: 54 pps out: 289]
下面我們一一解釋其中的條目:
- L代表一分鐘平均負載
- P代表當前進程列表中的進程數量
- Swap Usage代表虛擬記憶體使用百分比
- pps in代表每秒接收資料包數量
- pps out代表每秒發出資料包數量
指令碼使用前的注意事項
重要事項:大家需要根據自己的理解來調整指令碼中的數值。完美的預設值設定並不存在,因為不同的伺服器環境在實際運行中所應遵循的標準也不一樣。舉例來說,擁有十六個CPU核心的伺服器在一分鐘平均負載方面肯定要高於只擁有一個CPU核心的伺服器。
注意:大家需要將自己的電子郵箱地址添加到EMAIL變數當中,如下所示:
代碼:
以下五項也需要根據實際情況加以調整:
- MAX_LOAD
- MAX_SWAP_USED
- MAX_MEM_USED
- MAX_PPS_OUT
- MAX_PPS_IN
EMAIL=you@example.com
代碼:#!/bin/sh export PATH=/bin:/usr/bin ########################################################################## # # # Copyright Jeff Petersen, 2009 - 2013 # # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see <http://www.gnu.org/licenses/>. # # # ########################################################################## ############################################################################### # START USER CONFIGURABLE VARIABLES ############################################################################### EMAIL="you@example.com" # 1 minute load avg MAX_LOAD=3 # kB MAX_SWAP_USED=1000 # kB MAX_MEM_USED=500000 # packets per second inbound MAX_PPS_IN=2000 # packets per second outbound MAX_PPS_OUT=2000 # max processes in the process list MAX_PROCS=400 ############################################################################### # END USER CONFIGURABLE VARIABLES ############################################################################### IFACE=`grep ETHDEV /etc/wwwacct.conf | awk '{print $2}'` if [[ "$IFACE" =~ "venet" ]] ; then IFACE=venet0 fi IFACE=${IFACE}: ############################################################################### # 1 min load avg ############################################################################### ONE_MIN_LOADAVG=`cut -d . -f 1 /proc/loadavg` echo "1 minute load avg: $ONE_MIN_LOADAVG" ############################################################################### # swap used ############################################################################### SWAP_TOTAL=`grep ^SwapTotal: /proc/meminfo | awk '{print $2}'` SWAP_FREE=`grep ^SwapFree: /proc/meminfo | awk '{print $2}'` let "SWAP_USED = (SWAP_TOTAL - SWAP_FREE)" echo "Swap used: $SWAP_USED kB" ############################################################################### # mem used ############################################################################### MEM_TOTAL=`grep ^MemTotal: /proc/meminfo | awk '{print $2}'` MEM_FREE=`grep ^MemFree: /proc/meminfo | awk '{print $2}'` let "MEM_USED = (MEM_TOTAL - MEM_FREE)" echo "Mem used: $MEM_USED kB" ############################################################################### # packets received ############################################################################### PACKETS_RX_1=`grep $IFACE /proc/net/dev | awk '{print $2}'` sleep 2; PACKETS_RX_2=`grep $IFACE /proc/net/dev | awk '{print $2}'` let "PACKETS_RX = (PACKETS_RX_2 - PACKETS_RX_1) / 2" echo "packets received (2 secs): $PACKETS_RX" ############################################################################### # packets sent ############################################################################### PACKETS_TX_1=`grep $IFACE /proc/net/dev | awk '{print $10}'` sleep 2; PACKETS_TX_2=`grep $IFACE /proc/net/dev | awk '{print $10}'` let "PACKETS_TX = (PACKETS_TX_2 - PACKETS_TX_1) / 2" echo "packets sent (2 secs): $PACKETS_TX" let "SWAP_USED = SWAP_TOTAL - SWAP_FREE" if [ ! "$SWAP_USED" == 0 ] ; then PERCENTAGE_SWAP_USED=`echo $SWAP_USED / $SWAP_TOTAL | bc -l` TOTAL_PERCENTAGE=`echo ${PERCENTAGE_SWAP_USED:1:2}%` else TOTAL_PERCENTAGE='0%' fi ############################################################################### # number of processes ############################################################################### MAX_PROCS_CHECK=`ps ax | wc -l` send_alert() { SUBJECTLINE="`hostname` [L: $ONE_MIN_LOADAVG] [P: $MAX_PROCS_CHECK] [Swap Use: $TOTAL_PERCENTAGE ] [pps in: $PACKETS_RX pps out: $PACKETS_TX]" ps auxwwwf | mail -s "$SUBJECTLINE" $EMAIL exit } if [ $ONE_MIN_LOADAVG -gt $MAX_LOAD ] ; then send_alert elif [ $SWAP_USED -gt $MAX_SWAP_USED ] ; then send_alert elif [ $MEM_USED -gt $MAX_MEM_USED ] ; then send_alert elif [ $PACKETS_RX -gt $MAX_PPS_IN ] ; then send_alert elif [ $PACKETS_TX -gt $MAX_PPS_OUT ] ; then send_alert elif [ $MAX_PROCS_CHECK -gt $MAX_PROCS ] ; then send_alert fi
需要注意的是,進程列表的輸出內容中包含一些有用的數列,涉及各個進程的CPU與記憶體使用量情況:
- %CPU
- %MEM
- VSZ
- RSS
- TIME (顯示一個進程的存在時間)
我們可以通過多種方式剖析伺服器負載高企的原因。下面我們列出幾項常用方案--僅供參考,並不全面:
- 利用mysqladmin processlist (或者簡寫為'mysqladmin pr')檢查MySQL進程列表
- 利用mytop檢查MySQL進程列表
- 查閱記錄檔。瞭解伺服器自身的反饋意見也很重要。您的伺服器是否遭遇暴力破解?
- 運行dmesg以檢查可能存在的硬體故障
- 利用netstat查看伺服器串連
下面則是值得關注的記錄檔及其儲存路徑:
- 系統日誌: /var/log/messages, /var/log/secure
- SMTP日誌: /var/log/exim_mainlog, /var/log/exim_rejectlog, /var/log/exim_paniclog
- POP3/IMAP日誌: /var/log/maillog
- Apache日誌: /usr/local/apache/logs/access_log, /usr/local/apache/logs/error_log, /usr/local/apache/logs/suexec_log, /usr/local/apache/logs/suphp_log
- 網站日誌: /usr/local/apache/domlogs/ (use this to find sites with traffic in the last 60 seconds: find -maxdepth 1 -type f -mmin -1 | egrep -v 'offset|_log$')
- Cron日誌: /var/log/cron
大家也可以在評論欄中反饋您在工作中遇到的問題、對本篇文章的評論及其它任何希望與朋友們分享的資訊。作為一篇獨立的指導性文章,我們不可避免會存在遺漏或者疏忽,期待您提出寶貴意見、也希望大家能從中受到一點啟發。