歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux管理 >> Linux服務 >> Linux服務器中高負載現象故障排查指南

Linux服務器中高負載現象故障排查指南

日期:2017/2/27 15:58:47   编辑:Linux服務
技術支持分析師們常常接到用戶對服務器高負載的控訴。事實上cPanel軟件及其安裝的應用很少引發服務器高負載情況。服務器擁有者、系統管理員或者服務器供應商應當對高負載狀況進行初步調查,並在確認情況復雜後再向分析人士求助。

服務器高負載因何而起?
下列項目的過度使用會直接導致高負載問題:
  • CPU
  • 內存(包括虛擬內存)
  • 磁盤I/O

該如何檢查這些項目?
這取決於大家是要審查當前資源使用情況還是歷史資源使用情況。當然,在本文中我們將從這兩方面進行探討。

關於sar的簡要說明
歷史資源使用情況可通過sar工具查看,該工具在默認情況下應該通過sysstat軟件包安裝在所有cPanel服務器當中。只要通過cron命令 對sysstat進行周期性執行(/etc/cron.d/sysstat),服務器的運行狀態數據就會被收集起來。如果cron沒有運 行,sysstat將無法收集歷史統計結果。

要在sar中查看歷史資源使用情況,我們必須為文件提供與統計數據相符的路徑。

舉例來說,如果大家打算查看本月23號以來服務器的平均負載狀況,可以運行以下命令:
sar -q -f /var/log/sa/sa23
以上命令中的-q用於獲取平均負載信息,而-f則用於指定sar從哪個文件中獲取信息。請注意,sar可能無法使用一周之前乃至更早的運行信息。

如果大家打算查看當前日期的統計信息,則不必為其指令具體時間。輸入以下命令即可顯示今天的平均負載情況:
$ sar -q
我們強烈建議大家閱讀sar說明文檔:
$ man sar
它所提供的統計信息能夠幫助我們確切掌握服務器的運行狀態。

當前CPU使用情況
運行top,並在Cpu(s)一行中檢查%id部分所顯示的閒置CPU百分比。該數字越高結果越好,說明CPU的工作負載不強。處於99%閒置狀態下的CPU幾乎沒有處理任何實際任務,而處於1%閒置狀態下的CPU則意味著接近滿載。
$ top c
提示:可加寫P根據消耗CPU資源的多少對進程加以分類。

歷史CPU使用情況
查看“%idle”列:
$ sar -p
當前內存使用情況
$ free -m
提示:運行top c並加寫M可查看哪個進程占用的內存量最大。

歷史內存使用情況
根據sar版本的不同,命令內容也有所區別。早期版本通過添加“-r”參數顯示內存使用百分比與虛擬內存使用百分比,但新版本則改用“-s”參數顯示虛擬內存使用百分比。
Check %memused and %swpused:
$ sar -r 
或者:
$ sar -S
內存使用情況提示:服務器內存占用量較高的情況其實非常正常。這是因為內存的讀寫速度及效率遠高於服務器磁盤,因此操作系統傾向於將內存作為緩沖機制預先載入數據,從而提高數據讀取速度。

同樣,內存使用百分比也並不是什麼大問題(除非大家沒有設置虛擬內存分區,但這也與內存本身無關)。大家真正需要關注的是虛擬內存使用百分比,因為只有在服務器的物理內存被全部占用後、虛擬內存才會接替而上發揮作用。這一數字越低,就說明服務器的運行狀態越好。如果虛擬內存使用率為0%,則意味著我們的服務器能夠完全利用物理內存執行任務。

那麼虛擬內存使用率達到多少才算過高?這取決於大家自己的感覺。一般來說,如果虛擬內存使用率一直不高、那麼我們的服務器的運行狀態還是比較理想的。如果大家發現虛擬內存使用率隨時間不斷提升(例如由1%到7%再到32%),這就代表服務器上的某些進程正在瘋狂吞噬內存,我們需要及時展開調查以了解具體情況(而不該直接安裝更多內存)。一旦服務器用盡了所有物理內存與虛擬內存,那麼整套系統的運行將變得極為緩慢,需要經過重啟才能暫時恢復正常。

當前磁盤I/O使用情況
注意:這一項對於OpenVZ/Virtuozzo容器不起作用。

以下命令將以每秒一次的頻率連續顯示十次磁盤使用率統計。請大家關注顯示結果中的%util列:
$ iostat -x 1 10

歷史磁盤I/O使用情況
$ sar -d
優秀的系統管理員能夠准確把握服務器負載的基准線,並在當前負載超出基准時立即做出判斷。這樣做的主要目的(除了防止服務器陷入半癱瘓並不得不重新啟動之外)是為了及時了解負載高企時服務器正在運行哪些項目。快速反應能幫助大家在發現問題後第一時間進行故障排查。

如果服務器負載過高的狀況出現在凌晨兩點到四點之間,那麼正在熟睡中的我們肯定無法馬上展開調查。雖然sar會一直守護在服務器身邊,幫我們收集這段時間內到底哪些資源的使用率居高不下,但卻無法揭示問題出現的實際原因。引發負載過高的原因多種多樣,其中包括DoS攻擊、垃圾郵件攻擊、php腳本設計不當、網絡蜘蛛在繪制網絡圖譜時太過積極、硬件故障、針對用戶MySQL數據庫的磁盤寫入量暴增等等。

好消息是,大家可以利用工具收集這些信息,並在負載過高後將結果自動發送過來。如何實現?從進程列表入手:
$ 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變量當中,如下所示:
[email protected]
以下五項也需要根據實際情況加以調整:
  • 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="[email protected]" 
# 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
Copyright © Linux教程網 All Rights Reserved