简介
在Linux系统管理中,监控是确保系统稳定性和性能的关键环节。通过监控,管理员可以及时发现系统瓶颈、异常行为和潜在的安全威胁。本文将详细介绍如何监控Linux系统中的CPU、内存、网络接口、磁盘和网络连接状态,帮助您更好地理解和维护您的系统。
CPU监控
CPU负载
系统负载是衡量系统性能的重要指标。通过查看/proc/loadavg
文件,我们可以获取系统的负载信息。
[root@master ~]# cat /proc/loadavg
0.79 1.29 1.14 1/586 2888
解释:
load1
: 过去一分钟的平均负载。load5
: 过去五分钟的平均负载。load15
: 过去十五分钟的平均负载。runq
: 运行队列的长度。plit
: 活跃任务的数量。
计算CPU负载
CPU负载通常是指系统的平均负载与CPU核心数的比值。如果您知道系统的CPU核心数,可以通过以下方式计算CPU负载:
cpu_cores=<您的CPU核心数>
cpu_load=$(echo "scale=2; ($five_min_load / $cpu_cores)" | bc)
请注意,这里的<您的CPU核心数>需要替换为您的实际CPU核心数。bc命令用于进行浮点运算,scale=2用于设置小数点后的位数。
最佳实践:
- 定期检查负载平均值,与系统的正常负载进行比较。
- 如果负载持续高于CPU核心数,可能需要优化系统或增加资源。
CPU使用率
CPU使用率反映了CPU的忙碌程度。我们可以通过分析/proc/stat
文件来计算CPU使用率。
[root@master ~]# cat /proc/stat
# cpu |user| nice| system| idle| iowait| irq| softirq| steal| guest| guest_nice|
cpu 7120663 240 6464219 86477773 20993501 0 351887 0 0 0
cpu0 3399409 91 3183417 43858519 9887667 0 273765 0 0 0
cpu1 3721254 149 3280801 42619254 11105834 0 78122 0 0 0
intr 2867399715 272 10 0 0 569 0 3 0 0 0 0 0 15 0 608998 0 0 0 0 0 0 0 0 0 0 292996772 0 6071840 1 6685457 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
ctxt 5256803242
btime 1712712608
processes 10745547
procs_running 1
procs_blocked 1
softirq 1084601827 1 338692913 5 101953644 273251017 0 106 162105669 0 208598472
计算方法:
#!/bin/bash
# 获取初始数据
initial_data=$(cat /proc/stat)
# 等待一段时间
sleep 1
# 获取最终数据
final_data=$(cat /proc/stat)
# 初始化变量
user_delta=0
system_delta=0
idle_delta=0
total_delta=0
# 处理每个CPU核心的数据
for i in $(echo "$initial_data" | grep -o 'cpu[0-9]*' | sed 's/cpu//g'); do
initial_cpu_data=$(echo "$initial_data" | grep "cpu$i")
final_cpu_data=$(echo "$final_data" | grep "cpu$i")
# 提取CPU时间数据
initial_user=$(echo "$initial_cpu_data" | awk '{print $2}')
initial_system=$(echo "$initial_cpu_data" | awk '{print $3}')
initial_idle=$(echo "$initial_cpu_data" | awk '{print $4}')
final_user=$(echo "$final_cpu_data" | awk '{print $2}')
final_system=$(echo "$final_cpu_data" | awk '{print $3}')
final_idle=$(echo "$final_cpu_data" | awk '{print $4}')
# 计算时间差
user_delta=$(echo "$user_delta + ($final_user - $initial_user)" | bc)
system_delta=$(echo "$system_delta + ($final_system - $initial_system)" | bc)
idle_delta=$(echo "$idle_delta + ($final_idle - $initial_idle)" | bc)
total_delta=$(echo "$total_delta + ($final_user + $final_system + $final_idle - $initial_user - $initial_system - $initial_idle)" | bc)
done
# 计算CPU使用率
cpu_usage=$(echo "scale=2; ($total_delta - $idle_delta) / $total_delta * 100" | bc)
# 输出结果
echo "CPU Usage: $cpu_usage %"
首先,从/proc/stat文件中读取CPU的统计信息。这个文件提供了自系统启动以来,CPU在不同模式下的累计时间消耗,如用户模式、系统模式和空闲模式等。在等待一段时间后(通常至少1秒),再次读取/proc/stat文件,获取最新的CPU时间统计信息。这段时间的选择应该足够让CPU产生可观察的变化,但又不能太长,以免引入过多的系统负载波动。
对于每个CPU核心,计算用户模式、系统模式和空闲模式下的时间差异。这些差异表示在给定时间间隔内,CPU在这些模式下的工作量。
将所有模式的时间差异相加,得到总的时间差异。这代表了在给定时间间隔内,CPU的总活动量。
同样地,计算空闲模式下的时间差异。这表示在给定时间间隔内,CPU未被使用的时间量。
计算CPU使用率:使用以下公式计算CPU使用率:
CPU使用率 = (总时间差异 - 空闲时间差异) / 总时间差异 * 100%
这个公式通过从总活动量中减去空闲时间量,然后除以总活动量,来得出CPU的使用率。
最后,输出计算得到的CPU使用率百分比,这可以用于监控系统性能,或者作为系统负载的指标。
最佳实践:
- 使用自动化工具,如
vmstat
,定期记录CPU使用情况。 - 对于多核系统,监控每个核心的使用情况。
内存监控
内存是系统运行应用程序和处理数据的关键资源。我们可以通过/proc/meminfo
文件来监控内存状态。
[root@master ~]# cat /proc/meminfo
MemTotal: 2046504 kB
MemFree: 72796 kB
MemAvailable: 300680 kB
Buffers: 1972 kB
Cached: 357968 kB
SwapCached: 0 kB
Active: 1590280 kB
Inactive: 183076 kB
Active(anon): 1427056 kB
Inactive(anon): 11540 kB
Active(file): 163224 kB
Inactive(file): 171536 kB
Unevictable: 22676 kB
Mlocked: 22676 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 652 kB
Writeback: 0 kB
AnonPages: 1436312 kB
Mapped: 95476 kB
Shmem: 15804 kB
Slab: 88660 kB
SReclaimable: 49860 kB
SUnreclaim: 38800 kB
KernelStack: 9280 kB
PageTables: 21152 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 1023252 kB
Committed_AS: 5509768 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 9404 kB
VmallocChunk: 34359709792 kB
Percpu: 768 kB
HardwareCorrupted: 0 kB
AnonHugePages: 278528 kB
CmaTotal: 0 kB
CmaFree: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 87928 kB
DirectMap2M: 2009088 kB
DirectMap1G: 0 kB
内存使用率
内存使用率可以通过比较系统的总内存(MemTotal)和空闲内存(MemFree)来计算。此外,还需要考虑缓存(Cached)和缓冲区(Buffers)内存,因为这些内存虽然被标记为已使用,但实际上可以根据需要重新分配给应用程序。
内存使用率计算公式:
内存使用率 = (1 - (MemFree + Cached + Buffers) / MemTotal) * 100%
内存活跃度
内存活跃度是指经常被访问的内存页面的比例,这可以通过比较活跃内存页面(Active)和非活跃内存页面(Inactive)来衡量。活跃内存页面是频繁访问的,而非活跃内存页面则不是。
内存活跃度计算公式
内存活跃度 = (Active / (Active + Inactive)) * 100%
大页内存活跃度
当计算内存活跃度时,如果系统中使用了大页内存(HugePages),需要考虑这部分内存的特殊性。大页内存通常用于优化大型应用程序的内存访问效率,因为它们可以减少页表的大小和TLB(Translation Lookaside Buffer)缓存的负载。然而,大页内存的管理与传统的小页内存(标准4KB页)有所不同,因此在计算内存活跃度时需要特别处理。
以下是考虑大页内存时计算内存活跃度的方法:
-
确定大页内存的使用情况:首先,从
/proc/meminfo
中读取与大页内存相关的统计数据,包括大页内存的总数(HugePages_Total)、已使用的大页内存(HugePages_Free)和保留的大页内存(HugePages_Rsvd)。 -
计算活跃和非活跃的小页内存:读取
/proc/meminfo
中的Active和Inactive字段,这些字段表示活跃和非活跃的小页内存的数量。 -
计算活跃和非活跃的大页内存:如果系统中使用了大页内存,您需要知道哪些大页是活跃的,哪些是非活跃的。这通常需要额外的工具或方法来确定,因为
/proc/meminfo
不直接提供大页内存的活跃状态。如果没有这些信息,可以假设所有的大页内存都是活跃的,或者根据应用程序的行为进行估计。 -
计算总活跃内存:将活跃的小页内存和活跃的大页内存相加,得到总活跃内存。
-
计算总非活跃内存:将非活跃的小页内存和非活跃的大页内存相加,得到总非活跃内存。
-
计算内存活跃度:使用以下公式计算内存活跃度:
内存活跃度 = (总活跃内存 / (总活跃内存 + 总非活跃内存)) * 100%
请注意,由于大页内存的特殊性,计算内存活跃度可能会变得更加复杂。如果无法精确地确定大页内存的活跃状态,计算结果可能只是一个近似值。在实际应用中,可能需要结合系统的具体使用情况和应用程序的行为来估计大页内存的活跃度。
最佳实践:
- 监控内存使用率和活跃度,以避免内存不足或过度交换。
- 考虑使用内存缓存和交换空间来优化性能。
网络接口监控
网络接口的性能直接影响到系统的网络通信效率。通过分析/proc/net/dev
文件,我们可以监控网络接口的状态。
[root@master ~]# cat /proc/net/dev
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
calidf0202ade0b: 656 8 0 0 0 0 0 0 446 5 0 0 0 0 0 0
calif11cc367b81: 6760 112 0 0 0 0 0 0 7144 118 0 0 0 0 0 0
dummy0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
eth0: 2103354425 14591832 0 0 0 0 0 0 3698959260 13397903 0 0 0 0 0 0
lo: 25659759826 88824066 0 0 0 0 0 0 25659759826 88824066 0 0 0 0 0 0
kube-ipvs0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
caliec11109cadd: 16203320 211027 0 0 0 0 0 0 22233459 267357 0 0 0 0 0 0
tunl0: 197542 403 0 0 0 0 0 0 21268315 354272 0 0 0 0 0 0
cali620188ea77b: 34367473 403845 0 0 0 0 0 0 353895456 410785 0 0 0 0 0 0
每个接口的名称位于行的开始,后面跟着一系列的数字,分别代表:
名称 | 解释 |
---|---|
Rx packets | 接收到的数据包数量(单位:个) |
Rx bytes | 接收到的字节数(单位:字节) |
Rx errors | 接收错误 |
Rx dropped | 接收时丢弃的数据包数量 |
Rx overruns | 接收缓冲区溢出的次数 |
Tx packets | 发送的数据包数量(单位:个) |
Tx bytes | 发送的字节数(单位:字节) |
Tx errors | 发送错误 |
Tx dropped | 发送时丢弃的数据包数量 |
Tx overruns | 发送缓冲区溢出的次数 |
Tx carrier errors | 发送时载体错误的次数 |
Tx collisions | 发送时冲突的次数 |
计算案例
假设我们有一个名为eth0的网络接口,我们想要计算在某个特定时间段内的网络流量。首先,我们需要在两个不同的时间点记录下eth0接口的Rx bytes和Tx bytes值。
时间点1:
[root@master ~]# head -2 /proc/net/dev; grep 'eth0' /proc/net/dev
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
eth0: 2104999299 14605855 0 0 0 0 0 0 3703357281 13413342 0 0 0 0 0 0
时间点2 (10分钟后):
[root@master ~]# head -2 /proc/net/dev; grep 'eth0' /proc/net/dev
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
eth0: 2106578811 14619190 0 0 0 0 0 0 3707723332 13428268 0 0 0 0 0 0
现在,我们将使用这些数据来计算10分钟内的网络流量。
计算接收流量:
# 接收流量 = 时间点2的Rx bytes - 时间点1的Rx bytes
接收流量 = 2106578811 - 2105256111 = 1322700
计算发送流量:
# 发送流量 = 时间点2的Tx bytes - 时间点1的Tx bytes
发送流量 = 3707723332 - 3704084868 = 3638464
将字节转换为比特:
# 流量(bps) = 字节数 * 8
接收流量(bps) = 1322700 * 8 = 10581600 bps
发送流量(bps) = 3638464 * 8 = 29107712 bps
计算总流量:
# 总流量 = 接收流量 + 发送流量
总流量 = 10581600 bps + 29107712 bps = 39689312 bps
根据这个计算,我们可以得出在这10分钟的时间段内,eth0接口的总流量为39689312比特每秒(bps)。这个数据可以帮助我们了解网络的使用情况,如果我们需要监控网络带宽使用或者检测网络瓶颈,这样的计算是非常有用的。
最佳实践:
- 定期监控网络接口的流量,以便及时发现网络拥堵或异常流量。
磁盘监控
磁盘是存储数据的主要介质。通过/etc/mtab
文件,我们可以了解磁盘分区的情况。
[root@master cron.d]# python
Python 2.7.5 (default, Nov 14 2023, 16:14:06)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from os import statvfs
>>> statvfs('/')
posix.statvfs_result(f_bsize=4096, f_frsize=4096, f_blocks=10288179, f_bfree=4565268, f_bavail=4120812, f_files=2621440, f_ffree=2254506, f_favail=2254506, f_flag=4096, f_namemax=255)
#计算公式
磁盘使用率 = `100 - (f_bfree * 100 / f_blocks)`
最佳实践:
- 监控磁盘使用率,确保有足够的磁盘空间。
- 定期检查磁盘健康状况,预防磁盘故障。
网络连接状态监控
通过网络连接状态,我们可以了解系统的网络通信情况。/proc/net/snmp
文件提供了这方面的信息。
[root@master ~]# cat /proc/net/snmp
Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates
Ip: 1 64 101644416 0 0 460 1 0 101643443 101038822 0 40 0 0 0 0 3 0 6
Icmp: InMsgs InErrors InCsumErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps
Icmp: 439298 202 0 263 5 0 0 55 438972 3 0 0 0 0 446574 0 7602 0 0 0 0 0 438972 0 0 0 0
IcmpMsg: InType0 InType3 InType5 InType8 InType11 OutType0 OutType3
IcmpMsg: 3 263 55 438972 5 438972 7602
Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors
Tcp: 1 200 120000 -1 1686536 975775 114585 741592 261 103555259 102377604 2954454 4266 1247740 436
Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors
Udp: 252256 7811 0 253200 0 0 0
UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors
UdpLite: 0 0 0 0 0 0 0
字段名称 | 解释 |
---|---|
TCP RtoAlgorithm | 重传算法的类型 |
TCP RtoMin | 最小重传时间 |
TCP RtoMax | 最大重传时间 |
TCP MaxConn | 最大并发连接数 |
TCP ActiveOpens | 主动打开的连接数 |
TCP PassiveOpens | 被动打开的连接数 |
TCP AttemptFails | 连接尝试失败的次数 |
TCP EstabResets | 被对方重置的连接数 |
TCP CurrEstab | 当前已建立的连接数 |
TCP InSegs | 接收到的TCP段数 |
TCP OutSegs | 发送的TCP段数 |
TCP RetransSegs | 重传的TCP段数 |
TCP InErrs | 接收到的带有错误的TCP段数 |
TCP OutRsts | 发送的重置连接的TCP段数 |
TCP InCsumErrors | 接收到的校验和错误的TCP段数 |
UDP InDatagrams | 接收到的UDP数据报文数 |
UDP NoPorts | 由于没有监听的端口而被丢弃的UDP数据报文数 |
UDP InErrors | 接收到的错误UDP数据报文数 |
UDP OutDatagrams | 发送的UDP数据报文数 |
UDP RcvbufErrors | 接收缓冲区溢出导致的错误数 |
UDP SndbufErrors | 发送缓冲区溢出导致的错误数 |
UDP InCsumErrors | 接收到的校验和错误的UDP数据报文数 |
/proc/net/snmp文件提供了网络子系统的统计信息,但它本身并不直接提供当前活动的连接列表。然而,您可以通过监控Tcp部分中的某些指标来间接地了解连接的状态和数量。
以下是一些通过/proc/net/snmp监控连接数的方法:
跟踪CurrEstab值
CurrEstab表示当前已建立的TCP连接数。通过定期检查这个值,您可以了解当前的连接数量。如果这个数值持续增长或异常高,可能表明有大量连接正在建立,这可能是正常业务流量,也可能是潜在的攻击。
监控ActiveOpens和PassiveOpens
ActiveOpens表示系统主动尝试建立连接的次数。
PassiveOpens表示系统被动接受连接的次数。
监控这两个指标可以帮助您了解系统的连接模式。如果ActiveOpens远大于PassiveOpens,可能表明系统更多地作为客户端发起连接;反之,则表明系统更多地作为服务器接受连接。
检查InSegs和OutSegs
InSegs表示接收到的TCP段数量。
OutSegs表示发送的TCP段数量。
这两个指标可以帮助您了解数据传输的活跃程度。如果这两个值持续增加,可能表明网络连接正在积极传输数据。
注意InErrs和OutRsts
InErrs表示接收到的带有错误的TCP段数量。
OutRsts表示发送的重置连接的TCP段数量。
如果这两个指标的值较高,可能表明网络连接存在问题,如丢包、超时或其他错误。
为了更有效地监控连接数,您可以编写脚本定期读取/proc/net/snmp文件,并记录上述指标的值。通过分析这些数据随时间的变化,您可以识别出网络流量的模式和潜在的问题。
请注意,/proc/net/snmp文件提供的是统计信息,而不是实时的连接状态。如果您需要查看当前所有的网络连接,可以使用netstat命令或查看/proc/net/tcp文件(对于TCP连接)和/proc/net/udp文件(对于UDP连接)。这些工具和文件提供了更详细的关于当前活动连接的信息。
最佳实践:
- 监控TCP和UDP的连接状态,以便及时发现网络问题。
- 使用防火墙和安全策略来保护系统免受未授权访问。
监控SWAP分区使用
查看哪个进程占用的SWAP分区比较多。
for i in $(cd /proc;ls | grep "^[0-9]" | awk '$0>100'); do awk '/Swap:/{a=a+$2}END{print '"$i"',a/1024"M"}' /proc/$i/smaps;done| sort -k2nr | head
监控进程打开的句柄数
查看当前进程打开了多少文件句柄。
lsof -n | awk '{print($2)}' | sort | uniq -c | sort -nr | more
结论
掌握Linux系统监控技巧对于确保系统稳定运行至关重要。通过本文介绍的方法,您可以有效地监控系统的关键性能指标,并采取适当的措施来优化系统性能。记住,定期监控和维护是保持系统健康的关键。同时,利用自动化监控工具可以大大提高效率和准确性。希望本文能帮助您更好地理解和应用Linux系统监控,确保您的系统始终处于最佳状态。