Linux Threads

Linux下如何监控每个微服务的线程数

1. 背景

现在的 CPU 基本都是由多个核心组成,加上我们现在的微服务,更加充分利用多核处理器的强大功能,我们的微服务都会开启多线程进行各种任务处理,这也导致我们遇到问题的时候很难定位。例如我们线上排查问题,可能需要有关特定进程下使用多少线程的信息,但如果没有一些强大的APM工具,我发现身边一些同事其实还不太了解如何进行线程监控。在本文中,我们将向您介绍可用于检查和监控线程计数数据的所有工具和命令。

2. 查看线程数

接下来会演示下,在Linux服务器查看线程的几种方式。

2.1 使用ps命令

有时候我们在线上定位问题,想知道服务器上每个服务到底开启了多少条线程,从而定位哪个服务有滥用线程。指令 ps显示有关计算机上当前活动进程的信息。组合选项-e和-f是一种标准方法,我们可以使用它以格式化的方式获取有关每个进程的信息。同样,我们可以附加-L选项让ps报告额外的线程信息:


Last login: Mon Mar 20 14:45:58 2023 from 172.17.0.1
[root@ca51ce5b1371 ~]# ps -eLf
UID          PID    PPID     LWP  C NLWP STIME TTY          TIME CMD
root           1       0       1  0    1 14:45 ?        00:00:00 /usr/sbin/init
root          28       1      28  0    1 14:45 ?        00:00:00 /usr/lib/systemd/systemd-journald
root          29       1      29  0    1 14:45 ?        00:00:00 /usr/lib/systemd/systemd-udevd
dbus          78       1      78  0    1 14:45 ?        00:00:00 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
root          79       1      79  0    1 14:45 ?        00:00:00 /usr/sbin/sshd -D -oCiphers=aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr,aes256-cbc,aes128-gcm@openssh.com,aes128-ctr,aes128-cbc -oMACs=hmac-sha2-256-etm@openssh.com,hmac-sha1-etm@openssh.
root          85      79      85  0    1 14:45 ?        00:00:00 sshd: root [priv]
root          87      85      87  0    1 14:45 ?        00:00:00 sshd: root@pts/1
root          88      87      88  0    1 14:45 pts/1    00:00:00 -bash
root          95      87      95  0    1 14:45 ?        00:00:00 /usr/libexec/openssh/sftp-server
root         119      88     119  0    1 14:47 pts/1    00:00:00 top
root         120      79     120  0    1 14:49 ?        00:00:00 sshd: root [priv]
root         122     120     122  0    1 14:49 ?        00:00:00 sshd: root@pts/2
root         123     122     123  0    1 14:49 pts/2    00:00:00 -bash
root         126     122     126  0    1 14:49 ?        00:00:00 /usr/libexec/openssh/sftp-server
root         153     123     153  0    1 14:50 pts/2    00:00:00 ps -eLf
  • 「PID」: 唯一进程标识
  • 「PPID」: 父进程标识
  • 「LWP」: 进程中的唯一线程标识
  • 「NLWP」: (轻量级进程数)列指示附加到该特定进程的线程数

例如,当我们查看一个 NLWP 值大于 1 的进程时,我们可以看到它之后的相应行数具有相同的 PID 值。但是,如果我们不想接收每个进程的所有这些混乱信息,而我们只想搜索特定进程的线程数,我们可以使用带有 -o选项的ps


[root@ca51ce5b1371 ~]# ps -o nlwp 126
NLWP
   1

这里的nlwp 是我们上面获取线程数信息的列,126是一个进程的PID。正如我们所见,这个进程同时运行了1个线程。除此之外,我们还可以通过使用thcount而不是nlwp来获得相同的结果:


[root@ca51ce5b1371 ~]# ps -o thcount 126
THCNT
    1

还可以通过以下组合命令查询服务器上的所有线程数:ps -eo nlwp | tail -n +2 | awk '{ num_threads += $1 } END { print num_threads }'


[root@ca51ce5b1371 ~]# ps -eo nlwp | tail -n +2 | awk '{ num_threads += $1 } END { print num_threads }'
17

这里服务器的总线程数是17

2.2 检查/proc目录

以类似的方式,我们可以检查/proc 目录中的线程计数数据。/proc是一个虚拟文件系统,其中包含有关进程的各种信息


[root@ca51ce5b1371 ~]# ls /proc/126/task/
126

正如我们在上面清楚看到的,PID 为 126 的进程包含1个线程(因为我这里的进程只有一条线程,所以这里看到的线程ID和进程 ID一样)。事实上,这个结果与我们之前使用命令ps得到的结果相符。此外,我们可以验证这些目录名称与LWP 列下的相应结果完全相同。


[root@ca51ce5b1371 ~]# cat /proc/126/status | grep Threads
Threads:        1

3 实时监控线程数

3.1 ps命令与watch结合

当我们使用watch 工具 结合上一节提到的命令,我们可以实时监控任意进程的线程状态。我们还可以使用-n选项以秒为单位指定更新间隔。


[root@ca51ce5b1371 ~]# watch -n 1 ps -o thcount 126
Every 1.0s: ps -o thcount 126                                                                                                                                                                                                             ca51ce5b1371: Mon Mar 20 16:52:36 2023

THCNT
    1

请注意,以上结果每秒刷新一次。watch每秒运行命令 ps -o thcount 126 并将输出显示回控制台。

3.2 使用top命令

top 是一个内置程序,可报告 CPU 使用率内存状态等系统信息。我们可以使用此工具来获取每个进程的线程数信息,但默认情况下它是禁用的。因此,我们必须手动调整该工具。首先,我们需要进入实用程序:


top - 16:54:58 up  2:10,  2 users,  load average: 0.03, 0.03, 0.00
Tasks:  15 total,   1 running,  14 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.1 us,  0.2 sy,  0.0 ni, 99.8 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   7851.4 total,   6434.9 free,    329.5 used,   1087.0 buff/cache
MiB Swap:   1024.0 total,   1024.0 free,      0.0 used.   6983.8 avail Mem 

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                                                                                                                                                                                  
      1 root      20   0   21456   9212   7048 S   0.0   0.1   0:00.28 systemd                                                                                                                                                                                                  
     28 root      20   0   26528   7976   7104 S   0.0   0.1   0:00.04 systemd-journal                                                                                                                                                                                          
     29 root      20   0   30576   7316   5684 S   0.0   0.1   0:00.05 systemd-udevd                                                                                                                                                                                            
     78 dbus      20   0   10084   3364   2952 S   0.0   0.0   0:00.00 dbus-daemon                                                                                                                                                                                              
     79 root      20   0   14724   6356   5484 S   0.0   0.1   0:00.00 sshd                                                                                                                                                                                                     
     85 root      20   0   19728   8792   7568 S   0.0   0.1   0:00.02 sshd                                                                                                                                                                                                     
     87 root      20   0   19728   5240   4008 S   0.0   0.1   0:01.38 sshd                                                                                                                                                                                                     
     88 root      20   0    6720   3292   2816 S   0.0   0.0   0:00.00 bash                                                                                                                                                                                                     
     95 root      20   0    7080   4192   3676 S   0.0   0.1   0:00.00 sftp-server                                                                                                                                                                                              
    119 root      20   0   12068   3664   3100 S   0.0   0.0   0:05.92 top                                                                                                                                                                                                      
    120 root      20   0   19728   9008   7788 S   0.0   0.1   0:00.03 sshd                                                                                                                                                                                                     
    122 root      20   0   19728   5256   4036 S   0.0   0.1   0:00.12 sshd                                                                                                                                                                                                     
    123 root      20   0    6852   3224   2740 S   0.0   0.0   0:00.04 bash                                                                                                                                                                                                     
    126 root      20   0    7080   4292   3776 S   0.0   0.1   0:00.00 sftp-server                                                                                                                                                                                              
    522 root      20   0   12068   3732   3168 R   0.0   0.0   0:00.00 top    

默认情况下,我们是没办法看到线程数这一列,这也是很多初级开发人员误以为top命令只显示这一些内容。实际上我们如果按下f键盘,就可以进入top 的指标列表。按上下可以自由选择你要显示的指标,在这里按 d可以选择nTH 字段去显示线程数指标,然后按q返回主界面:


Fields Management for window 1:Def, whose current sort field is %CPU
   Navigate with Up/Dn, Right selects for move then  or Left commits,
   'd' or  toggles display, 's' sets sort.  Use 'q' or  to end!

* PID     = Process Id             SUPGRPS = Supp Groups Names   
* USER    = Effective User Name    TGID    = Thread Group Id     
* PR      = Priority               OOMa    = OOMEM Adjustment    
* NI      = Nice Value             OOMs    = OOMEM Score current 
* VIRT    = Virtual Image (KiB)    ENVIRON = Environment vars    
* RES     = Resident Size (KiB)    vMj     = Major Faults delta  
* SHR     = Shared Memory (KiB)    vMn     = Minor Faults delta  
* S       = Process Status         USED    = Res+Swap Size (KiB) 
* %CPU    = CPU Usage              nsIPC   = IPC namespace Inode 
* %MEM    = Memory Usage (RES)     nsMNT   = MNT namespace Inode 
* TIME+   = CPU Time, hundredths   nsNET   = NET namespace Inode 
* COMMAND = Command Name/Line      nsPID   = PID namespace Inode 
  PPID    = Parent Process pid     nsUSER  = USER namespace Inode
  UID     = Effective User Id      nsUTS   = UTS namespace Inode 
  RUID    = Real User Id           LXC     = LXC container name  
  RUSER   = Real User Name         RSan    = RES Anonymous (KiB) 
  SUID    = Saved User Id          RSfd    = RES File-based (KiB)
  SUSER   = Saved User Name        RSlk    = RES Locked (KiB)    
  GID     = Group Id               RSsh    = RES Shared (KiB)    
  GROUP   = Group Name             CGNAME  = Control Group name  
  PGRP    = Process Group Id       NU      = Last Used NUMA node 
  TTY     = Controlling Tty     
  TPGID   = Tty Process Grp Id  
  SID     = Session Id          
* nTH     = Number of Threads   
  P       = Last Used Cpu (SMP) 
  TIME    = CPU Time            
  SWAP    = Swapped Size (KiB)  
  CODE    = Code Size (KiB)     
  DATA    = Data+Stack (KiB)    
  nMaj    = Major Page Faults   
  nMin    = Minor Page Faults   
  nDRT    = Dirty Pages Count   
  WCHAN   = Sleeping in Function
  Flags   = Task Flags 
  CGROUPS = Control Groups      
  SUPGIDS = Supp Groups IDs     

选择之后的界面会多了nTH这一列,这样我们就可以看到每个进程下到底开启了多少线程,有没有微服务程序滥用线程:


top - 17:00:41 up  2:15,  2 users,  load average: 0.08, 0.03, 0.01
Tasks:  15 total,   1 running,  14 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.1 us,  0.1 sy,  0.0 ni, 99.8 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   7851.4 total,   6429.4 free,    335.0 used,   1087.0 buff/cache
MiB Swap:   1024.0 total,   1024.0 free,      0.0 used.   6978.4 avail Mem 

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                                                               nTH 
      1 root      20   0   21456   9212   7048 S   0.0   0.1   0:00.28 systemd                                                                                 1 
     28 root      20   0   26528   7976   7104 S   0.0   0.1   0:00.04 systemd-journal                                                                         1 
     29 root      20   0   30576   7316   5684 S   0.0   0.1   0:00.05 systemd-udevd                                                                           1 
     78 dbus      20   0   10084   3364   2952 S   0.0   0.0   0:00.00 dbus-daemon                                                                             1 
     79 root      20   0   14724   6356   5484 S   0.0   0.1   0:00.00 sshd                                                                                    1 
     85 root      20   0   19728   8792   7568 S   0.0   0.1   0:00.02 sshd                                                                                    1 
     87 root      20   0   19728   5240   4008 S   0.0   0.1   0:01.45 sshd                                                                                    1 
     88 root      20   0    6720   3292   2816 S   0.0   0.0   0:00.00 bash                                                                                    1 
     95 root      20   0    7080   4192   3676 S   0.0   0.1   0:00.00 sftp-server                                                                             1 
    119 root      20   0   12068   3664   3100 S   0.0   0.0   0:06.19 top                                                                                     1 
    120 root      20   0   19728   9008   7788 S   0.0   0.1   0:00.03 sshd                                                                                    1 
    122 root      20   0   19728   5256   4036 S   0.0   0.1   0:00.16 sshd                                                                                    1 
    123 root      20   0    6852   3224   2740 S   0.0   0.0   0:00.04 bash                                                                                    1 
    126 root      20   0    7080   4292   3776 S   0.0   0.1   0:00.00 sftp-server                                                                             1 
    522 root      20   0   12068   3732   3168 R   0.0   0.0   0:00.14 top