在Linux上查看活跃线程数与连接数

文章介绍了如何在Linux环境下使用top和ss命令监控Java应用的线程池和连接池活跃度,包括查看线程数和活跃线程,以及连接数和活跃连接。此外,还提到了使用arthas工具获取更详细的线程池和连接池信息,如SpringBoot中Tomcat和Druid的数据源状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

现如今,有两种常见的软件资源几乎成了Java后端程序的标配,即线程池与连接池,但这些池化资源非常的重要,一旦不够用了,就会导致程序阻塞、性能低下,所以有时我们需要看看它们的使用情况,以判断这里是否是瓶颈。

查看活跃线程数

在Linux上,通过top -H -p 1命令,可以查看java进程的线程情况,其中1是java进程号,如下:
image_2023-03-04_20230304140014
如上,可以看到线程的名称、CPU使用率等,其中http-nio-8080-e就是Tomcat线程池中的线程,tomcat线程全名类似于http-nio-8080-exec-20,由于Linux中线程名称有长度限制,所以被截断了。

注:jdk8的话,需要jdk8u222以上版本,才能在top中看到线程名称。

我们数一下http-nio-8080-e线程的数量,发现它有20个,正好对应上了在springboot中的线程配置。
image_2023-03-04_20230304133328

这样能通过top得到线程池的线程数量了,但如何了解线程池的使用情况,即活跃线程有多少个呢?

经过查看man文档,我发现top命令有一个-i选项,描述如下:
image_2023-03-04_20230304134557
意思就是i是一个开关选项,默认会显示全部线程,而打开此选项之后,就只显示活跃线程了!

所以,只需要利用-i选项,再配合sed/awk/uniq等文本处理命令,即可以统计出活跃线程数了,如下:

$ top -H -i -b -d 1 -n2 -p 1 | awk -v RS= 'END{print $0}' | awk '$1 ~ /[0-9]+/{print $12}' | sed -E 's/[0-9]+/n/g' | sort | uniq -c

image_2023-03-04_20230304141731
可以看到,20个线程的线程池中,在1秒内只有4个线程是活跃的,线程池中线程数量是足够的。

这个命令脚本就不展开解释了,也不复杂,有linux命令基础的将命令依次拆开执行,应该能Get到脚本逻辑,没学过linux命令的话,就直接拿去用吧😅

查看活跃连接数

在Linux上,使用ss -natp|grep pid=1可以查看1号进程的TCP连接,如下:
image_2023-03-04_20230304144050
比如若redis数据库端口是6379的话,那么可这样查看redis连接池中连接数量,如下:

$ ss -natp | grep pid=1 | awk '$5~/:6379$/' | wc -l
20

可见当前有20个redis网络连接,那同样的,其中有多少个是活跃的呢?

经过查看man文档,发现ss中也有一个-i选项,如下:
image_2023-03-04_20230304145652
可以发现,添加-i选项后,ss会输出tcp连接中的一些额外信息,其中lastsnd表示最后一次发送包到当前所经历的毫秒数,lastrcv表示最后一次接收包到当前所经历的毫秒数。

有了这个信息后,就可以通过awk过滤出lastsnd或lastrcv小于1000的tcp连接,这些连接即是1秒内活跃过的连接了,因此我又编写了如下命令脚本。

$ ss -natpi | sed '1!{N;s/\n//;}' | grep pid=1 | awk -v t=1000 'match($0,/lastsnd:(\w+) lastrcv:(\w+)/,a) && (a[1]<t || a[2]<t) && match($4,/(.+):(\w+)$/,s) && match($5,/(.+):(\w+)$/,d) && s[2]>=32768{print d[2]}' |sort |uniq -c |sort -nk2
      8 80
      3 3306
      7 3307
      6 6379
      1 7916

如上,可以看到各连出端口的活跃连接情况,其中80是http连接池端口,3306与3307是MySQL主从库的连接池端口,6379是redis连接池的端口。

这是java应用主动连出连接的活跃情况,那调用方连入java应用的呢?

其实只需要稍微调整一下awk脚本即可,如下:

  1. s[2]>=32768调整为s[2]<32768,其中32768是Linux默认的临时端口号的分界线,可通过sysctl net.ipv4.ip_local_port_range查询,本地端口号大于这个值,代表是连出连接.
  2. print d[2]调整为print s[2],和上面条件联合起来,输出的就是本地监听端口了.

调整后,效果如下:

$ ss -natpi | sed '1!{N;s/\n//;}' | grep pid=1 | awk -v t=1000 'match($0,/lastsnd:(\w+) lastrcv:(\w+)/,a) && (a[1]<t || a[2]<t) && match($4,/(.+):(\w+)$/,s) && match($5,/(.+):(\w+)$/,d) && s[2]<32768{print s[2]}' |sort |uniq -c |sort -nk2
     8 8080

可以发现,我们服务的8080端口,1秒内活跃过的连接数是8个。

注:只有当调用方也使用连接池时,这种方法获取到的活跃连接数才是准确的,若调用方使用短链接的话,则不准确。

arthas查看活跃线程数与连接数

通过上面的方法,已经可以查看活跃线程数与连接数了,但有些情况下,会丧失一些细节,如下:

  1. top中的线程名会截断,如果不同线程池的线程名前16字符一样,则在top中无法区分。
  2. ss中是通过端口来区分线程池的,但http服务的端口号基本都是80或443,所以不同域名的http服务的连接池无法区分。

若需要分辩这些细节,还是要深入到jvm里面来,而arthas就是一个不错的工具,它的vmtool命令能够获取指定类型的Java对象,并从Java对象中获取信息。

以springboot为例,获取内置tomcat线程池的活跃情况,如下:

# --action getInstances:表示获取对象实例
# --classLoaderClass:指定类加载器
# --className:指定要获取哪个类的实例
# --express:指定ognl表达式,用来从对象上获取信息
[arthas@1]$ vmtool --action getInstances --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader --className org.apache.tomcat.util.threads.ThreadPoolExecutor  --express 'instances.{ #{"ActiveCount":getActiveCount(),"LargestPoolSize":getLargestPoolSize(),"CorePoolSize":getCorePoolSize(),"MaximumPoolSize":getMaximumPoolSize(),"QueueSize":getQueue().size(),"ThreadName":getThreadFactory().namePrefix }}' -x 2

image_2023-03-04_20230304155857
上面其实就是通过vmtool工具,获取到了tomcat的线程池对象,然后调用线程池的getActiveCount()等方法,获取到了活跃线程数🙄

要获取连接池的活跃情况,也一并呈上吧,如下:

# 获取druid连接池的使用情况
[arthas@1]$ vmtool --action getInstances --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader --className com.alibaba.druid.pool.DruidDataSource  --express 'instances.{ #{"url":#this.getUrl().split("\\?")[0], "username":#this.getUsername(),"PoolingCount":#this.getPoolingCount(),"ActiveCount":#this.getActiveCount(),"MaxActive":#this.getMaxActive(),"WaitThreadCount":#this.getWaitThreadCount(),"MaxWaitThreadCount":#this.getMaxWaitThreadCount()} }' -x 2

# 获取httpclient连接池的使用情况
[arthas@1]$ vmtool --action getInstances --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader --className org.apache.http.impl.conn.PoolingHttpClientConnectionManager --express 'instances.{ #pool=#this.pool.routeToPool.values() }' -x2

可以看到,arthas真的很方便实用,对于Java Boy来说,值得好好研究研究👍👍👍

Tomcat连接池是**从Tomcat 7版本开始引入的一个高性能的数据库连接池**。下面将具体介绍查看Tomcat连接池的方法: 1. **通过配置文件查看:** - Tomcat的数据源可以在`context.xml`或`server.xml`文件中进行配置,通过查看这些文件可以获得连接池的设置信息。 - 在虚拟主机的配置文件中,也可能对连接池进行了特定的设置,这同样需要检查以获取完整的配置信息。 2. **通过管理页面查看:** - 如果启用了Tomcat的管理页面,可以通过访问`http://localhost:8080/manager/status`来查看服务器的状态,包括连接池信息。 - Tomcat管理页面提供的连接池信息可能包括:当前活跃连接数、空闲的连接数等。 3. **通过JMX查看:** - Tomcat 提供了一个JMX(Java Management Extensions)接口,可以远程监控和管理Tomcat的各项参数,包括连接池状态。 - 使用支持JMX的工具如JConsole或VisualVM等,可以连接到Tomcat的JMX接口,实时查看和调整连接池的配置。 4. **通过日志文件查看:** - Tomcat的日志文件(通常是`catalina.out`)可能会记录连接池相关的信息,例如连接的打开和关闭。 - 通过分析日志文件,可以了解连接池在实际运行中的行为模式及可能存在的问题。 5. **通过命令行工具查看:** - 可以使用操作系统提供的命令行工具,如Linux的`ps`或`netstat`命令,来查看Tomcat进程的网络连接情况。 - 这类工具虽然不直接显示连接池的状态,但可以间接反映连接池的使用情况。 6. **第三方监控工具:** - 市面上有许多第三方的应用服务器监控工具,如New Relic、AppDynamics等,它们提供了更全面的监控能力,包括对连接池的监控。 - 这些工具通常提供图形化界面,帮助用户更直观地理解连接池的使用情况和性能指标。 7. **编写简单的测试程序:** - 可以通过编写简单的Java程序,使用JNDI查找数据源,并打印出连接池的相关属性和当前状态。 - 这种方法可以灵活地获取和展示连接池的信息,便于开发人员进行调试和分析。 此外,在了解以上内容后,以下还有一些其他建议: - 在使用连接池时,需要注意合理设置连接池的大小和其他参数,以适应不同的应用需求和负载情况。 - 定期检查连接池的健康状态,例如是否有泄漏的连接或者连接是否得到有效的复用。 - 考虑使用连接池自带的监控功能或集成第三方监控工具,以便更好地监控和管理连接池。 总的来说,查看Tomcat连接池的方法主要包括通过配置文件、管理页面、JMX、日志文件、命令行工具、第三方监控工具以及编写简单的测试程序等方式。每种方法都有其特点和适用场景,用户可以根据自己的需求和环境选择合适的方法来进行查看。同时,合理配置和维护连接池对于保证应用的稳定性和性能是非常重要的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值