天天看點

利用Top以及WPS監控指定程序記憶體,以及可視化

需求

GameServer 有一段時間記憶體波動異常,需要對其定位問題。

最直接的方式

看機器的總體記憶體曲線,比如阿裡雲可以看ECS的監控。

不足

GameServer 的波動隻占機器記憶體的一小部分,且機器時常也有其他 GameServer 的維護,無法從總體上精确判定指定的 GameServer 的記憶體異常。

簡單Top來跟蹤指定PID

top -p ${pid} 即可隻觀察指定pid的記憶體形象

寫成日志到盤

nohup top -b -d 3 -p 16772 > top_log&

nohup 即背景模式,-b 即batch,批量輸出(加上這個才可增量輸出到檔案),-d 是間隔,這裡3秒鐘一次即可。-p 後面連接配接需要監控的 pid。

最後的結果類似:

top - 11:14:28 up 171 days,  6:02,  2 users,  load average: 0.05, 0.14, 0.22
Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu(s):  3.1 us,  0.4 sy,  0.0 ni, 96.3 id,  0.2 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 16266124 total,  2262148 free,  4796360 used,  9207616 buff/cache
KiB Swap:        0 total,        0 free,        0 used. 11130132 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
16772 root      20   0 2349536 906344  23444 S  10.6  5.6   1397:57 node

top - 11:14:32 up 171 days,  6:02,  2 users,  load average: 0.04, 0.13, 0.22
Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu(s):  3.3 us,  0.3 sy,  0.0 ni, 96.2 id,  0.3 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 16266124 total,  2261404 free,  4797100 used,  9207620 buff/cache
KiB Swap:        0 total,        0 free,        0 used. 11129392 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
16772 root      20   0 2349536 906728  23444 S  11.3  5.6   1397:57 node

           

進一步提取結果,隻關注記憶體

JS 代碼很簡單可實作(注意要根據實際的輸出規律來,比如這裡的程序資訊是 node)

let fs = require("fs")

//多個空格縮短為一個空格
function reset_blank(str)
{
    return str.replace(/\s+/g, ' ')
}

function main()
{
    let buff = fs.readFileSync("./top_log")

    let str = buff.toString()

    let arr = str.match(/top([\s\S]*?)node/g)
    let axis_str = ""
    for (let one of arr)
    {
        //按照行分
        let lines = one.split("\n")
        //第一行讀出來時間
        let first_line = lines[0]
        first_line = reset_blank(first_line)

        let elems = first_line.split(" ")
        let time_str = elems[2]

        //最後一行讀出關鍵的記憶體資訊
        let end_line = lines[lines.length - 1]
        end_line = reset_blank(end_line)

        elems = end_line.split(" ")
        let res_str = elems[5]

        let bytes_str = res_str
        let g_reg = /g/g
        let m_reg = /m/g

        if (g_reg.test(bytes_str))
            bytes_str = Number(bytes_str.split("g")[0]) * 1024 * 1024
        else if (m_reg.test(bytes_str))
            bytes_str = Number(bytes_str.split("m")[0]) * 1024

        axis_str += `${time_str} ${bytes_str}\n`
    }

    fs.writeFileSync("./axis.txt", axis_str)
}

main()

           

處理後,輸出的結構就是一個坐标軸資訊。第一列是時間,第二列是bytes。類似:

11:14:28 906344
11:14:32 906728
11:14:35 906412
11:14:38 907024
11:14:41 907024
11:14:44 907024
11:14:47 906816
11:14:50 906816
11:14:53 906816
11:14:56 906816
11:14:59 906660
11:15:02 906660
11:15:05 906808
11:15:08 906808
11:15:11 906808
11:15:14 906976
11:15:17 906976
11:15:20 907768
11:15:23 907768
11:15:26 906956
11:15:29 907024
11:15:32 907504
11:15:35 907300
11:15:38 907300
11:15:41 907212
...
           

可視化

單純這樣看不夠直覺看出規律,可以把這些資料導入到辦公軟體實作可視化觀察。

這裡我們用WPS來實作。

· 直接複制資料到wps檔案(或者在資料量龐大時,選擇導入,不用經過粘貼闆,避免卡頓);

· 選擇【資料】->【分列】->【智能分列】,然後按照空格劃分出兩列,一列是時間,一列是bytes大小;

· 第一行插入兩列,Time、Res;

· 上面步驟執行完,效果類似:

利用Top以及WPS監控指定程式記憶體,以及可視化

· 選中左上角單元格,選擇【插入】->【圖表】->【折線圖】,大功告成!

利用Top以及WPS監控指定程式記憶體,以及可視化

· 最後效果

利用Top以及WPS監控指定程式記憶體,以及可視化

分析

記憶體雖然有高峰,但最終呈現規律的回落。大體是一個正常的、每天随着線上玩家數起伏的曲線。

但是,在個别時間有極端的尖峰,時間是0點。推測是跨天時有瞬間的高峰運算,導緻臨時配置設定了許多記憶體。

至此OS層面的問題排查結束,不存在記憶體洩漏(甚至可以說完美),但存在記憶體尖峰。至于具體的NodeJS記憶體分析,後面有時間再表。

繼續閱讀