原创:扣钉日记(微信大众号ID:codelogs),欢迎共享,非大众号转载保留此声明。

简介

现如今,有两种常见的软件资源简直成了Java后端程序的标配,即线程池与衔接池,但这些池化资源十分的重要,一旦不行用了,就会导致程序阻塞、功能低下,所以有时咱们需求看看它们的使用状况,以判别这儿是否是瓶颈。

检查活泼线程数

在Linux上,经过top -H -p 1指令,能够检查java进程的线程状况,其间1是java进程号,如下:

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

如上,能够看到线程的称号、CPU使用率等,其间http-nio-8080-e便是Tomcat线程池中的线程,tomcat线程全名类似于http-nio-8080-exec-20,因为Linux中线程称号有长度约束,所以被切断了。

注:jdk8的话,需求jdk8u222以上版别,才能在top中看到线程称号。

咱们数一下http-nio-8080-e线程的数量,发现它有20个,正好对应上了在springboot中的线程装备。

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

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

经过检查man文档,我发现top指令有一个-i选项,描述如下:

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

意思便是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

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

能够看到,20个线程的线程池中,在1秒内只有4个线程是活泼的,线程池中线程数量是足够的。

这个指令脚本就不展开解释了,也不杂乱,有linux指令根底的将指令顺次拆开执行,应该能Get到脚本逻辑,没学过linux指令的话,就直接拿去用吧

检查活泼衔接数

在Linux上,使用ss -natp|grep pid=1能够检查1号进程的TCP衔接,如下:

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

比如若redis数据库端口是6379的话,那么可这样检查redis衔接池中衔接数量,如下:

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

可见当前有20个redis网络衔接,那同样的,其间有多少个是活泼的呢?

经过检查man文档,发现ss中也有一个-i选项,如下:

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

能够发现,添加-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

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

上面其实便是经过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来说,值得好好研究研究