天天看點

通過shell擷取Linux伺服器CPU、記憶體、網絡等基礎項監控

1、擷取系統(CPU)負載

系統平均負載的定義:在特定時間間隔内運作隊列中的平均程序數。

如何擷取系統(CPU)負載?

在Linux系統中可以通過/proc/loadavg檔案擷取,其中各項參數含義解釋:

0.11 0.09 0.06 2/263 10982      

  前三個數字分别表示:1、5、15分鐘的系統負載(或者叫平均程序數), 第四個類似分數形勢的分别表示正在運作的程序數和系統目前總的程序數,最後一個數字表示的最近一個運作程序的ID。

  如果我們想要擷取我們目前系統的CPU負載使用情況可以通過下邊的shell指令擷取:

cat /proc/loadavg | awk ‘{print $1,$2,$3}’      

除了通過檢視/proc/loadavg擷取系統的負載,還可以使用Linux下的uptime、w、top等指令來擷取,當使用這些指令時,輸出結果中都會有load average字樣,那麼後邊跟的三個數字就是目前系統在1、5、15分鐘内的平均負載。

一般來說當每個CPU的目前程序數(運作隊列長度)持續大于1,就需要開始調查引起問題的原因了,如果每個CPU的任務數持續大于3,就需要徹底檢查解決這個問題了,因為這個時候任何一個程序運作時都不能立馬得到CPU的響應。如果每個CPU的任務數大于5,那麼就說明你的服務出現了嚴重問題,如果不及時處理,可能會導緻當機。

2、擷取CPU使用率

CPU使用率是指目前運作的程式(程序)占用的CPU資源情況,也就是說CPU使用率是一個程式占用一個CPU處理器多少時間的百分比。在Linux/Unix下,CPU使用率又分為使用者态、系統态和空閑态,分别用來表示CPU處于使用者态執行的時間、系統核心執行的時間和空閑系統程序的時間。在通常我們所說的CPU利用是指:CPU執行非系統空閑程序的時間/CPU總的執行時間。

   不要與CPU負載混淆,CPU使用率和CPU負載在一定程度上都能用在衡量一個伺服器的資源使用情況,但CPU負載和CPU使用率之間沒有絕對的關聯關系,更不能混為一談,關于CPU負載(系統負載)的概念在上節中已經說明。

如何擷取CPU使用率?

在Linux系統中可以通過/proc/stat檔案來計算CPU的使用率。其中各項參數說明:

cpu  13020415 2752 14585234 1898039188 5345 0 46019 0 0 0
cpu0 3212795 820 3641656 474590184 756 0 9239 0 0 0
cpu1 3285261 628 3634202 474396971 3220 0 8799 0 0 0
cpu2 3388112 637 3695487 474389928 420 0 3115 0 0 0
cpu3 3134246 665 3613888 474662103 947 0 24864 0 0 0
intr 4669596224 155 10 0 0 0 0 2 0 1713 0 0 0 16 0 0 4715099 0 535144 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8955035 7121118 7194150 7163302 0 1739264 7 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
ctxt 4454886169
btime 1524214872
processes 3187040
procs_running 1
procs_blocked 0
softirq 1113211729 0 591606805 1931306 31654758 2851576 0 4047 296149644 0 189013593      

以我的機器為例:

就拿第一行來說:

cpu  13020415 2752 14585234 1898039188 5345 0 46019 0 0 0      

第一個字段(cpu)是cpu辨別。

第二個字段(13020415)表示是從系統啟動開始一直到目前時刻,程序在使用者态(user)下執行的時間積累。

第三個字段(2752)表示是從系統啟動開始一直到目前時刻,nice值為負的程序所占用的CPU時間。

第四個字段(14585234)表示是從系統啟動開始一直到目前時刻,程序在系統核心(system)的執行時間積累。

第五個字段(1898039188)表示是從系統啟動開始一直到目前時刻,處硬碟IO等待以外其他的空閑時間(idle)積累。

第六個字段(5345)表示是從系統啟動開始一直到目前時刻,IO等待(iowait)的時間積累。

第七個字段(0)表示是從系統啟動開始一直到目前時刻,硬中斷的時間(irq)。

第八個字段(46019)表示是從系統啟動開始一直到目前時刻,軟中斷的時間(softirq)。

剩下的幾行:

intr: 給出的是中斷資訊,第一個數為自系統啟動以來,發生的所有中斷的次數;後面的每個數對應一個特定的中斷,表示該中斷自系統啟動以來發生的次數。

ctxt: 表示系統CPU發生的上下文交換次數。

btime: 表示自系統啟動到現在的時間,機關為秒。

processes: 表示自系統啟動以來所建立的任務的數目。

procs_running: 目前運作隊列的任務數目。

procs_blocked: 目前被阻塞的任務數目,等待I/O完成次數。

CPU的使用率可以通過如下方式計算:

cpu_usage=(idle2-idle1)/(cpu2-cpu1)*100

cpu_usage=[(user2+sys2+nice2)-(user1+sys1+nice1)]/(total2-total)*100

擷取CPU使用率的相關腳本如下:

#!/bin/sh
#
#腳本功能描述:依據/proc/stat檔案擷取并計算CPU使用率
#
#CPU時間計算公式:CPU_TIME=user+system+nice+idle+iowait+irq+softirq
#CPU使用率計算公式:cpu_usage=(idle2-idle1)/(cpu2-cpu1)*100
#預設時間間隔
TIME_INTERVAL=5
 
LAST_CPU_INFO=$(cat /proc/stat | grep -w cpu | awk '{print $2,$3,$4,$5,$6,$7,$8}')
LAST_SYS_IDLE=$(echo $LAST_CPU_INFO | awk '{print $4}')
LAST_TOTAL_CPU_T=$(echo $LAST_CPU_INFO | awk '{print $1+$2+$3+$4+$5+$6+$7}')
sleep ${TIME_INTERVAL}
NEXT_CPU_INFO=$(cat /proc/stat | grep -w cpu | awk '{print $2,$3,$4,$5,$6,$7,$8}')
NEXT_SYS_IDLE=$(echo $NEXT_CPU_INFO | awk '{print $4}')
NEXT_TOTAL_CPU_T=$(echo $NEXT_CPU_INFO | awk '{print $1+$2+$3+$4+$5+$6+$7}')
 
#系統空閑時間
SYSTEM_IDLE=`echo ${NEXT_SYS_IDLE} ${LAST_SYS_IDLE} | awk '{print $1-$2}'`
#CPU總時間
TOTAL_TIME=`echo ${NEXT_TOTAL_CPU_T} ${LAST_TOTAL_CPU_T} | awk '{print $1-$2}'`
CPU_USAGE=`echo ${SYSTEM_IDLE} ${TOTAL_TIME} | awk '{printf "%.2f", 100-$1/$2*100}'`
 
echo "CPU Usage:${CPU_USAGE}%"      

除了利用/proc/stat檔案擷取CPU使用率,還可以通過top等指令擷取CPU的使用率,如

# top -n 1 | grep Cpu
 %Cpu(s):  1.5 us,  1.5 sy,  0.0 ni, 96.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st      

3、擷取記憶體使用情況

1)在Linux下要檢視記憶體的使用情況一般使用free指令:

# free
total       used       free     shared    buffers     cached
Mem:       3922048    3416120     505928       1396     137396    2836636
-/+ buffers/cache:     442088    3479960
Swap:      8241148       3500    8237648      

其中的各項字段解釋說明:

total: 實體記憶體的總大小

used: 已經使用的記憶體大小

free:空閑的記憶體大小

shared:應用程式共享的記憶體

buffers: 緩存,主要用于目錄方面,inode值等

cached: 緩存,主要用于已打開的檔案

通過上邊的解釋說明我們可以得到:

total = used + free

used = shared + buffers + cached

是以在計算系統記憶體使用率是時候,從系統的層面考慮,可以直接通過mem usage = used / total 計算記憶體使用率。

而第三行(-/+buffers/cache)中主要是針對應用程式的記憶體使用來說的:

-buffers/cache:應用程式使用的記憶體大小,即used減去緩存值

+buffers/cache:所有可供應用程式使用的記憶體大小,free加上緩存值

從應用程式角度看,對于應用程式來說buffers/cache也等同于可用的,因為buffers/cache本身是為了提高檔案的讀取性能,是以當記憶體緊張的時候,buffers/cache會被回收,重新配置設定給申請記憶體的應用程式。

 是以從應用程式的角度來說,可用記憶體 = 系統free + buffers + cached

2)除了通過free指令擷取Linux記憶體的使用情況,我們還可以通過/proc/meminfo檔案來擷取記憶體的使用率:

#cat /proc/meminfo
MemTotal:        1883388 kB
MemFree:           81952 kB
MemAvailable:     995960 kB
Buffers:            2072 kB
Cached:           747400 kB
SwapCached:            4 kB
Active:           520372 kB
Inactive:         599848 kB
Active(anon):     173680 kB
Inactive(anon):   296344 kB
Active(file):     346692 kB
Inactive(file):   303504 kB
...      

相關字段解釋說明:

MemTotal:所有實體可用RAM記憶體

MemFree:目前空閑記憶體

MemAvailable: 預計可使用的記憶體

Buffers: 用來給檔案做緩沖的記憶體

Cached: 高速緩沖存儲器所用記憶體

SwapCached: 交換空間

Active: 活躍使用的Buffer或Cache的記憶體大小

Inactive:不經常使用的Buffer或Cache的記憶體大小

###利用/proc/meminfo擷取記憶體使用情況的腳本如下:

#!/bin/sh
mem_use_info=(`awk '/MemTotal/{memtotal=$2}/MemAvailable/{memavailable=$2}END{printf "%.2f %.2f %.2f",memtotal/1024/1024," "(memtotal-memavailable)/1024/1024," "(memtotal-memavailable)/memtotal*100}' /proc/meminfo`)
 
echo total:${mem_use_info[0]}G  used:${mem_use_info[1]}G  Usage:${mem_use_info[2]}%      

4、擷取實時網卡流量資訊

   在Linux下如果需要檢視實時流量一般都采用iftop指令來檢視不同網卡的實時流量資訊。

    但是如果想分析網卡的網絡包、流量、錯包、丢包等資訊一般都是通過/proc/net/dev檔案來分析。

 針對/proc/net/dev檔案,通常檔案内容如下:

#cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
ens192: 110400390 1840002    0  904    0     0          0         0      900      14    0    0    0     0       0          0
    lo:  923561   14578    0    0    0     0          0         0   923561   14578    0    0    0     0       0          0
ens160: 1375841938 17880629    0  909    0     0          0         0 1331915939 15766579    0    0    0     0       0          0      

相關字段解釋說明:

從第一行中可以看出這個檔案大緻分為三部分,分别是:

第一個字段表示接口名稱

第二個字段Recevice表示收包

第三個字段Transmit表示發包。

下邊幾行内容相同:

第一個字段(face):表示接口名稱

第二個字段和第十個字段(byte):分别表示收到、發送的位元組數

第三個字段和第十一個字段(packets):分别表示收到、發送的正确資料包的數量

第四個字段和第十二個字段(errs):分别表示收到、發送的錯誤資料包量

第五個字段和第十三個字段(drop):分别表示收到、發送丢棄的資料包量

下邊是擷取伺服器網卡實時流量的腳本:

#!/bin/sh
#
#通過/proc/net/dev擷取執行網卡的資訊
if [ $# -lt 2 ];then
  echo "Useage : `basename $0` eth0 1"
  exit 1
fi
#網卡名
eth=$1
#時間間隔(頻率)
interval=$2
 
in_last=$(cat /proc/net/dev | grep ${eth} | sed -e "s/\(.*\)\:\(.*\)/\2/g" | awk '{print $1 }')
out_last=$(cat /proc/net/dev | grep ${eth} | sed -e "s/\(.*\)\:\(.*\)/\2/g" | awk '{print $9 }')
 
while true
    do
        sleep ${interval}
        in=$(cat /proc/net/dev | grep $eth | sed -e "s/\(.*\)\:\(.*\)/\2/g" | awk '{print $1 }')
        out=$(cat /proc/net/dev | grep $eth | sed -e "s/\(.*\)\:\(.*\)/\2/g" | awk '{print $9 }')
 
        traffic_in=`echo ${in} ${in_last} | awk '{printf "%.2f", ($1-$2)/1024}'`
        traffic_out=`echo ${out} ${out_last} | awk '{printf "%.2f", ($1-$2)/1024}'`
        current_time=$(date +"%F %H:%M:%S")
 
        echo "${current_time} -- IN: ${traffic_in} KByte/s     OUT: ${traffic_out} KByte/s"
 
        in_old=${in}
        out_old=${out}
   done