接口请求时间太长,jstack观察锁持有情况

场景:在工程A中调用工程B的接口完成一些逻辑,A中每调用一个接口打印一条信息,观察到当接口连续调用一段时间后,会卡住一会,然后又继续执行。老大给出建议查看下jstack dump堆栈信息,查看阻塞和耗时长的操作。

  1. 在命令行终端,输入jps 查看当前java进程id;
    在这里插入图片描述
  2. jstack –l PID >>log.txt, PID指进程Id,将堆栈信息输出到当前目录下的log.txt文件中。
    在这里插入图片描述
    对其中参数解释:
    -l long listings,会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况
    -m mixed mode,不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法)
  3. 堆栈的详细分析,参考jstack dump日志文件详细分析

通过上述的分析,发现项目中的日志打印中存在同步程序,导致所有的接口都在等待日志打印;另一个问题是身份验证太慢。

解决:

  1. 日志级别调成error,减少日志打印占用的资源,p6spy关闭减少资源占用,打印日志非常耗费资源,日志中的同步更是让接口处于等待状态。
  2. tokenID认证使用本地的认证,或者将认证去掉,原来使用外网地址的认证,通过Apache访问认证接口,Apache默认长连接,会限制连接的数量,等待连接释放,使程序阻塞。

除此之外,能够增加接口处理速度的设置:

  1. 设置MySQL数据库,my.ini
max_allowed_packet = 64M
innodb_buffer_pool_size =20G   --也不用设置过大,4096M也还可以
  1. 设置数据库的连接数,增加初始连接数,最大连接数:
#定义初始连接数  
initialSize=10  
#连接池处于活动状态的数据库连接的最大数目,0表示不限制,表示最大并发
maxActive=200 
#连接池处于空闲状态的数据库连接的最大数目,取非正整数表示不受限制,超过此数值时多余的空闲连接将会被释放
maxIdle=20
#连接池处于空闲状态的数据库连接的最小数目,低于此数值将会创建所欠缺的连接,设0无限制  
minIdle=10
#连接池中连接用完时,新的请求的等待时间(即等待别的连接空闲),超时返回异常,毫秒  
maxWait=60000
  1. 修改Tomcat,server.xml
<Connector  
	executor="tomcatThreadPool"
	port="8280"  
	protocol="org.apache.coyote.http11.Http11Nio2Protocol" 
	enableLookups="false"  
	acceptCount="1500"               
	disableUploadTimeout="false"      
	connectionTimeout="180000" 		
	connectionUploadTimeout="300000"
	maxConnections="10000"              
	URIEncoding="UTF-8"                           
	redirectPort="8443"               
	compression="on"              
	compressionMinSize="1024" 
	useSendfile="false"
	keepAliveTimeout="60000"
	tcpNoDelay="true"
	noCompressionUserAgents="gozilla, traviata" 
	maxPostSize="-1"  
    maxParameterCount="-1"
   compressibleMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/javascript "   />
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>

将tomcat的线程池最大连接数增加改成maxThreads=200;
http的长连接超时时间keepAliveTimeout设置为keepAliveTimeout="2000"ms,因为我只是调用一下,不需要保持长连接获取数据,无用连接快速释放就可以了。

jstack生成的Thread Dump日志.docx 系统线程状态 (Native Thread Status) 系统线程有如下状态: deadlock 死线程,一般指多个线程调用期间进入了相互资源占用,导致一直等待无法释放的情况。 runnable 一般指该线程正在执行状态中,该线程占用了资源,正在处理某个操作,如通过SQL语句查询数据库、对某个文件进行写入等。 blocked 线程正处于阻塞状态,指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。 waiting on condition 线程正处于等待资源或等待某个条件的发生,具体的原因需要结合下面堆栈信息进行分析。 (1)如果堆栈信息明确是应用代码,则证明该线程正在等待资源,一般是大量读取某种资源且该资源采用了资源情况下,线程进入等待状态,等待资源的读取,或者正在等待其他线程的执行等。 (2)如果发现有大量的线程都正处于这种状态,并且堆栈信息中得知正等待网络读写,这是因为网络阻塞导致线程无法执行,很有可能是一个网络瓶颈的征兆: 网络非常繁忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写; 网络可能是空闲的,但由于路由或防火墙等原因,导致包无法正常到达; 所以一定要结合系统的一些性能观察工具进行综合分析,比如netstat统计单位时间的发送包的数量,看是否很明显超过了所在网络带宽的限制;观察CPU的利用率,看系统态的CPU时间是否明显大于用户态的CPU时间。这些都指向由于网络带宽所限导致的网络瓶颈。 (3)还有一种常见的情况是该线程在 sleep,等待 sleep 的时间到了,将被唤醒。 waiting for monitor entry 或 in Object.wait() Moniter 是Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者class的,每个对象都有,也仅有一个 Monitor。 从上图可以看出,每个Monitor在某个时刻只能被一个线程拥有,该线程就是 "Active Thread",而其他线程都是 "Waiting Thread",分别在两个队列 "Entry Set"和"Waint Set"里面等待。其中在 "Entry Set" 中等待的线程状态是 waiting for monitor entry,在 "Wait Set" 中等待的线程状态是 in Object.wait()。 (1)"Entry Set"里面的线程。 我们称被 synchronized 保护起来的代码段为临界区,对应的代码如下: synchronized(obj){} 当一个线程申请进入临界区时,它就进入了 "Entry Set" 队列中,这时候有两种可能性: 该Monitor不被其他线程拥有,"Entry Set"里面也没有其他等待的线程。本线程即成为相应类或者对象的Monitor的Owner,执行临界区里面的代码;此时在Thread Dump中显示线程处于 "Runnable" 状态。 该Monitor被其他线程拥有,本线程在 "Entry Set" 队列中等待。此时在Thread Dump中显示线程处于 "waiting for monity entry" 状态。 临界区的设置是为了保证其内部的代码执行的原子性和完整性,但因为临界区在任何时间只允许线程串行通过,这和我们使用多线程的初衷是相反的。如果在多线程程序中大量使用synchronized,或者不适当的使用它,会造成大量线程在临界区的入口等待,造成系统的性能大幅下降。如果在Thread Dump中发现这个情况,应该审视源码并对其进行改进。 (2)"Wait Set"里面的线程 当线程获得了Monitor,进入了临界区之后,如果发现线程继续运行的条件没有满足,它则调用对象(通常是被synchronized的对象)的wait()方法,放弃Monitor,进入 "Wait Set"队列。只有当别的线程在该对象上调用了 notify()或者notifyAll()方法,"Wait Set"队列中的线程才得到机会去竞争,但是只有一个线程获得对象的Monitor,恢复到运行态。"Wait Set"中的线程在Thread Dump中显示的状态为 in Object.wait()。通常来说, 通常来说,当CPU很忙的时候关注 Runnable 状态的线程,反之则关注 waiting for monitor entry 状态的线程。 JVM线程运行状态 (JVM Thread Status)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值