需求
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;
· 上面步驟執行完,效果類似:
· 選中左上角單元格,選擇【插入】->【圖表】->【折線圖】,大功告成!
· 最後效果
分析
記憶體雖然有高峰,但最終呈現規律的回落。大體是一個正常的、每天随着線上玩家數起伏的曲線。
但是,在個别時間有極端的尖峰,時間是0點。推測是跨天時有瞬間的高峰運算,導緻臨時配置設定了許多記憶體。
至此OS層面的問題排查結束,不存在記憶體洩漏(甚至可以說完美),但存在記憶體尖峰。至于具體的NodeJS記憶體分析,後面有時間再表。