关于系统监控和Go语言采集代码

在生产环境,有时候需要对系统的性能进行时时采集,可以预防问题的出现,比如CPU、内存、硬盘等硬件问题导致系统崩溃,在Linux下有以下命令。

CPU监控命令之top命令

  1. 概述:
    top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。下面详细介绍它的使用方法。
    top是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果在前台执行该命令,它将独占前台,直到用户终止该程序为止.比较准确的说,top命令提供了实时的对系统处理器的状态监视.它将显示系统中CPU最“敏感”的任务列表.该命令可以按CPU使用.内存使用和执行时间对任务进行排序;而且该命令的很多特性都可以通过交互式命令或者在个人定制文件中进行设定.

  2. 命令格式:
    top [参数]

  3. 命令功能:
    显示当前系统正在执行的进程的相关信息,包括进程ID、内存占用率、CPU占用率等

  4. 命令参数:
    -b 批处理
    -c 显示完整的治命令
    -I 忽略失效过程
    -s 保密模式
    -S 累积模式
    -i<时间> 设置间隔时间
    -u<用户名> 指定用户名
    -p<进程号> 指定进程
    -n<次数> 循环显示的次数

  5. 使用实例:
    01
    实例1:显示进程信息:
    命令:top
    输出:

说明:
1.系统运行时间和平均负载:

top命令的顶部显示与uptime命令相似的输出
这些字段显示:
当前时间、系统已运行的时间、当前登录用户的数量、相应最近5、10和15分钟内的平均负载。
可以使用'l'命令切换uptime的显示。
22:46:38 — 当前系统时间
0 days, 3:59 — 系统已经运行了3小时59分钟(在这期间没有重启过)
3 users — 当前有2个用户登录系统
load average:0.01, 0.02, 0.00 — load average后面的三个数分别是5分钟、10分钟、15分钟的负载情况。
load average数据是每隔5秒钟检查一次活跃的进程数,然后按特定算法计算出的数值。如果这个数除以逻辑CPU的数量,结果高于5的时候就表明系统在超负荷运转了。

2.任务:

Tasks — 任务(进程),系统现在共有146个进程,其中处于运行中的有1个,145个在休眠(sleep),stoped状态的有0个,zombie状态(僵尸)的有0个。
第二行显示的是任务或者进程的总结。进程可以处于不同的状态。这里显示了全部进程的数量。除此之外,还有正在运行、睡眠、停止、僵尸进程的数量(僵尸是一种进程的状态)。这些进程概括信息可以用't'切换显示

3.CPU 状态:

这里显示不同模式下所占cpu时间百分比,这些不同的cpu时间表示:
us, user:运行(未调整优先级的) 用户进程的CPU时间
sy,system: 运行内核进程的CPU时间
ni,niced:运行已调整优先级的用户进程的CPU时间
wa,IO wait: 用于等待IO完成的CPU时间
hi:处理硬件中断的CPU时间
si: 处理软件中断的CPU时间
st:这个虚拟机被hypervisor偷去的CPU时间(译注:如果当前处于一个hypervisor下的vm,实际上hypervisor也是要消耗一部分CPU处理时间的)。
可以使用't'命令切换显示。
0.3% us — 用户空间占用CPU的百分比。
0.7% sy — 内核空间占用CPU的百分比。
0.0% ni — 改变过优先级的进程占用CPU的百分比
99.0% id — 空闲CPU百分比
0.0% wa — IO等待占用CPU的百分比
0.0% hi — 硬中断(Hardware IRQ)占用CPU的百分比
0.0% si — 软中断(Software Interrupts)占用CPU的百分比
在这里CPU的使用比率和windows概念不同,如果你不理解用户空间和内核空间,需要充充电了。

4.内存使用:

接下来两行显示内存使用率,有点像'free'命令。第一行是物理内存使用,第二行是虚拟内存使用(交换空间)。
物理内存显示如下:全部可用内存、已使用内存、空闲内存、缓冲内存。相似地:交换部分显示的是:全部、已使用、空闲和缓冲交换空间。
内存显示可以用'm'命令切换。
1004348k total — 物理内存总量(1004M)
938408k used — 使用中的内存总量(938M)
65940k free — 空闲内存总量(65M)
44344k buffers — 缓存的内存量 (44M)
swap交换分区
2031612k total — 交换区总量(2031M)
4k used — 使用的交换区总量(4k)
2031608k free — 空闲交换区总量(2031M)
538676k cached — 缓冲的交换区总量(538M)

5.各进程(任务)的状态监控:

PID:进程ID,进程的唯一标识符
USER:进程所有者的实际用户名。
PR:进程的调度优先级。这个字段的一些值是'rt'。这意味这这些进程运行在实时态。
NI:进程的nice值(优先级)。越小的值意味着越高的优先级。负值表示高优先级,正值表示低优先级
VIRT:进程使用的虚拟内存。进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
RES:驻留内存大小。驻留内存是任务使用的非交换物理内存大小。进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
SHR:SHR是进程使用的共享内存。共享内存大小,单位kb
S:这个是进程的状态。它有以下不同的值:
D - 不可中断的睡眠态。
R – 运行态
S – 睡眠态
T – 被跟踪或已停止
Z – 僵尸态
%CPU:自从上一次更新时到现在任务所使用的CPU时间百分比。
%MEM:进程使用的可用物理内存百分比。
TIME+:任务启动后到现在所使用的全部CPU时间,精确到百分之一秒。
COMMAND:运行进程所使用的命令。进程名称(命令名/命令行)
还有许多在默认情况下不会显示的输出,它们可以显示进程的页错误、有效组和组ID和其他更多的信息。

6.其他使用技巧:
6.1.多U多核CPU监控
在top基本视图中,按键盘数字“1”,可监控每个逻辑CPU的状况:

6.2.高亮显示当前运行进程
敲击键盘“b”(打开/关闭加亮效果),top的视图变化如下:

我们发现进程id为7600的“top”进程被加亮了,top进程就是视图第二行显示的唯一的运行态(runing)的那个进程,可以通过敲击“y”键关闭或打开运行态进程的加亮效果。

6.3.进程字段排序
默认进入top时,各进程是按照CPU的占用量来排序的,在下图中进程ID为7517的java进程排在第一(cpu占用0.7%),进程ID为3073的java进程排在第二(cpu占用0.3%)。

敲击键盘“x”(打开/关闭排序列的加亮效果),top的视图变化如下:

可以看到,top默认的排序列是“%CPU”

6.4. 通过”shift + >”或”shift + <”可以向右或左改变排序列
下图是按一次”shift + >”的效果图,视图现在已经按照%MEM来排序。

02
实例2显示完整命令:
命令:top -c
输出:

03
实例3显示指定进程信息:
命令:
top -p 7517
输出:

6、top交互命令:
在top 命令执行过程中可以使用的一些交互命令。这些命令都是单字母的,如果在命令行中使用了s 选项, 其中一些命令可能会被屏蔽。
h 显示帮助画面,给出一些简短的命令总结说明
k 终止一个进程。
i 忽略闲置和僵死进程。这是一个开关式命令。
q 退出程序
r 重新安排一个进程的优先级别
S 切换到累计模式
s 改变两次刷新之间的延迟时间(单位为s),如果有小数,就换算成m s。输入0值则系统将不断刷新,默认值是5 s
f或者F 从当前显示中添加或者删除项目
o或者O 改变显示项目的顺序
l 切换显示平均负载和启动时间信息
m 切换显示内存信息
t 切换显示进程和CPU状态信息
c 切换显示命令名称和完整命令行
M 根据驻留内存大小进行排序
P 根据CPU使用百分比大小进行排序
T 根据时间/累计时间进行排序
W 将当前设置写入~/.toprc文件中

在Go语言中如何调用系统监控呢?我们需要用到gopsutil包,python也有类似的包,这里仅用Go来实现各种视频监控。

// QueryHost 获取本机信息
func queryHost() (out *response.JsonSimpleRes, err error) {
   out = &response.JsonSimpleRes{}

   info, _ := host.Info()
   fmt.Println(info)

   // host.BootTime()返回主机开机时间的时间戳:
   timestamp, _ := host.BootTime()
   t := time.Unix(int64(timestamp), 0)
   fmt.Println(t.Local().Format("2006-01-02 15:04:05"))

   //内核版本和平台信息
   version, _ := host.KernelVersion()
   fmt.Println(version)

   platform, family, version, _ := host.PlatformInformation()
   fmt.Println("platform:", platform)
   fmt.Println("family:", family, "version:", version)

   // host.Users()返回终端连接上来的用户信息,每个用户一个UserStat结构:
   users, _ := host.Users()
   for _, user := range users {
      data, _ := json.MarshalIndent(user, "", " ")
      fmt.Println(string(data))
   }

   return out, err

输出例子:

  {"hostname":"WIN-SP09TQCP1U8","uptime":25308,"bootTime":1558574107,"procs":175,"os":"windows","platform":"Microsoft Windows 10 Pro","platformFamily":"Standalone Workstation","platformVersion":"10.0.17134 Build 17134","kernelVersion":"","virtualizationSystem":"","virtualizationRole":"","hostid":。。。}
}


// QueryCPU 采集CPU相关信息
func queryCPU() (out *response.JsonSimpleRes, err error) {
   out = &response.JsonSimpleRes{}

   c, _ := cpu.Info()
   fmt.Println("cpu信息:", c)
   输出内容:[{"cpu":0,cores":4,"modelName":"Intel(R) Core(TM) i5-2520M CPU @ 2.50GHz","mhz":2501,。。。]
   /*用户CPU时间/系统CPU时间/空闲时间。。。等等
     用户CPU时间:就是用户的进程获得了CPU资源以后,在用户态执行的时间。
     系统CPU时间:用户进程获得了CPU资源以后,在内核态的执行时间。
   */
   c1, _ := cpu.Times(false)
   fmt.Println("cpu1:", c1)
   输出内容:[{"cpu":"cpu-total","user":1272.0,"system":1572.7,"idle":23092.3,"nice":0.0,"iowait":0.0,"irq":0.0,。。。}]
   // 用户CPU时间:就是用户的进程获得了CPU资源以后,在用户态执行的时间。
   // 系统CPU时间:用户进程获得了CPU资源以后,在内核态的执行时间。
   // CPU使用率,每秒刷新一次
   //for {
   c2, _ := cpu.Percent(time.Duration(time.Second), false)
   fmt.Println(c2)
   //}

   n, _ := cpu.Counts(true) //cpu逻辑数量
   fmt.Println(n)           //4
   n, _ = cpu.Counts(false) //cpu物理核心
   fmt.Println(n)           //如果是2说明是双核超线程, 如果是4则是4核非超线程

   return out, err
}


// QueryMem 采集内存信息
func queryMem() (out *response.JsonSimpleRes, err error) {
   out = &response.JsonSimpleRes{}

   //获取物理内存和交换区内存信息
   m1, _ := mem.VirtualMemory()
   fmt.Println("m1:", m1)
   m2, _ := mem.SwapMemory()
   fmt.Println("m2:", m2)
   return out, err

输出内容:

{"total":8129818624,"available":4193423360,"used":3936395264,"usedPercent":48,"free":0,"active":0,"inactive":0,...}

输出内容:

{"total":8666689536,"used":4716843008,"free":3949846528,"usedPercent":0.5442496801583825,"sin":0,"sout":0,...}
   //总内存大小是8129818624 = 8 GB,已用3936395264 = 3.9 GB,使用了48%。而交换区大小是8666689536 = 8 GB。
}

// QueryDisk 采集磁盘信息
func queryDisk() (out *response.JsonSimpleRes, err error) {
   out = &response.JsonSimpleRes{}

   //可以通过psutil获取磁盘分区、磁盘使用率和磁盘IO信息
   d1, _ := disk.Partitions(true) //所有分区
   fmt.Println("d1:", d1)
   d2, _ := disk.Usage("E:") //指定某路径的硬盘使用情况
   fmt.Println("d2:", d2)
   d3, _ := disk.IOCounters() //所有硬盘的io信息
   fmt.Println("d3:", d3)
   return out, err

输出内容:

[{"device":"C:","mountpoint":"C:","fstype":"NTFS","opts":"rw.compress"} {"device":"D:","mountpoint":"D:","fstype":"NTFS","opts":"rw.compress"} {"device":"E:","mountpoint":"E:","fstype":"NTFS","opts":"rw.compress"} ]
   // {"path":"E:","fstype":"","total":107380965376,"free":46790828032,"used":60590137344,"usedPercent":56.425398236866755,"inodesTotal":0,"inodesUsed":0,"inodesFree":0,"inodesUsedPercent":0}
   // map[C::{"readCount":0,"mergedReadCount":0,"writeCount":0,"mergedWriteCount":0,"readBytes":0,"writeBytes":4096,"readTime":0,"writeTime":0,"iopsInProgress":0,"ioTime":0,"weightedIO":0,"name":"C:","serialNumber":"","label":""} 。。。]
}

// QueryNet 采集网络信息
func queryNet() (out *response.JsonSimpleRes, err error) {
   out = &response.JsonSimpleRes{}

   //获取当前网络连接信息
   n1, _ := net.Connections("all") //可填入tcp、udp、tcp4、udp4等等
   fmt.Println("n1:", n1)

输出内容:

[{"fd":0,"family":2,"type":1,"localaddr":{"ip":"0.0.0.0","port":135},"remoteaddr":{"ip":"0.0.0.0","port":0},"status":"LISTEN","uids":null,"pid":668} {"fd":0,"family":2,"type":1,"localaddr":{"ip":"0.0.0.0","port":445},"remoteaddr":{"ip":"0.0.0.0","port":0},"status":"LISTEN","uids":null,"pid":4} {"fd":0,"family":2,"type":1,"localaddr":{"ip":"0.0.0.0","port":1801},"remoteaddr":{"ip":"0.0.0.0","port":0},"status":"LISTEN","uids":null,"pid":3860}
   // 等等。。。]
   //获取网络读写字节/包的个数
   n2, _ := net.IOCounters(false)
   fmt.Println("n2:", n2)
   return out, err
   //output:[{"name":"all","bytesSent":6516450,"bytesRecv":36991210,"packetsSent":21767,"packetsRecv":33990,"errin":0,"errout":0,"dropin":0,"dropout":0,"fifoin":0,"fifoout":0}]

}

// QueryProcess 采集进程相关信息
func queryProcess() (out *response.JsonSimpleRes, err error) {
   out = &response.JsonSimpleRes{}

   //获取到所有进程的详细信息
   p1, _ := process.Pids() //获取当前所有进程的pid
   fmt.Println("p1:", p1)

输出内容:

[0 4 96 464 636 740 748 816 852 880 976 348 564 668 912 1048 1120 1184 1268 1288。。。]
   ifExists, _ := process.PidExists(10086) // 判断进程是否存在
   fmt.Println("ifExists:", ifExists)

   return out, err
}

作者:扶程星云

posted @   中亿丰数字科技  阅读(54)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示