新聞中心
系統(tǒng)資源常分為兩類,一類是軟件資源,如進(jìn)程、線程、文件描述符、socket連接,偏開發(fā)視角,另一類是硬件資源,如CPU、內(nèi)存、硬盤、網(wǎng)絡(luò),偏運(yùn)維視角,而本章主要介紹Linux中與觀測軟件資源有關(guān)的命令。

成都創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于網(wǎng)站設(shè)計制作、網(wǎng)站設(shè)計、堆龍德慶網(wǎng)絡(luò)推廣、微信小程序、堆龍德慶網(wǎng)絡(luò)營銷、堆龍德慶企業(yè)策劃、堆龍德慶品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎;成都創(chuàng)新互聯(lián)公司為所有大學(xué)生創(chuàng)業(yè)者提供堆龍德慶建站搭建服務(wù),24小時服務(wù)熱線:18982081108,官方網(wǎng)址:www.cdcxhl.com
ps查看進(jìn)程相關(guān)信息
相信ps命令大家也比較熟悉,主要是用來列出進(jìn)程的,基本用法如下:
# 列出所有進(jìn)程,-e表示列出所有進(jìn)程,-f表示列出進(jìn)程詳細(xì)信息
$ ps -ef
# 也是列出所有進(jìn)程,這是從BSD系統(tǒng)中保留過來的用法
$ ps aux
# -C java指定列出java進(jìn)程
$ ps -fC java
# 列出java進(jìn)程的pid,cpu使用率,內(nèi)存使用率,-o指定列出的字段
$ ps -o pid,pcpu,pmem -C java
# 列出pid=328的進(jìn)程,-p指定列出具體進(jìn)程
$ ps -fp 328
# 列出前10個進(jìn)程,cpu及內(nèi)存倒序排序,--sort指定排序字段
ps aux --sort -pcpu,-pmem | head -n 10
上面用法在網(wǎng)上是很常見的,下面這些就不太常見了,但也很有用,如下:
- 查看進(jìn)程啟動時間。
有時進(jìn)程在非常頻繁的重啟,會導(dǎo)致系統(tǒng)CPU升高,可通過查看進(jìn)程啟動時間來推斷是否剛重啟了。
# 查看各java進(jìn)程啟動時間與已運(yùn)行時長
$ ps -o lstart,etime -C java
STARTED ELAPSED
Fri Oct 22 20:33:31 2021 10:05
- 查看進(jìn)程的線程數(shù)量。
因為在Linux中,線程也叫做輕量級進(jìn)程Light Weight Process(LWP),所以查看LWP數(shù)量就是線程數(shù)量。
# 查看各java進(jìn)程的線程數(shù)量
$ ps -o pid,nlwp -C java
PID NLWP
2121 21
- 查看運(yùn)行與阻塞狀態(tài)的線程數(shù)量
如果系統(tǒng)CPU使用率很高,我們可以通過top命令進(jìn)一步找到是哪個進(jìn)程占用cpu高,但在某些特殊場景下,可能會發(fā)現(xiàn)系統(tǒng)負(fù)載很高,但CPU使用率不高,這是由于Linux系統(tǒng)負(fù)載綜合考察了系統(tǒng)中正在運(yùn)行(R狀態(tài))的線程數(shù)量以及阻塞于IO(D狀態(tài))的線程數(shù)量,如果線程全阻塞于IO調(diào)用,就可能出現(xiàn)此現(xiàn)象。
這時可以嘗試用下面方法統(tǒng)計各進(jìn)程運(yùn)行與阻塞線程數(shù)量,以判斷是哪個進(jìn)程導(dǎo)致了問題。
# 看進(jìn)程運(yùn)行及阻塞的線程數(shù)量之和,其中h表示不打印標(biāo)題行,-L表示顯示線程而不是進(jìn)程
$ ps h -eLo s,pid | grep ^[RD] |sort|uniq -c|sort -nrk1
/proc目錄
在Linux系統(tǒng)中,進(jìn)程的信息,都被虛擬到/proc目錄中了,而ps命令不過是從這個目錄中讀取數(shù)量,并展示出來罷了。
而/proc/397/就表示397這個進(jìn)程相關(guān)信息的起始目錄,如下:
$ ll /proc/397/
total 0
dr-xr-xr-x 2 work work 0 2021-10-17 21:41:53 attr
-r-------- 1 work work 0 2021-10-17 21:41:53 auxv
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 cgroup
-r--r--r-- 1 work work 0 2021-10-17 21:41:41 cmdline
-rw-r--r-- 1 work work 0 2021-10-17 21:41:53 comm
-rw-r--r-- 1 work work 0 2021-10-17 21:41:53 coredump_filter
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 cpuset
lrwxrwxrwx 1 work work 0 2021-10-17 21:41:53 cwd -> /home/work
-r-------- 1 work work 0 2021-10-17 21:41:53 environ
lrwxrwxrwx 1 work work 0 2021-10-17 21:41:53 exe -> /usr/bin/ncat
dr-x------ 2 work work 0 2021-10-17 21:41:53 fd
dr-x------ 2 work work 0 2021-10-17 21:41:53 fdinfo
-r-------- 1 work work 0 2021-10-17 21:41:53 io
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 limits
dr-x------ 2 work work 0 2021-10-17 21:41:53 map_files
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 maps
-rw------- 1 work work 0 2021-10-17 21:41:53 mem
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 mounts
dr-xr-xr-x 12 work work 0 2021-10-17 21:41:53 net
dr-x--x--x 2 work work 0 2021-10-17 21:41:53 ns
-rw-r--r-- 1 work work 0 2021-10-17 21:41:53 oom_adj
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 oom_score
-rw-r--r-- 1 work work 0 2021-10-17 21:41:53 oom_score_adj
lrwxrwxrwx 1 work work 0 2021-10-17 21:41:53 root -> /
-rw-r--r-- 1 work work 0 2021-10-17 21:41:53 sched
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 schedstat
-rw-r--r-- 1 work work 0 2021-10-17 21:41:53 setgroups
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 smaps
-r-------- 1 work work 0 2021-10-17 21:41:53 stack
-r--r--r-- 1 work work 0 2021-10-17 21:41:41 stat
-r--r--r-- 1 work work 0 2021-10-17 21:41:41 status
-r-------- 1 work work 0 2021-10-17 21:41:53 syscall
dr-xr-xr-x 3 work work 0 2021-10-17 21:41:53 task
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 timers
可見內(nèi)容是相當(dāng)?shù)亩啵覀儊砜纯催@里面常見的項:
# cmdline保存了進(jìn)程啟動的命令行
$ cat /proc/397/cmdline|xargs -0
ncat -lk 8888
# cwd是個軟鏈接,指向了進(jìn)程的工作目錄
$ readlink /proc/397/cwd
/home/work
# environ保存了進(jìn)程的環(huán)境變量
$ cat /proc/397/environ
# exe是個軟鏈接,指向了啟動進(jìn)程的命令程序
$ readlink /proc/397/exe
/usr/bin/ncat
# status存儲進(jìn)程一些基礎(chǔ)信息
$ cat /proc/397/status
Name: ncat
Umask: 0022
State: S (sleeping)
Tgid: 397
Ngid: 0
Pid: 397
PPid: 31607
TracerPid: 0
Uid: 1000 1000 1000 1000
Gid: 1000 1000 1000 1000
# /task目錄保存進(jìn)程的線程相關(guān)信息
cat /proc/397/task/
# fd目錄里面保存著進(jìn)程打開的文件描述符,可以用來查看進(jìn)程打開了什么文件,打開了多少網(wǎng)絡(luò)連接
$ ll /proc/397/fd
total 0
lrwx------ 1 work work 64 2021-10-17 21:47:23 0 -> /dev/pts/3
l-wx------ 1 work work 64 2021-10-17 21:47:23 1 -> /home/work/app.log
lrwx------ 1 work work 64 2021-10-17 21:47:23 2 -> /dev/pts/3
lrwx------ 1 work work 64 2021-10-17 21:47:23 3 -> 'socket:[49436]'
lrwx------ 1 work work 64 2021-10-17 21:47:23 4 -> 'socket:[49437]'
# maps保存了進(jìn)程的內(nèi)存段映射信息,pmap命令取的就是這里面的數(shù)據(jù)
# 如果你是C/C++系開發(fā)者,可能會相對熟悉一些
$ cat /proc/397/maps | head
5606c2808000-5606c280d000 r--p 00000000 08:10 11419 /usr/bin/ncat
5606c280d000-5606c282f000 r-xp 00005000 08:10 11419 /usr/bin/ncat
5606c282f000-5606c283d000 r--p 00027000 08:10 11419 /usr/bin/ncat
5606c283e000-5606c283f000 r--p 00035000 08:10 11419 /usr/bin/ncat
5606c283f000-5606c2840000 rw-p 00036000 08:10 11419 /usr/bin/ncat
5606c2840000-5606c2841000 rw-p 00000000 00:00 0
5606c397e000-5606c399f000 rw-p 00000000 00:00 0 [heap]
7f0c7a5ce000-7f0c7a5d0000 rw-p 00000000 00:00 0
7f0c7a5d0000-7f0c7a5df000 r--p 00000000 08:10 44447 /usr/lib/x86_64-linux-gnu/libm-2.31.so
7f0c7a5df000-7f0c7a686000 r-xp 0000f000 08:10 44447 /usr/lib/x86_64-linux-gnu/libm-2.31.so
# net目錄保存著網(wǎng)絡(luò)相關(guān)的信息,如下/net/tcp保存著進(jìn)程的tcp連接信息
$ cat /proc/397/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 00000000:22B8 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 49437 1 0000000007f9a245 100 0 0 10 0
# sched保存著進(jìn)程被調(diào)度的一些信息,如:
# se.nr_migrations線程遷移次數(shù)
# nr_voluntary_switches自愿上下文切換次數(shù)
# nr_involuntary_switches非自愿上下文切換次數(shù)
$ cat /proc/397/sched
ncat (397, #threads: 1)
-------------------------------------------------------------------
se.exec_start : 85694324.807968
se.vruntime : 333882.289243
se.sum_exec_runtime : 10.572689
se.nr_migrations : 0
nr_switches : 10
nr_voluntary_switches : 10
nr_involuntary_switches : 0
se.load.weight : 1048576
se.runnable_weight : 1048576
se.avg.load_sum : 42293
se.avg.runnable_load_sum : 42293
se.avg.util_sum : 26159838
se.avg.load_avg : 914
se.avg.runnable_load_avg : 914
se.avg.util_avg : 552
se.avg.last_update_time : 85694324807680
se.avg.util_est.ewma : 499
se.avg.util_est.enqueued : 553
policy : 0
prio : 120
clock-delta : 43
通過工作目錄找進(jìn)程
有時候,多個相同的程序部署在同一臺機(jī)器上,比如Tomcat,但你只知道你們的Tomcat在/home/work/tomcat_order/目錄,這時可以查詢出各個tomcat進(jìn)程的工作目錄(cwd),然后辨別哪個是自己的Tomcat,如下:
# 查詢各java進(jìn)程的工作目錄,注:tomcat是java實現(xiàn)的
# 可以看到867進(jìn)程的工作目錄是/home/work/tomcat_order/,那它就是我們要找的進(jìn)程啰
$ pgrep java | xargs -i ls -l /proc/{}/cwd
lrwxrwxrwx 1 work work 0 2021-10-17 22:15:30 /proc/867/cwd -> /home/work/tomcat_order
lrwxrwxrwx 1 work work 0 2021-10-17 22:15:30 /proc/885/cwd -> /home/work/tomcat_goods
lrwxrwxrwx 1 work work 0 2021-10-17 22:15:42 /proc/906/cwd -> /home/work/tomcat_stock
找進(jìn)程的日志文件
在排查問題時,經(jīng)常需要查閱日志文件,如果你記不住相關(guān)進(jìn)程的日志文件寫到什么目錄了,就可以通過/proc/$pid/fd/目錄來查找,如下:
$ ll /proc/867/fd | grep .log$
l-wx------ 1 work work 64 2021-10-17 22:24:03 1 -> /home/work/app.log
netstat查看網(wǎng)絡(luò)連接
netstat是用來查看網(wǎng)絡(luò)連接信息的工具命令,具體來說,像在編程語言中可以通過創(chuàng)建socket來建立網(wǎng)絡(luò)連接,而netstat就是用來查看這些socket信息的,如下:
# 查看所有的socket,-n代表不解析ip為主機(jī)名,-a表示all所有,-t代表tcp
$ netstat -nat
# 顯示各狀態(tài)socket數(shù)量,TIME_WAIT與CLOSE_WAIT數(shù)量太多,一般都不是好事情
$ netstat -nat | awk '/tcp/{print $6}'|sort|uniq -c
21 ESTABLISHED
3 TIME_WAIT
3 CLOSE_WAIT
2 LISTEN
# 查看LISTEN狀態(tài)的socket,-l代表只顯示LISTEN狀態(tài)的
$ netstat -nlt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:8888 0.0.0.0:* LISTEN
tcp6 0 0 :::8888 :::* LISTEN
# 查看進(jìn)程867的socket數(shù)量,-p顯示出創(chuàng)建網(wǎng)絡(luò)連接的進(jìn)程號
$ netstat -natp|grep -w 867 -c
2
# 找到監(jiān)聽在8888端口的進(jìn)程
$ netstat -nltp|grep -w 8888
tcp 0 0 0.0.0.0:8888 0.0.0.0:* LISTEN 867/ncat
tcp6 0 0 :::8888 :::* LISTEN 867/ncat
lsof查看打開文件
在Linux的設(shè)計哲學(xué)中,"一切皆文件",像進(jìn)程(/proc/$pid)、網(wǎng)絡(luò)連接(/proc/net/tcp)、主機(jī)設(shè)備(/dev)等,Linux也都把它虛擬成了文件,方便程序或shell讀取,就像上面的ps命令,如果你愿意,通過讀取/proc目錄的數(shù)據(jù),可以非常容易地實現(xiàn)自己的ps命令!
而lsof(list open files)命令,就是用來查看系統(tǒng)或進(jìn)程打開的文件的,所以這個命令非常的強(qiáng)大,它幾乎是觀測軟件資源最好用的工具了,如下:
# 查看系統(tǒng)打開的所有文件(包括網(wǎng)絡(luò)連接等)
$ lsof
# 查看進(jìn)程867打開的文件(包括網(wǎng)絡(luò)連接等),-p指定具體進(jìn)程號
$ lsof -p 867
# 類似上面介紹的,查找進(jìn)程的日志文件
$ lsof -p 867 | grep .log$
# 類似上面介紹的,查看java進(jìn)程的工作目錄, -c java表示過濾出java進(jìn)程的文件,-d cwd表示過濾出工作目錄
# 而-a表示-c與-d是AND關(guān)系(默認(rèn)OR),即java進(jìn)程的cwd文件,就是工作目錄
$ lsof -a -c java -d cwd
ncat 867 work 1w REG 8,16 0 171403 /home/work/app.log
# 顯示進(jìn)程867的tcp連接,-n不解析ip為主機(jī)名,-P不解析端口為服務(wù)名,-i TCP顯示TCP連接
$ lsof -a -nP -i TCP -p 867
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ncat 867 work 3u IPv6 48737 0t0 TCP *:8888 (LISTEN)
ncat 867 work 4u IPv4 48738 0t0 TCP *:8888 (LISTEN)
# 顯示8888號端口的連接
$ lsof -nP -i :8888
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ncat 867 work 3u IPv6 48737 0t0 TCP *:8888 (LISTEN)
ncat 867 work 4u IPv4 48738 0t0 TCP *:8888 (LISTEN)
# 顯示與172.16.12.5主機(jī)的連接
$ lsof -nP -i @172.16.12.5
# 通過指定目錄或文件找進(jìn)程
$ lsof /home/work/app.log
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ncat 867 work 1w REG 8,16 0 171403 /home/work/app.log
有時候,系統(tǒng)磁盤空間不足了,我們想刪掉一些大的日志文件來釋放磁盤空間,卻發(fā)現(xiàn)刪除后,磁盤剩余空間沒有變多,這是因為有進(jìn)程引用了這個文件,可以如下確認(rèn):
# 找出已刪除但被進(jìn)程引用的文件
$ lsof | grep deleted
ncat 867 work 1w REG 8,16 0 171403 /home/work/app.log (deleted)
這時我們只需要重啟867這個進(jìn)程,即可真正釋放空間。
注:可以這么理解,刪除文件只是去掉了文件系統(tǒng)對這個文件的引用,而如果進(jìn)程之前還打開了這個文件,那進(jìn)程中保有的文件描述符也是引用了這個文件的,此時文件還不能回收,因為回收可能會導(dǎo)致進(jìn)程出錯,然而重啟進(jìn)程后,對文件的所有引用就都沒有了,文件占用的空間才能被真正回收。
實踐
1、陌生環(huán)境找服務(wù)日志
當(dāng)我們剛開始接手一些系統(tǒng)時,對系統(tǒng)的部署情況不太了解,比如訂單系統(tǒng)的數(shù)據(jù)庫地址是test.mycat.order.proxy:8566,它是個mycat,部署在test.mycat.order.proxy機(jī)器上,但運(yùn)維在這臺機(jī)器上還部署了好幾個其它系統(tǒng)的mycat,那怎么找到自己的mycat進(jìn)程,并找到其gc日志呢?
- 登錄test.mycat.order.proxy,根據(jù)8566端口找進(jìn)程
$ netstat -nltp|grep -w 8566
tcp 0 0 0.0.0.0:8566 0.0.0.0:* LISTEN 467313/haproxy
可見8566并不是mycat進(jìn)程,而是一個網(wǎng)絡(luò)代理haproxy,對于網(wǎng)絡(luò)代理進(jìn)程,它連出最多的端口,一般就是代理后面的服務(wù)提供的,所以我們需要再查一下haproxy創(chuàng)建了哪些連接。
- 查找haproxy創(chuàng)建了哪些連接
# 注:467313是haproxy的進(jìn)程號
$ netstat -natp|grep 467313
tcp 0 0 0.0.0.0:8566 0.0.0.0:* LISTEN 467313/haproxy
tcp 0 0 10.12.231.1:8566 10.39.12.32:42282 ESTABLISHED 467313/haproxy
tcp 0 0 10.12.231.1:8566 10.39.12.32:36638 ESTABLISHED 467313/haproxy
tcp 0 0 10.12.231.1:21103 10.12.231.1:8466 ESTABLISHED 467313/haproxy
tcp 0 0 10.12.231.1:31417 10.12.231.1:8466 ESTABLISHED 467313/haproxy
tcp 0 0 10.12.231.1:48432 10.12.231.1:8466 ESTABLISHED 467313/haproxy
tcp 0 0 10.12.231.1:59047 10.12.231.1:8466 ESTABLISHED 467313/haproxy
可見,haproxy進(jìn)程連出最多的是8466端口。
- 再根據(jù)8466端口找進(jìn)程
$ netstat -nltp|grep -w 8466
tcp 0 0 0.0.0.0:8466 0.0.0.0:* LISTEN 956758/java
找到了一個java進(jìn)程,mycat就是java實現(xiàn)的,那這個估計就是我們的mycat進(jìn)程了,如下確認(rèn)一下:
- 查看進(jìn)程詳情
$ ps -fp 956758 | cat
UID PID PPID C STIME TTY TIME CMD
work 956758 956756 11 Oct15 ? 09:15:36 java -DMYCAT_HOME=. -server -XX:MaxPermSize=128M -XX:-UseGCOverheadLimit -XX:+AggressiveOpts -XX:MaxDirectMemorySize=4G -XX:+HeapDumpOnOutOfMemoryError ...
$ ll /proc/956758/cwd
lrwxrwxrwx 1 work work 0 Oct 15 16:22 /proc/956758/cwd -> /home/work/order/mycat
可見,它就是個mycat,且其工作目錄在/home/work/order/mycat。
- 查找其gc日志
$ ll /proc/956758/fd | grep .log$
l-wx------ 1 work work 64 Oct 16 14:12 3 -> /home/work/order/mycat/logs/gc-2021-10-15_15-27-40.log
l-wx------ 1 work work 64 Oct 16 14:12 57 -> /home/work/order/mycat/logs/sql_time.log
l-wx------ 1 work work 64 Oct 16 14:12 58 -> /home/work/order/mycat/logs/mycat_auth.log
l-wx------ 1 work work 64 Oct 16 14:12 59 -> /home/work/order/mycat/logs/error_msg.log
l-wx------ 1 work work 64 Oct 16 14:12 60 -> /home/work/order/mycat/logs/mycat_prepare.log
l-wx------ 1 work work 64 Oct 16 14:12 61 -> /home/work/order/mycat/logs/sql_error_msg.log
這樣,我們就在自己本不熟悉的機(jī)器環(huán)境里,找到了自己服務(wù)的gc日志。
2、文件描述符泄露
系統(tǒng)的文件描述符資源是有限的,用完了必須歸還,不然就會發(fā)生泄露,對應(yīng)在Java中的場景如下:
a. 通過fis=new FileInputStream("xxx")打開文件,讀取完文件后,必須調(diào)用fis.close()關(guān)閉,不然FD(file descriptor)創(chuàng)建越來越多,導(dǎo)致oom。
b. jdbc中通過conn=DriverManager.getConnection()獲取連接,操作完數(shù)據(jù)庫后,必須調(diào)用conn.close()關(guān)閉,不然就會socket創(chuàng)建越來越多(socket也是一種文件,也有FD),導(dǎo)致oom。
要想確認(rèn)java服務(wù)中,是否存在那種忘記調(diào)用close的地方,只需要不斷監(jiān)控進(jìn)程的FD數(shù)量,如果它一直都在增長,基本就是發(fā)生了泄露,如下:
$ while true; do pgrep java | xargs -i ls -l /proc/{}/fd | wc -l; sleep 10; done | tee fd_num.log
12303
12292
12290 本文名稱:Linux系統(tǒng)查看軟件資源損耗
網(wǎng)頁地址:http://fisionsoft.com.cn/article/ccecpdh.html


咨詢
建站咨詢
