掌握几种linux工具让程序更稳定

总结几种linux下观察程序使用资源情况的工具,包括:CPU,内存,fd有无泄漏,IO有无异常(比如日志异常输出),网络IO有无异常。通过这几种工具监控程序运行时资源有无异常,让程序更加稳定。

CPU使用率

最常用的命令是top,它可以显示整个系统中所有进程的CPU使用情况并且可以进行排序,当然它不止可以监控CPU资源,还可以监控内存,IO等。默认以CPU的使用率排序。最简单的方式就是直接输入top命令查看整个系统资源使用情况。

通过top命令也可以监控进程中线程CPU的使用情况,默认也是按CPU使用情况排序

-H 是一个很有用的参数,可以直接查看进程中线程资源使用的情况,并且可以看到进程中线程数

top -H -p 18047

如上命令通过top查看进程18047所有线程的资源使用状态,如下是结果

top - 14:56:53 up 28 days,  4:12,  3 users,  load average: 0.00, 0.03, 0.05
Threads:  15 total,   0 running,  15 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.9 us,  0.3 sy,  0.0 ni, 98.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  7747244 total,  1567056 free,  2786128 used,  3394060 buff/cache
KiB Swap:  7995388 total,  7646984 free,   348404 used.  4241380 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                                                     
18047 root      20   0  366744  21036   2464 S  0.0  0.3   0:07.73 RelayServer                                                                                                 
18051 root      20   0  366744  21036   2464 S  0.0  0.3   0:03.08 RelayServer                                                                                                 
18052 root      20   0  366744  21036   2464 S  0.0  0.3   0:00.00 RelayServer                                                                                                 
18053 root      20   0  366744  21036   2464 S  0.0  0.3   0:17.26 RelayServer                                                                                                 
18054 root      20   0  366744  21036   2464 S  0.0  0.3   0:26.31 RelayServer                                                                                                 
18055 root      20   0  366744  21036   2464 S  0.0  0.3   0:09.40 RelayServer                                                                                                 
18056 root      20   0  366744  21036   2464 S  0.0  0.3   0:11.53 RelayServer                                                                                                 
18057 root      20   0  366744  21036   2464 S  0.0  0.3   0:04.05 RelayServer                                                                                                 
18058 root      20   0  366744  21036   2464 S  0.0  0.3   0:24.14 RelayServer                                                                                                 
18059 root      20   0  366744  21036   2464 S  0.0  0.3   0:17.90 RelayServer                                                                                                 
18060 root      20   0  366744  21036   2464 S  0.0  0.3   0:38.72 RelayServer                                                                                                 
18061 root      20   0  366744  21036   2464 S  0.0  0.3   0:22.37 RelayServer                                                                                                 
18062 root      20   0  366744  21036   2464 S  0.0  0.3   0:42.98 RelayServer                                                                                                 
18063 root      20   0  366744  21036   2464 S  0.0  0.3   0:14.47 RelayServer                                                                                                 
18064 root      20   0  366744  21036   2464 S  0.0  0.3   1:56.67 RelayServer

软中断

linux中的软中断包括网络收发,定时,RCU锁等各种
,每个CPU都对应一个软中断内核线程,名字是ksoftirqd/CPU编号。当软中断事件的频率过高时,内核线程也会因为CPU使用率过高而导致软中断处理不及时,进而引发网络收发,调度缓慢等性能问题。

可以通过 watch -d cat /proc/softirqs 命令查看系统软中断次数,其中watch命令是变化,cat /proc/softirqs才是显示系统中真正的累计中断次数

一种分析网络服务的收发包是否正常的方式:通过查看软中断中NET_TX 和 NET_RX的增速是否很快,如果很快,CPU在处理大量网络中断,使用率肯定会增高。这个时候就需要查看程序收发包的代码逻辑,为什么会有大量的收发包情况。

如下命令输出,显示每个CPU上软中断的累计次数

Every 2.0s: cat /proc/softirqs                                                                                                                                                                                   Tue Jul  2 17:36:50 2019

                    CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7
          HI:          2          0          0          0          0          0          2          0
       TIMER:    3010721    2977489    3016155    3099307    2897057    3492281    2896383    2853132
      NET_TX:       6201         43         69        201        914       1233        336         82
      NET_RX:     897297     336229     907668   16233407    8454552     506387     877685   16687073
       BLOCK:       4227        416     158020        147        158      65584        104    1391370
BLOCK_IOPOLL:          0          0          0          0          0          0          0          0
     TASKLET:       3797        169        207        157    7311978       2827        668   15754714
       SCHED:    1307215     474968     706726     330146     550114     258509     535334     326909
     HRTIMER:          0          0          0          0          0          0          0          0
         RCU:    1864254    1629223    1880544    1730405    1864998    1876487    1865292    1806708
         

在网络程序的协议设计中应尽量避免设计成小包协议(避免收发大量小包),这种情况会造成产生大量的的收发包中断,而影响性能

句柄泄漏

句柄泄漏是服务端编程经常遇到问题,这种问题的表现比较隐晦,它并不影响业务,但是如果服务长时间运行或在请求高峰值的情况下,句柄泄漏加剧,达到进程限制值。这个时候服务就无法处理新的请求了。所以在服务测试阶段就应该测试服务有无句柄泄漏的情况。

lsof -p 进程id

lsof列出了进行所有的资源,常见的包括文件fd,socket fd,eventfd,timerfd,eventpoll等,通过lsof命令可以查看指定进程打开的fd,根据linux下一切皆文件的思想

watch lsof -p 进程id

可以查看指定进程的fd的变化情况,判断出fd是否有泄漏。

COMMAND     PID USER   FD      TYPE   DEVICE SIZE/OFF      NODE NAME
RelayServ 18047 root  cwd       DIR    253,0     4096   3070583 /usr/local/smartseesip/siprelay
RelayServ 18047 root  rtd       DIR    253,0     4096       192 /
RelayServ 18047 root  txt       REG    253,0  7921129   3070563 /usr/local/smartseesip/siprelay/RelayServer
RelayServ 18047 root  mem       REG    253,0  2107816 201329626 /usr/lib64/libc-2.17.so
RelayServ 18047 root  mem       REG    253,0    88720 201326793 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
RelayServ 18047 root  mem       REG    253,0  1141552 201329666 /usr/lib64/libm-2.17.so
RelayServ 18047 root  mem       REG    253,0   995840 201329703 /usr/lib64/libstdc++.so.6.0.19
RelayServ 18047 root  mem       REG    253,0   110808 201329686 /usr/lib64/libresolv-2.17.so
RelayServ 18047 root  mem       REG    253,0    19512 201329664 /usr/lib64/libdl-2.17.so
RelayServ 18047 root  mem       REG    253,0   142296 201329684 /usr/lib64/libpthread-2.17.so
RelayServ 18047 root  mem       REG    253,0    44088 201329688 /usr/lib64/librt-2.17.so
RelayServ 18047 root  mem       REG    253,0   164432 201329619 /usr/lib64/ld-2.17.so
RelayServ 18047 root    0r      CHR      1,3      0t0      1028 /dev/null
RelayServ 18047 root    1w      CHR      1,3      0t0      1028 /dev/null
RelayServ 18047 root    2w      CHR      1,3      0t0      1028 /dev/null
RelayServ 18047 root    3w      REG    253,0        0 137585576 /usr/local/smartseesip/siprelay/relay/relay.20190702-000220.18047.log
RelayServ 18047 root    4r     FIFO      0,8      0t0  12209677 pipe
RelayServ 18047 root    5w     FIFO      0,8      0t0  12209677 pipe
RelayServ 18047 root    6r     FIFO      0,8      0t0  12209678 pipe
RelayServ 18047 root    7w     FIFO      0,8      0t0  12209678 pipe
RelayServ 18047 root    8u     IPv4 12209679      0t0       UDP 192.168.100.104:sentinel-lm 
RelayServ 18047 root    9u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   10u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   11u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   12u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   13u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   14u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   15u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   16u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   17u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   19u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   20u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   21u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   23u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   24u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   25u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   26u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   27u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   28u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   31u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   32u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   33u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   36u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   37u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   38u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   41u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   42u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   43u  a_inode      0,9        0      6765 [timerfd]
RelayServ 18047 root   46u  a_inode      0,9        0      6765 [eventfd]
RelayServ 18047 root   47u  a_inode      0,9        0      6765 [eventpoll]
RelayServ 18047 root   48u  a_inode      0,9        0      6765 [timerfd]

如上所示,lsof列出了RelayServer所打开的所有句柄,包括socket fd,文件,event fd,timer fd等

IO

服务的业务模型通常分为CPU密集型和IO密集型,CPU密集型就是服务需要占用CPU进行大量计算,比如视频转码服务,会议服务等。IO密集型是主要业务操作是IO操作,比如ftp服务,代理服务等。CPU密集型的服务CPU占用比较高,IO密集型服务CPU占用比较低(当然高低是个相对概念)。

top 命令的输出中有个wa占用比例可以用来判断当前系统的IO情况,如果服务是CPU密集型,这个wa占用率高,那么就应该要注意了,比如需要关注是否是在狂打日志。

top中iowait的比例

通过 pidstat -d 来查看每个进程的IO情况,确定具体进程的IO情况,如果所关注的进程出现异常值(值比预期的大),那么就需要检查进程的代码逻辑了


[root@localhost GWStreamServer]# pidstat -d 5
Linux 3.10.0-327.el7.x86_64 (localhost.localdomain)     2019年07月02日  _x86_64_        (4 CPU)

21时52分11秒   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
21时52分16秒     0      1321      0.00      4.79      0.00  dmserver

21时52分16秒   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
21时52分21秒     0      1321      0.00      4.00      0.00  dmserver
21时52分21秒     0      2879      0.00      0.80      0.00  slapd
21时52分21秒     0      2881      0.00      2.40      0.00  java
21时52分21秒     0      3009      0.00      5.60      0.00  java
21时52分21秒     0      3036      0.00      2.40      0.00  java

网络

最常用的命令就是netstat,可以查看程序占用的端口及端口被哪个程序占用,可以查看tcp的状态,可以统计当前系统的网络协议信息

  • 查看RelayServer的占用的端口
netstat -anp | grep RelayServer 

输出如下,RelayServer占用udp端口 5093

udp        0      0 192.168.20.87:5093      0.0.0.0:*                           2841/./RelayServer
  • 查看端口554被哪个程序占用
nestat -anp | grep 554

输出如下,554被DarwnStreamin程序占用,类型为tcp,状态为listen

tcp        0      0 0.0.0.0:554             0.0.0.0:*               LISTEN      2688/DarwinStreamin
  • 协议状态统计
netstat -s 

可以统计协议的工作状态,但它的输出较多,不便宜观察,推荐使用

ss -s 

输出如下:

Total: 508 (kernel 625)
TCP:   80 (estab 51, closed 6, orphaned 0, synrecv 0, timewait 5/0), ports 0

Transport Total     IP        IPv6
*         625       -         -        
RAW       1         0         1        
UDP       14        10        4        
TCP       74        40        34       
INET      89        50        39       
FRAG      0         0         0        

TCP那行里,可以直接看到当前系统所有tcp连接的状态,如已连接状态,close状态等。这样的输出数据简洁明亮,便于观察。

程序调试

  • top + gdb,在前面介绍过通过 top -H -p 命令可以查看指定进程中,线程占用的资源情况。比如观察到占 CPU最高的线程ID后,我们可以通过gdb - pid 直接附加到线程,查看当前线程的堆栈信息,定位程序逻辑问题。

  • perf top,一般在生产环境是不可能用gdb直接去调试程序,这样会造成程序无法处理业务。通过perf工具,可以直接查看系统中消耗性能最大的函数列表。

top + gdb的方式,简单,直接。perf工具提供的分析方式更多,更深入,当然也要求对linux系统知识有更深的理解。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mo4776

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值