tomcat 越来越慢解决思路(tomcat反应慢)
oracle如何解决锁表问题
当我们出现锁表时,新的修改事务发生时,会报下面的错误:
record is locked by another user;
或是出现某一个修改业务长期处于卡死状态,可以考虑是出现锁表的可能性。可以通过数据字典v$session、v$locked_object等进行关联查询出正处于一直在执行的SQL的sessionID和对应的SQL语句。代码如下:
查看锁表进程SQL语句
1:select sess.sid,sess.serial#, lo.oracle_username,lo.os_user_name, ao.object_name, lo.locked_mode from v$locked_object lo,dba_objects ao, v$session sesswhere ao.object_id = lo.object_id and lo.session_id = sess.sid;
2:select * from v$session t1, v$locked_object t2 where t1.sid = t2.SESSION_ID;
然后,通过查询出来锁表的SID和serial#对对应的session进行kill(杀死)。代码如下:
alter system kill session 'SID,serial#';
案例:
1、对学生信息表(stuinfo)中学生“SC201801006”进行年龄的修改,但是忘记提交,如下:
2、然后,通过另外一个窗口,对其进行update操作,修改其年级为“2019”,模拟锁表情况,代码如下:
3、发现,由于第一个窗口为提交数据,导致update操作一直处于等待,这时我们通过锁表语句查询数据库的是否存在锁表情况,如下:
4、这时可以通过 kill语句杀死第一个未提交的会话,或者主动对第一个窗口的修改语句进行提交,即可解除锁表情况。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Tomcat假死的原因及解决方案
服务器配置:linux+tomcat
现象:Linux服务器没有崩,在浏览器中访问页面,出现无法访问的情况,没有报4xx或5xx错误(假死),并且重启tomcat后,恢复正常。
原因:tomcat默认最大连接数(线程数)200个,默认每一个连接的生命周期2小时(7200秒),tomcat使用http 1.1协议,而http1.1默认是长连接。tomcat接受处理完请求后,socket没有主动关闭,因此如果在2小时内,请求数超过200个,服务器就会出现上述假死现象。
解决方案1:及时断开socket
解决方案2:修改tomcat配置文件,修改最大连接数(增大)
修改server.xml配置文件,Connector节点中增加acceptCount和maxThreads这两个属性的值,并且使acceptCount大于等于maxThreads:
connectionTimeout="20000"
???????????redirectPort="8443"?acceptCount="500"?maxThreads="400"?/>
解决方案3:修改linux的TCP超时时间(socket生命周期)限制
vi /etc/sysctl .conf
# Decrease the time default value for tcp_fin_timeout connection
net.ipv4.tcp_fin_timeout = 30
# Decrease the time default value for tcp_keepalive_time connection
net.ipv4.tcp_keepalive_time = 1800
# 探测次数
net.ipv4.tcp_keepalive_probes=2
# 探测间隔秒数
net.ipv4.tcp_keepalive_intvl=2
编辑完 /etc/sysctl .conf,要重启network 才会生效
[root@temp /] # /etc/rc.d/init.d/n
//////////////////////////////////////////////////////////////////////////////////////////////////////////
2.2检查tomcat 的网络情况
分析业务配置的tomcat访问日志xxxx.log上是否有日志访问记录,经过查询该台tomcat应用日志完全没有任何访问记录,由于我们的部署是本机的nginx转到本机的tomcat应用,所以可以排除不是网络问题。到此基本可以断定网络没有问题,tomcat 本身出现了假死的情况。在tomcat的日志里有报过OutOfMemoryError的异常,所以可以肯定tomcat假死的原因是OOM
3 分析JVM内存溢出
3.1为什么会发生内存泄漏
在我们学习Java的时候就知道它最为方便的地方就是我们不需要管理内存的分配和释放,一切由JVM自己来进行处理,当Java对象不再被应用时,等到堆内存不够用时JVM会进行GC处理,清除这些对象占用的堆内存空间,但是如果对象一直被应用,那么JVM是无法对其进行GC处理的,那么我们创建新的对象时,JVM就没有办法从堆中获取足够的内存分配给此对象,这时就会导致OOM。我们出现OOM原因,一般都是因为我们不断地往容器里存放对象,然而容器没有相应的大小限制或清除机制,这样就容易导致OOM。
3.2快速定位问题
当我们的应用服务器占用了过多内存的时候,我们怎么样才能快速地定位问题呢?要想快速定位问题,首先我们必须获取服务器JVM某时刻的内存快照。Jdk里面提供了很多相应的命令比如:jstack,jstat,jmap,jps等等. 在出现问题后我们应该快速保留现场。
3.2.1 jstack
可以观察到jvm中当前所有线程的运行情况和线程当前状态.
sudo jstack -F 进程ID
输出内容如下:
从上面的图我们可以看到tomcat进程里面没有死锁的情况,而且每个线程都处理等待的状态。这个时候我们可以telnet命令连上tomcat的端口查看tomcat进程是否有任务回应。这时发现tomcat没有任何回应可以证明tomcat应用已没有响应处理假死状态。
3.2.2 jstat
这是jdk命令中比较重要,也是相当实用的一个命令,可以观察到classloader,compiler,gc相关信息
具体参数如下:
-class:统计class loader行为信息
-compile:统计编译行为信息
-gc:统计jdk gc是heap信息
-gccapacity:统计不同的generations(包括新生区,老年区,permanent区)相应的heap容量情况
-gccause:统计gc的情况,(同-gcutil)和引起gc的事件
-gcnew:统计gc时,新生代的情况
-gcnewcapacity:统计gc时,新生代heap容量
-gcold:统计gc时,老年区的情况
-gcoldcapacity:统计gc时,老年区heap容量
-gcpermcapacity:统计gc时,permanent区heap容量
-gcutil:统计gc时,heap情况
-printcompilation:不知道干什么的,一直没用过。
一般比较常用的几个参数是:
sudo jstat -class 2083 1000 10 (每隔1秒监控一次,一共做10次)
查看当时的head情况
sudo jstat -gcutil 20683 2000
注:该图不是出错截取
出现时候截取的数据是gc已经完全没有处理了,因为没有加上full gc的日志所以不确定JVMGC 时间过长,导致应用暂停.
3.2.3获取内存快照
Jdk自带的jmap可以获取内在某一时刻的快照
命令:jmap -dump:format=b,file=heap.bin
file:保存路径及文件名
pid:进程编号(windows通过任务管理器查看,linux通过ps aux查看)
dump文件可以通过MemoryAnalyzer分析查看,网址:
http://www.eclipse.org/mat/,可以查看dump时对象数量,内存占用,线程情况等。
从上面的图可以看得出来对象没有内存溢出。
从上图我们可以明确的看出此项目的HashMap内存使用率比较高,因为我们的系统都是返回Map的数据结构所以占用比较高的内存是正常情况。
3.2.4观察运行中的jvm物理内存的占用情况
观察运行中的jvm物理内存的占用情况。我们也可以用jmap命令
参数如下:-heap:打印jvm heap的情况
-histo:打印jvm heap的直方图。其输出信息包括类名,对象数量,对象占用大小。
-histo:live:同上,但是只答应存活对象的情况
-permstat:打印permanent generation heap情况
命令使用:
jmap -heap 2083
可以观察到New Generation(Eden Space,From Space,To Space),tenured generation,Perm Generation的内存使用情况
输出内容:
上图为tomcat应用出错前JVM的配置信息,可以明确的看到当时的信息:
MaxHeapSize堆内存大小为:3500M
MaxNewSize新生代内存大小:512M
PermSize永久代内存大小:192M
NewRatio设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为2,则年轻代与年老代所占比值为1:2,年轻代占整个堆栈的1/3
SurvivorRatio设置年轻代中Eden区与Survivor区的大小比值。设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10
在New Generation中,有一个叫Eden的空间,主要是用来存放新生的对象,还有两个SurvivorSpaces(from,to), 它们用来存放每次垃圾回收后存活下来的对象。在Old Generation中,主要存放应用程序中生命周期长的内存对象,还有个Permanent Generation,主要用来放JVM自己的反射对象,比如类对象和方法对象等。
从上面的图可以看出来JVM的新生代设置太小,可以看出应用的新生代区完全占满了,无法再往新生代区增加新的对象此时的这些对象都处于活跃状态,所以不会被GC处理,但是tomcat应用还在继续产生新的对象,这样就会导致OOM的发生,这就是导致tomcat假死的原因.
4 Tomcat假死其它情况
以下是网上资料说的tomcat假的情况:
1、应用本身程序的问题,造成死锁。
2、load太高,已经超出服务的极限
3、jvm GC时间过长,导致应用暂停
因为出错项目里面没有打出GC的处理情况,所以不确定此原因是否也是我项目tomcat假死的原因之一。
4、大量tcp连接CLOSE_WAIT
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
TIME_WAIT 48
CLOSE_WAIT 2228
ESTABLISHED 86
常用的三个状态是:ESTABLISHED 表示正在通信,T
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
如何解决程序中未释放数据库连接的问题
问题描述:
在某种情况下,由于代码不严格,数据库连接没有正常释放,导致数据库连接池达到最大值,出现请求失败的问题。
解决方案:
方案一:修改代码,正常释放数据库连接;
方案二:如果代码不能代码(如第三方的代码),可以在tomcat/conf/context.xml配置数据库连接时,添加以下三个属性:
removeAbandoned="true"
removeAbandonedTimeout="300"
logAbandoned="true"
/////////////////////////////////////////////////////
select process,osuser,username,machine,logon_time ,sql_text
from v$session a,v$sqltext b where a.sql_address=b.address;
可看到未断开的连接