Linux服務(wù)器中高負(fù)載現(xiàn)象故障排查指南
譯文【2013年7月11日 51CTO外電頭條】技術(shù)支持分析師們常常接到用戶對服務(wù)器高負(fù)載的控訴。事實上cPanel軟件及其安裝的應(yīng)用很少引發(fā)服務(wù)器高負(fù)載情況。服務(wù)器擁有者、系統(tǒng)管理員或者服務(wù)器供應(yīng)商應(yīng)當(dāng)對高負(fù)載狀況進(jìn)行初步調(diào)查,并在確認(rèn)情況復(fù)雜后再向分析人士求助。
服務(wù)器高負(fù)載因何而起?
下列項目的過度使用會直接導(dǎo)致高負(fù)載問題:
- CPU
- 內(nèi)存(包括虛擬內(nèi)存)
- 磁盤I/O
該如何檢查這些項目?
這取決于大家是要審查當(dāng)前資源使用情況還是歷史資源使用情況。當(dāng)然,在本文中我們將從這兩方面進(jìn)行探討。
關(guān)于sar的簡要說明
歷史資源使用情況可通過sar工具查看,該工具在默認(rèn)情況下應(yīng)該通過sysstat軟件包安裝在所有cPanel服務(wù)器當(dāng)中。只要通過cron命令對sysstat進(jìn)行周期性執(zhí)行(/etc/cron.d/sysstat),服務(wù)器的運行狀態(tài)數(shù)據(jù)就會被收集起來。如果cron沒有運行,sysstat將無法收集歷史統(tǒng)計結(jié)果。
要在sar中查看歷史資源使用情況,我們必須為文件提供與統(tǒng)計數(shù)據(jù)相符的路徑。
舉例來說,如果大家打算查看本月23號以來服務(wù)器的平均負(fù)載狀況,可以運行以下命令:
代碼:
- [user@host ~]$ sar -q -f /var/log/sa/sa23
以上命令中的-q用于獲取平均負(fù)載信息,而-f則用于指定sar從哪個文件中獲取信息。請注意,sar可能無法使用一周之前乃至更早的運行信息。
如果大家打算查看當(dāng)前日期的統(tǒng)計信息,則不必為其指令具體時間。輸入以下命令即可顯示今天的平均負(fù)載情況:
代碼:
- [user@host ~]$ sar -q
我們強烈建議大家閱讀sar說明文檔:
代碼:
- [user@host ~]$ man sar
它所提供的統(tǒng)計信息能夠幫助我們確切掌握服務(wù)器的運行狀態(tài)。
當(dāng)前CPU使用情況
運行top,并在Cpu(s)一行中檢查%id部分所顯示的閑置CPU百分比。該數(shù)字越高結(jié)果越好,說明CPU的工作負(fù)載不強。處于99%閑置狀態(tài)下的CPU幾乎沒有處理任何實際任務(wù),而處于1%閑置狀態(tài)下的CPU則意味著接近滿載。
代碼:
- [user@host ~]$ top c
提示:可加寫P根據(jù)消耗CPU資源的多少對進(jìn)程加以分類。
歷史CPU使用情況
查看“%idle”列:
代碼:
- [user@host ~]$ sar -p
當(dāng)前內(nèi)存使用情況
代碼:
- [user@host ~]$ free -m
提示:運行top c并加寫M可查看哪個進(jìn)程占用的內(nèi)存量最大。
歷史內(nèi)存使用情況
根據(jù)sar版本的不同,命令內(nèi)容也有所區(qū)別。早期版本通過添加“-r”參數(shù)顯示內(nèi)存使用百分比與虛擬內(nèi)存使用百分比,但新版本則改用“-s”參數(shù)顯示虛擬內(nèi)存使用百分比。
Check %memused and %swpused:
代碼:
- [user@host ~]$ sar -r
或者:
代碼:
- [user@host ~]$ sar -r
代碼:
- [user@host ~]$ sar -S
內(nèi)存使用情況提示:服務(wù)器內(nèi)存占用量較高的情況其實非常正常。這是因為內(nèi)存的讀寫速度及效率遠(yuǎn)高于服務(wù)器磁盤,因此操作系統(tǒng)傾向于將內(nèi)存作為緩沖機制預(yù)先載入數(shù)據(jù),從而提高數(shù)據(jù)讀取速度。
同樣,內(nèi)存使用百分比也并不是什么大問題(除非大家沒有設(shè)置虛擬內(nèi)存分區(qū),但這也與內(nèi)存本身無關(guān))。大家真正需要關(guān)注的是虛擬內(nèi)存使用百分比,因為只有在服務(wù)器的物理內(nèi)存被全部占用后、虛擬內(nèi)存才會接替而上發(fā)揮作用。這一數(shù)字越低,就說明服務(wù)器的運行狀態(tài)越好。如果虛擬內(nèi)存使用率為0%,則意味著我們的服務(wù)器能夠完全利用物理內(nèi)存執(zhí)行任務(wù)。
那么虛擬內(nèi)存使用率達(dá)到多少才算過高?這取決于大家自己的感覺。一般來說,如果虛擬內(nèi)存使用率一直不高、那么我們的服務(wù)器的運行狀態(tài)還是比較理想的。如果大家發(fā)現(xiàn)虛擬內(nèi)存使用率隨時間不斷提升(例如由1%到7%再到32%),這就代表服務(wù)器上的某些進(jìn)程正在瘋狂吞噬內(nèi)存,我們需要及時展開調(diào)查以了解具體情況(而不該直接安裝更多內(nèi)存)。一旦服務(wù)器用盡了所有物理內(nèi)存與虛擬內(nèi)存,那么整套系統(tǒng)的運行將變得極為緩慢,需要經(jīng)過重啟才能暫時恢復(fù)正常。
當(dāng)前磁盤I/O使用情況
注意:這一項對于OpenVZ/Virtuozzo容器不起作用。
以下命令將以每秒一次的頻率連續(xù)顯示十次磁盤使用率統(tǒng)計。請大家關(guān)注顯示結(jié)果中的%util列:
代碼:
- [user@host ~]$ iostat -x 1 10
歷史磁盤I/O使用情況
代碼:
- [user@host ~]$ sar -d
優(yōu)秀的系統(tǒng)管理員能夠準(zhǔn)確把握服務(wù)器負(fù)載的基準(zhǔn)線,并在當(dāng)前負(fù)載超出基準(zhǔn)時立即做出判斷。這樣做的主要目的(除了防止服務(wù)器陷入半癱瘓并不得不重新啟動之外)是為了及時了解負(fù)載高企時服務(wù)器正在運行哪些項目??焖俜磻?yīng)能幫助大家在發(fā)現(xiàn)問題后第一時間進(jìn)行故障排查。
如果服務(wù)器負(fù)載過高的狀況出現(xiàn)在凌晨兩點到四點之間,那么正在熟睡中的我們肯定無法馬上展開調(diào)查。雖然sar會一直守護在服務(wù)器身邊,幫我們收集這段時間內(nèi)到底哪些資源的使用率居高不下,但卻無法揭示問題出現(xiàn)的實際原因。引發(fā)負(fù)載過高的原因多種多樣,其中包括DoS攻擊、垃圾郵件攻擊、php腳本設(shè)計不當(dāng)、網(wǎng)絡(luò)蜘蛛在繪制網(wǎng)絡(luò)圖譜時太過積極、硬件故障、針對用戶MySQL數(shù)據(jù)庫的磁盤寫入量暴增等等。
好消息是,大家可以利用工具收集這些信息,并在負(fù)載過高后將結(jié)果自動發(fā)送過來。如何實現(xiàn)?從進(jìn)程列表入手:
代碼:
- [user@host ~]$ ps auxwwwf
我創(chuàng)建了一個shell腳本,以我曾經(jīng)管理過的服務(wù)器上的一套perl腳本為基礎(chǔ)。這套腳本與其它服務(wù)器監(jiān)控工具(例如Nagios)配合起來給我的工作帶來諸多便利。它能檢查六種不同項目(下面將詳細(xì)介紹),并在進(jìn)程列表中的條目超出閾值時向我發(fā)送郵件通知。
注意:cPanel公司對該腳本的開發(fā)、維護或技術(shù)支持不承擔(dān)責(zé)任。請不要就這款腳本提出服務(wù)申請。如果您在使用中遇到任何問題,請到相關(guān)論壇上發(fā)帖或請教有經(jīng)驗的系統(tǒng)管理員。cPanel不提供與此腳本相關(guān)的任何支持。
它所檢查的具體資源對象如下:
- 一分鐘平均負(fù)載
- 虛擬內(nèi)存使用數(shù)量(單位為KB)
- 內(nèi)存使用數(shù)量(單位為KB)
- 每秒接收數(shù)據(jù)包數(shù)量
- 每秒發(fā)出數(shù)據(jù)包數(shù)量
- 進(jìn)程總數(shù)
如何使用腳本
要自動運行此腳本,大家需要設(shè)置一項cron任務(wù)并根據(jù)實際情況設(shè)定運行頻率。我發(fā)現(xiàn)每五分鐘運行一次是個不錯的選擇。該腳本無需使用root身份運行,既然如此我們也就不必為其分配高權(quán)限。
如果上述監(jiān)控資源對象中的某一項超過用戶自定義的閾值,腳本會自動發(fā)送一封電子郵件,其中包含當(dāng)前進(jìn)程列表內(nèi)容。
電子郵件的主題行如下所示:
代碼:
- server.example.com [L: 35] [P: 237] [Swap Use: 1% ] [pps in: 54 pps out: 289]
下面我們一一解釋其中的條目:
- L代表一分鐘平均負(fù)載
- P代表當(dāng)前進(jìn)程列表中的進(jìn)程數(shù)量
- Swap Usage代表虛擬內(nèi)存使用百分比
- pps in代表每秒接收數(shù)據(jù)包數(shù)量
- pps out代表每秒發(fā)出數(shù)據(jù)包數(shù)量
#p#
腳本使用前的注意事項
重要事項:大家需要根據(jù)自己的理解來調(diào)整腳本中的數(shù)值。完美的默認(rèn)值設(shè)定并不存在,因為不同的服務(wù)器環(huán)境在實際運行中所應(yīng)遵循的標(biāo)準(zhǔn)也不一樣。舉例來說,擁有十六個CPU核心的服務(wù)器在一分鐘平均負(fù)載方面肯定要高于只擁有一個CPU核心的服務(wù)器。
注意:大家需要將自己的電子郵箱地址添加到EMAIL變量當(dāng)中,如下所示:
代碼:
- EMAIL=you@example.com
以下五項也需要根據(jù)實際情況加以調(diào)整:
- MAX_LOAD
- MAX_SWAP_USED
- MAX_MEM_USED
- MAX_PPS_OUT
- MAX_PPS_IN
代碼:
- #!/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
需要注意的是,進(jìn)程列表的輸出內(nèi)容中包含一些有用的數(shù)列,涉及各個進(jìn)程的CPU與內(nèi)存使用情況:
- %CPU
- %MEM
- VSZ
- RSS
- TIME (顯示一個進(jìn)程的存在時間)
我們可以通過多種方式剖析服務(wù)器負(fù)載高企的原因。下面我們列出幾項常用方案--僅供參考,并不全面:
- 利用mysqladmin processlist (或者簡寫為'mysqladmin pr')檢查MySQL進(jìn)程列表
- 利用mytop檢查MySQL進(jìn)程列表
- 查閱日志文件。了解服務(wù)器自身的反饋意見也很重要。您的服務(wù)器是否遭遇暴力破解?
- 運行dmesg以檢查可能存在的硬件故障
- 利用netstat查看服務(wù)器連接
下面則是值得關(guān)注的日志文件及其保存路徑:
- 系統(tǒng)日志: /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
- 網(wǎng)站日志: /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
大家也可以在評論欄中反饋您在工作中遇到的問題、對本篇文章的評論及其它任何希望與朋友們分享的信息。作為一篇獨立的指導(dǎo)性文章,我們不可避免會存在遺漏或者疏忽,期待您提出寶貴意見、也希望大家能從中受到一點啟發(fā)。
原文鏈接:
http://forums.cpanel.net/f34/troubleshooting-high-server-loads-linux-servers-319352.html