目的:
此文档的目的是指导研发同事在线上系统发生紧急问题的时候,如何快速,有条理的排查和解决问题。
总则:
1、首先明确处理问题的原则,快速恢复服务的可用性,将影响降低到最低。
2、问题升级策略,自己无法决策的问题立刻升级到部门经理,最高可直接升级到CTO。
1. 查询应用服务器
① 查询内存
free -m 剩余内存 = free +cached 200M以下 则需要升级配置或找到占用内存的进程进行处理
top 再按大写的M按内存占用排序
ps -p pid -o rss,vsz RSS VSZ 7152568 17485844
VSZ是虚拟内存,RSS是实际使用的内存,单位KB
jstat -gc -h10 pid 3000
看oc 和ou
看错误日志有没有OOM
OOM,全称“Out Of Memory”,来源于java.lang.OutOfMemoryError
java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: PermGen space
抓取内存dump并分析
jmap -dump:format=b,file=文件名 [pid]
MemoryAnalyzer.exe打开保存的内存dump,查看leak suspects,分析是哪个线程占用的内存
② 查询磁盘
Linux:
查询磁盘空间是否满了 df -h
找到占用空间的目录 du -sh du -sh *
查询未释放已删除文件 //TODO
windows
SpaceSniffer
③ 查询CPU
1.使用 top -p 命令查看占用cpu的进程:
2.使用 top -Hp pid 命令查看该Java进程内所有线程的资源占用情况
windows用ProcessExplorer,无需安装,下载后双击即可运行,查看想要观察的进程,选择属性可看到线程占用CPU情况
windows下也可以用pslist -d pid(下载psexec工具)
使用 printf "%x\n" tid 命令(tid指线程的id号)将以上10进制的线程号转换为16进制:
jstack pid | grep 0x86a -A20 打印进程的堆栈
常见线程
1、jobs-thread-n play项目中的JOB执行线程
2、play-thread-n play项目中的http请求处理线程
3、pool-n-thread-n java自定义线程池内的线程默认名称
4、C2 CompilerThread0 这个线程是JVM在server模式下字节码编译器,JVM启动的时候所有代码都处于解释执行模式,当某些代码被执行到一定阈值次数,这些代码(称为热点代码)就会被 C2 Compiler编译成机器码,编译成机器码后执行效率会得到大幅提升。
流量进来后,大部分代码成为热点代码,这个过程中C2 Compiler需要频繁占用CPU来运行,当大部分热点代码被编译成机器代码后,C2 Compiler就不再长期占用CPU了,这个过程也可以看作抖动。
5、GC task thread#n GC线程
④ 服务响应慢
ps -ef |grep NvBus 查进程
jps -v |grep NvBus 查JAVA进程
jstack -l pid >./jstacklog.txt 命令来获取线程快照结果并输入到指定文件。
windows服务启动的java进程,直接用jstack会报错没有system权限,可下载psexec工具 ,用psexec -s jstack运行即可
如果是VM线程上用CPU,则要分析是不是GC活动太频繁导致 jstat -gc -h10 pid 3000
jmap -dump:format=b,file=base3sync pid 配合MemoryAnalyzer.exe工具分析
jvm.memory=-XX:MaxDirectMemorySize=1024M -Xmx1024M -Xms128M -XX:PermSize=64M -XX:MaxPermSize=128M -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8686 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=127.0.0.1 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/
play status
看controls平均执行时长、最大执行时长、执行次数
看play线程池Queue siz、Waiting for execution
看数据库连接busy connection num
数据库超时BUG
db.busytimeout=120 单位秒,超时120秒后杀掉长连接正式环境不允许配置
搜索日志:A checked-out resource is overdue
db.pool.timeout=10000 单位毫秒,10秒后获取数据库连接失败
db.pool.maxSize=30 最大连接数
查看端口监听:lsof -i:9000
查看网络连接: netstat -anp |grep 3306 netstat -ano|findstr 9000
群文件网络诊断工具
畅达各平台日志查询
2.查询数据库sql
① 首先查询是否有表锁
SELECT object_name, machine, s.sid, s.serial#
FROM gv$locked_object l, dba_objects o, gv$session s
WHERE l.object_id = o.object_id
AND l.session_id = s.sid;
-- 释放SESSION SQL:
Alter system kill session 'sid, serial#';
-- 使用第一步执行出来的sid和serial
ALTER system kill session '23, 1647';
-- 锁特别多的情况下使用z
SELECT 'Alter system kill session ''' || s.sid || ',' || s.serial# || ''';'
FROM gv$locked_object l, dba_objects o, gv$session s
WHERE l.object_id = o.object_id
AND l.session_id = s.sid;
② 查询正在执行的任务
select a.program, b.spid, c.sql_text,c.SQL_ID
from v$session a, v$process b, v$sqlarea c
where a.paddr = b.addr
and a.sql_hash_value = c.hash_value
and a.username is not null;
③ 查询Oracle正在执行的sql语句及执行该语句的用户
SELECT c.sql_ID,
c.SQL_FULLTEXT,
c.EXECUTIONS "执行次数",
round(c.ELAPSED_TIME / 1000000, 2) "总执行时间",
round(c.ELAPSED_TIME / 1000000 / c.EXECUTIONS, 2) "平均执行时间",
sql_text 正在执行的SQL,
b.machine 计算机名,
paddr,
b.sid oracleID,
b.username 登录Oracle用户名,
b.serial#,
spid 操作系统ID
FROM v$process a, v$session b, v$sqlarea c
WHERE a.addr = b.paddr
AND b.sql_hash_value = c.hash_value
and round(c.ELAPSED_TIME / 1000000 / c.EXECUTIONS, 2) > 0
and c.EXECUTIONS > 0
order by c.EXECUTIONS desc;
④查看正在执行sql的发起者的发放程序
SELECT OSUSER 电脑登录身份,
PROGRAM 发起请求的程序,
USERNAME 登录系统的用户名,
SCHEMANAME,
B.Cpu_Time 花费cpu的时间,
STATUS,
B.SQL_TEXT 执行的sql
FROM V$SESSION A
LEFT JOIN V$SQL B ON A.SQL_ADDRESS = B.ADDRESS
AND A.SQL_HASH_VALUE = B.HASH_VALUE
ORDER BY b.cpu_time DESC
⑤查询执行时间打印3秒的sql
SELECT t.LAST_LOAD_TIME,t.MODULE,trunc(t.ELAPSED_TIME/t.EXECUTIONS/1000000),t.SQL_FULLTEXT,t.EXECUTIONS
FROM v$sqlarea t
Where t.EXECUTIONS>0 And t.ELAPSED_TIME/t.EXECUTIONS/1000000>3
and t.MODULE ='JDBC Thin Client'
-- and t.LAST_LOAD_TIME>sysdate-1/24
-- and t.LAST_ACTIVE_TIME>sysdate-1/24
ORDER BY t.ELAPSED_TIME/t.EXECUTIONS DESC;
⑥查询锁等待
select (select username from v$session where sid = a.sid) username,
a.sid,
(select serial# from v$session where sid = a.sid) serial#,
a.type,
a.id1,
a.id2,
a.lmode,
a.request,
a.block,
b.sid blocking_sid
from v$lock a,
(select *
from v$lock
where request > 0
and type <> 'MR') b
where a.id1 = b.id1(+)
and a.id2 = b.id2(+)
and a.lmode > 0
and a.type <> 'MR'
And b.sid is not null
order by username, a.sid, serial#, a.type
此时可以查询到锁等待的现象,最后一列不为空的就是等待的事件
-- 查询当前ACTIVE的的v$session
select t.sql_id as a, t.* from v$session t
where username is not null and status = 'ACTIVE'
order by logon_time, sid;
-- 根据sid 查询IP
SELECT sid,serial#,username,port,machine,logon_time FROM v$session WHERE sid=84;
netstat -ano |findstr port
select vs.SQL_TEXT,vsess.sid,vsess.SERIAL#,vsess.MACHINE,vsess.OSUSER
,vsess.TERMINAL,vsess.PROGRAM,vs.CPU_TIME,vs.DISK_READS
from v$sql vs,v$session vsess
where vs.ADDRESS=vsess.SQL_ADDRESS
and vsess.sid=1599