性能监控简单小结

性能监控简单小结

涉及MySQL和JVM

MySQL

首先是MySQL的常用监控项

缓存

  • 缓存概览
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    mysql> 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)
  • 缓存碎片率
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    mysql> 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_free_blocks大致等于Qcache_total_blocks/2,说明碎片非常严重
    如果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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    mysql> 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)
    缓存在Cache中的线程数量

连接数

  • DB已连接线程数

    1
    2
    3
    4
    5
    6
    7
    mysql> 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
    14
    mysql> 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
    7
    mysql> 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
    7
    mysql> 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
    7
    mysql> show variables like 'back_log';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | back_log | 80 |
    +---------------+-------+
    1 row in set (0.00 sec)
    类似于线程队列,当无法响应请求时,就让线程排队;值越小越好。

索引

  • 索引缓存大小
    1
    2
    3
    4
    5
    6
    7
    mysql> 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
    8
    mysql> 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
    13
    mysql> 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%

越大越好

  • 索引读取统计
    1
    2
    3
    4
    5
    6
    7
    8
    mysql> 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_unused表示未使用的缓存簇(blocks)数,Key_blocks_used表示曾经用到的最大的blocks数,如果缓存都用到了,那么要么增加key_buffer_size,要么就是过度索引把缓存占满了。
    比较理想的情况:

*Key_blocks_used/(Key_blocks_unused + Key_blocks_used) 100% ≈ 80%

  • 临时表
    1
    2
    3
    4
    5
    6
    7
    8
    9
    mysql> 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_tables非常大,则可能是系统中排序操作过多,或者表连接方式不是很优化。如果Created_tmp_disk_tables和Created_tmp_tables的比率过高,如超过10%,则需要考虑tmp_table_size这个系统参数的值是都设置的足够大。
    参考值: Created_tmp_disk_tables/Created_tmp_tables < 5%
1
2
3
4
5
6
7
8
mysql> show variables where Variable_name in ('tmp_table_size', 'max_heap_table_size');
+---------------------+----------+
| Variable_name | Value |
+---------------------+----------+
| max_heap_table_size | 33554432 |
| tmp_table_size | 33554432 |
+---------------------+----------+
2 rows in set (0.01 sec)

MySQL规定的内部内存临时表的最大值,每个线程都要分配。(实际起限制作用的是tmp_table_size和max_heap_table_size的最小值。)如果内存临时表超出了限制,MySQL就会自动地把它转化为基于磁盘的MyISAM表,存储在指定的tmpdir目录下:

1
2
3
4
5
6
7
mysql> show variables like "tmpdir";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| tmpdir | /tmp |
+---------------+-------+
1 row in set (0.01 sec)
  • 表扫描情况
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    mysql> 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
    7
    mysql> 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
2
3
-l: 返回java进程全路径 
-q: 仅显示进程号
-v: 返回JVM参数,可以查看堆大小

jstat

用的最多

  • 查看运行情况
    首先通过jps获取进程号,再使用jstat获取JVM中加载的累的数据和size
    1
    2
    [root@localhost ~]# jps
    15649 Gtest.0-y-1.1.5.jar
    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
    每1秒统计一次,每统计5次显示一次表头

字段含义:

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
2
3
[root@localhost ~]# jstat -gccapacity 15649
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
84992.0 1355776.0 688640.0 8192.0 20992.0 640512.0 171008.0 2711552.0 201728.0 201728.0 0.0 1105920.0 65280.0 0.0 1048576.0 8192.0 14 3

字段说明:

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
2
3
[root@localhost ~]# jstat -gcutil 15649
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
99.22 0.00 81.74 21.00 95.96 93.63 14 0.161 3 0.186 0.347

字段说明:

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
2
3
4
5
[C is a char[]
[S is a short[]
[I is a int[]
[B is a byte[]
[[I is a int[][]
  • 打印等待回收的对象信息
    jmap -finalizerinfo pid

dump快照打印下来之后,传到本地,可以使用Jsisualvm或者MemoryAnalyze(mat)打开

MemoryAnalyze

提取码:t4yy

jstack

步骤:

  1. top -c P(找最耗CPU进程拿pid) 4209

  2. top -Hp 4209 P (找最耗CPU线程,拿pid) 9890

  3. printf “%x” 9890 (转换为16进制)

  4. jstack 4209 | grep 26a2 -C5 –color

以上,就是整理的一点监控相关,配合以下几篇,性能测试的性能问题定位,差不多入门:

windows性能监控指标
Linux性能监控与分析
Linux定位最耗CPU的线程
JVM内存性能问题定位

文章目录
  1. MySQL
    1. 缓存
    2. 连接数
    3. 索引
  2. JVM
    1. jps
    2. jstat
    3. jmap
    4. jstack
|