性能监控简单小结
涉及MySQL和JVM
MySQL
首先是MySQL的常用监控项
缓存
- 缓存概览
1
2
3
4
5
6
7
8
9
10
11
12mysql> show variables like "%Query_cache%%";
+------------------------------+----------+
| Variable_name | Value |
+------------------------------+----------+
| have_query_cache | YES |
| query_cache_limit | 16777216 |
| query_cache_min_res_unit | 4096 |
| query_cache_size | 16777216 |
| query_cache_type | OFF |
| query_cache_wlock_invalidate | OFF |
+------------------------------+----------+
6 rows in set (0.24 sec) - 缓存碎片率其中,如果Qcache_free_blocks大致等于Qcache_total_blocks/2,说明碎片非常严重
1
2
3
4
5
6
7
8
9
10
11
12
13
14mysql> show status like "%Qcache%";
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 16760152 |
| Qcache_hits | 0 |
| Qcache_inserts | 0 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 19860231 |
| Qcache_queries_in_cache | 0 |
| Qcache_total_blocks | 1 |
+-------------------------+----------+
8 rows in set (0.21 sec)
如果Qcache_lowmem_prunes的值正在增加,并且有大量的自由块,表示碎片导致查询正在被从缓存中永久删除
*缓存碎片率 = Qcache_free_block/Qcache_total_blocks 100%如果查询缓存碎片率都超过20%,可以使用FLUSH QUERY CACHE
整理缓存碎片
*缓存利用率 = (query_cache_size - Qcache_free_memory)/ query_cache_size *100% *
查询缓存利用率低于25%,表明query_cache_size值设置过大,可以适当减小;
查询利用率在80%以上,并且Qcache_lowmem_prunes >50,表明query_cache_size值太小或者碎片太多
- thread_cache_size缓存在Cache中的线程数量
1
2
3
4
5
6
7
8
9mysql> show variables like "thread%";
+-------------------+---------------------------+
| Variable_name | Value |
+-------------------+---------------------------+
| thread_cache_size | 32 |
| thread_handling | one-thread-per-connection |
| thread_stack | 262144 |
+-------------------+---------------------------+
3 rows in set (0.00 sec)
连接数
DB已连接线程数
1
2
3
4
5
6
7mysql> show status like 'Connections';
+---------------+--------+
| Variable_name | Value |
+---------------+--------+
| Connections | 245884 |
+---------------+--------+
1 row in set (0.00 sec)当前连接线程状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14mysql> show status like '%thread%';
+------------------------------------------+-------+
| Variable_name | Value |
+------------------------------------------+-------+
| Delayed_insert_threads | 0 |
| Performance_schema_thread_classes_lost | 0 |
| Performance_schema_thread_instances_lost | 0 |
| Slow_launch_threads | 0 |
| Threads_cached | 18 |
| Threads_connected | 9 |
| Threads_created | 27 |
| Threads_running | 1 |
+------------------------------------------+-------+
8 rows in set (0.00 sec)服务器允许最大连接数
1
2
3
4
5
6
7mysql> show variables like 'max_connections';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| max_connections | 151 |
+-----------------+-------+
1 row in set (0.00 sec)一般500 ~ 800比较合适
服务器响应的最大连接数
1
2
3
4
5
6
7mysql> show global status like 'Max_used_connections';
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| Max_used_connections | 27 |
+----------------------+-------+
1 row in set (0.00 sec)
**Max_used_connections/max_connections <= 85%**比较理想
- 连接队列长度类似于线程队列,当无法响应请求时,就让线程排队;值越小越好。
1
2
3
4
5
6
7mysql> show variables like 'back_log';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| back_log | 80 |
+---------------+-------+
1 row in set (0.00 sec)
索引
- 索引缓存大小
1
2
3
4
5
6
7mysql> show variables like 'key_buffer_size';
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| key_buffer_size | 33554432 |
+-----------------+----------+
1 row in set (0.00 sec
*连接缓存命中率Threads_Cache_Hit = (Connections - Threads_created)/Connections100%**建议90%左右甚至更高
- 索引缓存未命中率
1
2
3
4
5
6
7
8mysql> show global status like 'key_read%';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Key_read_requests | 28 |
| Key_reads | 10 |
+-------------------+-------+
2 rows in set (0.10 sec)
*索引缓存未命中率key_cache_miss_rate = Key_reads/Key_read_requests 100%
1%即100个索引中有一个在缓存中找不到,要直接从硬盘读取;建议小于0.1%
- 索引缓存命中率
1
2
3
4
5
6
7
8
9
10
11
12
13mysql> show global status like 'key_%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| Key_blocks_not_flushed | 0 |
| Key_blocks_unused | 26785 |
| Key_blocks_used | 7 |
| Key_read_requests | 28 |
| Key_reads | 10 |
| Key_write_requests | 2 |
| Key_writes | 2 |
+------------------------+-------+
7 rows in set (0.00 sec)
key_buffer_read_hits = (1-Key_reads/Key_read_requests) *100%**
**key_buffer_write_hits = (1-Key_writes/Key_write_requests)*100%
越大越好
- 索引读取统计Key_blocks_unused表示未使用的缓存簇(blocks)数,Key_blocks_used表示曾经用到的最大的blocks数,如果缓存都用到了,那么要么增加key_buffer_size,要么就是过度索引把缓存占满了。
1
2
3
4
5
6
7
8mysql> show global status like 'key_blocks_u%';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Key_blocks_unused | 26785 |
| Key_blocks_used | 7 |
+-------------------+-------+
2 rows in set (0.00 sec)
比较理想的情况:
*Key_blocks_used/(Key_blocks_unused + Key_blocks_used) 100% ≈ 80%
表
- 临时表临时表比较大无法在内存中完成时就不得不使用磁盘文件。如果Created_tmp_tables非常大,则可能是系统中排序操作过多,或者表连接方式不是很优化。如果Created_tmp_disk_tables和Created_tmp_tables的比率过高,如超过10%,则需要考虑tmp_table_size这个系统参数的值是都设置的足够大。
1
2
3
4
5
6
7
8
9mysql> show global status like 'created_tmp%';
+-------------------------+--------+
| Variable_name | Value |
+-------------------------+--------+
| Created_tmp_disk_tables | 3054 |
| Created_tmp_files | 7 |
| Created_tmp_tables | 624084 |
+-------------------------+--------+
3 rows in set (0.00 sec)
参考值: Created_tmp_disk_tables/Created_tmp_tables < 5%
1 | mysql> show variables where Variable_name in ('tmp_table_size', 'max_heap_table_size'); |
MySQL规定的内部内存临时表的最大值,每个线程都要分配。(实际起限制作用的是tmp_table_size和max_heap_table_size的最小值。)如果内存临时表超出了限制,MySQL就会自动地把它转化为基于磁盘的MyISAM表,存储在指定的tmpdir目录下:
1 | mysql> show variables like "tmpdir"; |
- 表扫描情况
1
2
3
4
5
6
7
8
9
10
11
12
13mysql> show global status like 'handler_read%';
+-----------------------+----------+
| Variable_name | Value |
+-----------------------+----------+
| Handler_read_first | 9357279 |
| Handler_read_key | 77387871 |
| Handler_read_last | 121 |
| Handler_read_next | 69589828 |
| Handler_read_prev | 104 |
| Handler_read_rnd | 531042 |
| Handler_read_rnd_next | 45348670 |
+-----------------------+----------+
7 rows in set (0.00 sec)1
2
3
4
5
6
7mysql> show global status like 'com_select';
+---------------+----------+
| Variable_name | Value |
+---------------+----------+
| Com_select | 19894899 |
+---------------+----------+
1 row in set (0.00 sec)
表扫描率 = Handler_read_rnd_next /Com_select
如果表扫描率超过4000,说明进行了太多表扫描,可能是索引没有建好;
JVM
jps
直接运行命令,返回java进程号,参数:
1 | -l: 返回java进程全路径 |
jstat
用的最多
- 查看运行情况
首先通过jps
获取进程号,再使用jstat
获取JVM中加载的累的数据和size1
2[root@localhost ~]# jps
15649 Gtest.0-y-1.1.5.jar每1秒统计一次,每统计5次显示一次表头1
2
3
4
5
6
7[root@localhost ~]# jstat -class -h5 15649 1000
Loaded Bytes Unloaded Bytes Time
11654 21472.7 0 0.0 4.21
11654 21472.7 0 0.0 4.21
11654 21472.7 0 0.0 4.21
11654 21472.7 0 0.0 4.21
11654 21472.7 0 0.0 4.21
字段含义:
Item | 含义 |
---|---|
Loaded | 加载类的数目 |
Bytes | 加载类的Size,单位Bytes |
Unloaded | 卸载类的数量 |
Bytes | 卸载类的Size,单位Bytes |
Time | 加载和卸载类花费的时间 |
- jstat 所有选项说明
更详细可以man jstat
查看,所有选项及对应的参数说明
Item | 含义 |
---|---|
class | 查看类加载情况的统计 |
compiler | 查看HotSpot中即使编译器编译情况的统计 |
gc | 用于查看JVM中堆的垃圾回收情况统计 |
gccapacity | 查看新生代、老年代及元空间情况 |
gccause | 最后一次及当前正在垃圾回收的原因 |
gcnew | 查看新生代垃圾回收情况 |
gcnewcapacity | 查看新生代存储容量情况 |
gcold | 查看老年代及持久代发生GC的情况 |
gcoldcapacity | 查看老年代容量 |
gcmetacapacity | 元空间容量 |
gcutil | GC统计 |
- jstat gccapacity
1 | [root@localhost ~]# jstat -gccapacity 15649 |
字段说明:
Item | 说明 |
---|---|
NGCMN | 新生代最小容量(KB) |
NGCMX | 新生代最大容量(KB) |
NGC | 新生代当前容量(KB) |
S0C | 当前幸存者一区(survivor)容量(KB) |
S1C | 当前幸存者二区(survivor)容量(KB) |
EC | 当前伊甸园(eden)容量(KB) |
OGCMN | 老年代初始化大小(KB) |
OGCMX | 老年代最大容量(KB) |
OGC | 老年代当前容量(KB) Current old generation capacity (kB) |
OC | old区当前容量(KB) Current old space capacity (kB) |
MCMN | 最小元空间容量(kB) |
MCMX | 最大元空间容量(kB) |
MC | 元空间容量(kB) |
CCSMN | 压缩类空间最小容量(kB) |
CCSMX | 压缩类空间最大容量(kB) |
CCSC | 压缩类空间容量(kB) |
YGC | young GC次数 |
FGC | Full GC次数 |
- jstat gcutil
1 | [root@localhost ~]# jstat -gcutil 15649 |
字段说明:
Item | 含义 |
---|---|
S0 | 幸存者一区已使用的容量百分比 |
S1 | 幸存者二区已使用的容量百分比 |
E | 伊甸园已使用的容量百分比 |
O | 老年代已使用的容量百分比 |
M | 元空间已使用的容量百分比 |
CCS | 压缩类空间利用率百分比 |
YGC | Young GC次数 |
YGCT | JVM启动到采样时,Young GC用时(s) |
FGC | Full GC次数 |
FGCT | JVM启动到采样时,Full GC用时(s) |
GCT | GC总时间 |
jmap
jmap我知道的作用,就是dump下堆快照,再用工具分析
1 | jmap -dump:live,format=b,file=dump.hprof PID |
其他用法:
jmap分析jvm内存
jmap -heap pidOP
打印当前java堆活跃的各个对象的数量、大小
jmap -histo:live 16102 | head -10
1 | [C is a char[] |
- 打印等待回收的对象信息
jmap -finalizerinfo pid
dump快照打印下来之后,传到本地,可以使用Jsisualvm或者MemoryAnalyze
(mat)打开
提取码:t4yy
jstack
步骤:
top -c P(找最耗CPU进程拿pid) 4209
top -Hp 4209 P (找最耗CPU线程,拿pid) 9890
printf “%x” 9890 (转换为16进制)
jstack 4209 | grep 26a2 -C5 –color
以上,就是整理的一点监控相关,配合以下几篇,性能测试的性能问题定位,差不多入门: