今天看到一个报警信息,大体是CPU使用异常。
ZABBIX-监控系统:
------------------------------------
报警内容: CPU utilization is too high
报警级别: PROBLEM
监控项目: CPU idle time:55.17 %
报警时间:2016.03.22-19:03:23
对于这个问题,看到CPU使用率过高,大体已经有了一些思路。但是还是需要一些论证。
首先查看sar的情况,可以看出CPU的平均使用率在30~40%
06:55:01 PM all 32.35 0.00 7.57 0.00 60.08
06:56:01 PM all 31.78 0.00 7.55 0.00 60.67
06:57:01 PM all 31.65 0.00 7.52 0.01 60.82
06:58:01 PM all 31.42 0.00 7.48 0.00 61.10
06:59:01 PM all 30.91 0.00 7.58 0.00 61.51
07:00:02 PM all 31.13 0.00 7.62 0.00 61.25
07:01:01 PM all 30.84 0.00 7.62 0.02 61.53
07:02:01 PM all 31.86 0.00 7.83 0.11 60.19
07:03:01 PM all 32.88 0.00 7.64 0.06 59.43
Average: all 24.34 0.00 7.11 0.04 68.51
但是top的结果却让我有些奇怪。
top - 19:04:19 up 68 days, 22:47, 2 users, load average: 4.47, 4.58, 4.47
Tasks: 284 total, 14 running, 269 sleeping, 0 stopped, 1 zombie
Cpu(s): 31.6% us, 3.9% sy, 0.0% ni, 60.5% id, 0.0% wa, 0.1% hi, 3.9% si
Mem: 16430192k total, 16283948k used, 146244k free, 123716k buffers
Swap: 33551744k total, 115632k used, 33436112k free, 13809040k cached
可以看到CPU的使用率虽高,但是IO却几乎没有什么消耗。
然后查看部分的进程信息,发现有部分的进程CPU使用率较高。这个时候看起来是一个全表扫描的概率偏大了。
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+
COMMAND
28185
oracle 16 0 6282m 835m 829m S 82.6 5.2 5:01.48 oracletest
(LOCAL=NO)
28237
oracle 16 0 6282m 832m 826m S 82.6 5.2 4:50.64 oracletest
28345
oracle 16 0 6283m 874m 867m R 82.6 5.5 3:54.84 oracletest
28425
oracle 16 0 6281m 689m 682m S 82.6 4.3 3:50.17 oracletest
28703 oracle 16 0 6281m 571m 565m S 82.6 3.6 2:06.54 oracletest (LOCAL=NO)
然后绑定进程,查看进程对应的session执行sql的情况,发现语句竟然是一句非常简单的查询。
PREV_SQL_ID SQL_TEXT
------------------------------ ------------------------------------------------------------
7gwxpwru0czqw select companyname from license
执行计划如何呢,确实是一个全表扫描。
Plan hash value: 2492423498
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | | | 3 (100)| |
| 1 | TABLE ACCESS FULL| LICENSE | 1 | 29 | 3 (0)| 00:00:01 |
但是这个时候的问题倒不是在于这个全表扫描了,关键就是这个表中目前只有1条数据。
为什么会有这个CPU消耗较大的情况呢,目前来看,语句的执行频率极高。
Per Second
Per Transaction
Redo size:
3,455.88
0.53
Logical reads:
54,200.78
8.32
Block changes:
17.89
0.00
Physical reads:
5.72
Physical writes:
1.25
User calls:
39,104.93
6.01
Parses:
13,033.74
2.00
Hard parses:
4.75
Sorts:
12.16
Logons:
0.07
Executes:
13,035.13
Transactions:
6,512.05
如果看到这种情况,会发现目前的系统还是非常繁忙的,那么主要在哪儿忙呢。可以看到rollback的比例非常高。
% Blocks changed per Read:
0.03
Recursive Call %:
25.04
Rollback per transaction %:
99.97
Rows per Sort:
2027.20
从这个也可以看出应该是应用的逻辑部分出了问题,或者数据问题导致的校验失败导致回滚。
这个时候查看等待事件的情况如下。
Event
Waits
Time(s)
Avg Wait(ms)
% Total Call Time
Wait Class
CPU time
10,839
100.1
SQL*Net message to client
93,924,202
73
.7
Network
latch: cache buffers chains
79,297
8
.1
Concurrency
cursor: pin S
71,807
Other
log file sync
7,136
1
Commit
我们直接到sql的部分来看看。下面两条语句的执行频率极高,大概是1个小时2千多万次的频率。
Elapsed Time (s)
CPU Time (s)
Executions
Elap per Exec (s)
% Total DB Time
SQL Id
SQL Module
SQL Text
1,470
1,414
23,451,700
13.57
<a href="#7gwxpwru0czqw">7gwxpwru0czqw</a>
JDBC Thin Client
select companyname from licens...
694
686
23,024,521
6.41
<a href="#7nkxbfnwgx93v">7nkxbfnwgx93v</a>
select supdepid from mdepart...
那么怎么看出语句存在问题呢。可以在executions部分找到一些痕迹。
Rows Processed
Rows per Exec
CPU per Exec (s)
23,440,315
select supdepid from mdepart
第二条语句的执行频率和第一条一样都非常高,但是第二条语句的“Rows Processed"为0
如果查看语句的buffer gets,就会发现是0
$ sh showsql.sh 7nkxbfnwgx93v
HASH_VALUE PLAN_HASH_VALUE DISK_READS BUFFER_GETS SORTS EXECUTIONS CPU_TIME ELAPSED_TIME_S WAIT_TIME_EACH
---------- --------------- ---------- ----------- ---------- ---------- ---------- -------------- --------------
956212347 3350531500 0 0 0 1806030210 29 0 2
这是为什么呢。因为语句是这样的形式。
select supdepid from mdepartment where id =''
其中这个表的id列有非空约束,还有对应的id索引,这种情况下,直接会返回0行,尽管这个表里有百万的数据。
所以从这些痕迹来看,这个问题是一个异常的状态,需要和开发人员协调,到底是数据问题还是调用的逻辑部分出了问题。