性能调优——生产问题排查
原创2023-04-20 20:12·爱笑的程序猿小胡
一、CPU或内存使用率高
1、排查占用CPU的进程
1.1 top命令
- 按P键(大写打开时)会按照CPU使用率高低进行排序
- 按M键(大写打开时)会按照内存使用率高低进行排序

Top 命令的输出信息主要分为两部分,上半部分显示 CPU 和内存资源的总体使用情况:
- 第一行:系统当前时间,当前登录用户个数以及系统负载。
- 第二行:系统总进程数、运行中进程数、休眠、睡眠和僵尸进程数量。
- 第三行:CPU 当前使用情况。
- 第四行:内存当前使用情况。
- 第五行:Swap 空间当前使用情况。
1.2 jmap
jmap [options] pid
jmap -histo pid | head -20
1.3 jps
jps [options] [hostid]
option参数:
| 参数 | 说明 | 
|---|---|
| -l | 输出主类全名或jar路径 | 
| -q | 只输出LVMID | 
| -m | 输出JVM启动时传递给main()的参数 | 
| -v | 输出JVM启动时显示指定的JVM参数 | 
其中 [option]、[hostid] 参数也可以不写。

1.4 常用命令
- top:Linux 命令。可以实时查看各个进程的 CPU 使用情况。也可以查看最近一段时间的 CPU 使用情况。默认按 CPU 使用率排序。
- ps:Linux 命令。强大的进程状态监控命令。可以查看进程以及进程中线程的当前 CPU 使用情况。属于当前状态的采样数据。
- jstack:Java 提供的命令。可以查看某个进程的当前线程栈运行情况。根据这个命令的输出可以定位某个进程的所有线程的当前运行状态、运行代码,以及是否死锁等等。
- pstack:Linux 命令。可以查看某个进程的当前线程栈运行情况。
- jstat:Java 提供的命令。可以查看某个JVM进程的gc信息。
2、解决问题实战
1、top
进到linux容器中执行 top命令,结果发现高cpu占用,其中pid 为1的正是我们的java程序。

2、top -HP pid
执行命令找出占用CPU最高的线程 top -Hp pid 显示的新pid都是线程,找到占用cpu最高的线程号。

3、printf "%x\n" tid
把线程号转换为16进制,便于在jstack中查询 printf "%x\n" tid 变为16进制。

4、jstack pid | grep 0x十六进制结果 -A30
jstack命令查看相应线程的堆栈 jstack pid | grep 0x十六进制结果 -A30

5、jstat -gcutil pid
命令查看进程的堆情况

0:年轻代中第一个 survivor(幸存区)已使用的占当前容量百分比
S1:年轻代中第二个 survivor(幸存区)已使用的占当前容量百分比
E:年轻代中 Eden 区已使用的占当前容量百分比
O:老年代已使用的占当前容量百分比
M:元数据区使用比例
CCS:压缩使用比例
YGC:从应用程序启动到采样时年轻代中 gc 次数
YGCT:从应用程序启动到采样时年轻代中 gc 所用时间(单位秒)
FGC:从应用程序启动到采样时老年代 full gc 次数
FGCT:从应用程序启动到采样时老年代 full gc 所用时间(单位秒)
GCT:从应用程序启动到采样时 gc 用的总时间(单位秒)
6、jmap -dump:live,format=b,file=pid.hprof pid
命令导出堆文件,只导出 live 存活的对象。文件后缀名可以是任意的,因为它也是二进制的,不过通常以 hprof 结尾。

7、最后使用 JDK 自带的工具,JAVA_HOME/bin/jvisualvm.exe工具分析快照
操作路径:文件 -> 装入 -> 文件类型选择堆,选中刚才导出的堆文件。

选择类列表,按照大小排序,找出占用内存最大的类别

二、数据库CPU使用率100%
1、QPS过高
1.1 首先,查看当前cpu曲线

1.2 发现此时的cpu已经100%,再查看此时的qps曲线

1.3 会发现此时的qps曲线基本和cpu曲线保持一致,此时我们可断定cpu飙升必然存在qps过高的原因。为了验证是否有慢sql的存在,再查看慢sql曲线

发现此案例中完全不存在慢sql。因此责任可100%归为qps过高。
1.4 优化思路
- 1.qps过高时,考虑是否可以使用缓存。
- 2.使用批量操作,将多个操作合并为一次请求,但此种方式需要考虑是否可以一次批量的数据有多大,避免造成慢sql。
- 3.考虑分库、读写分离,减少对一个机器的访问压力。
- 4.机器升级,没什么是钱解决不了的。
2、慢查询
2.1 首先,查看当前cpu曲线

2.2 然后查看qps曲线

从上图我们可看出,cpu和qps的整体的整体走势是基本一致的,但是上图中相对qps曲线,cpu有好几次的抖动,甚至峰值达到80%,我们需要排查出这些峰刺点。
由于此时的cpu抖动和qps曲线不一致,可推测是慢sql引起的,观察下图抖动时间段内的慢sql,确定是否有慢sql,以及慢sql的具体信息。
观察上图发现该时间段内一些慢sql在库上使得cpu曲线发生了抖动,此时可采取kill+id的方法定制该sql的执行。
2.3 优化思路
- 1.扫描数据库记录数较多。
考虑表是否设置了合理的索引,表字段是否设置了合理的数据类型,sql是否有效的利用了索引等。
- 2.sql中是否有做了大量的聚合、计算?
考虑将sql简化,把逻辑操作上浮到业务中去做。
- 3.sql返回的记录数过多。
 考虑分页实现,通过limit将一次请求转为多次请求。
- 4.表中是否冗余字段过多?
 表若为宽表,包含大量冗余字段,可考虑分表。
- 5.库中是否有很多张表?
 此时可考虑将表拆分到多个库中,分库。
- 6.若库的读写较多,锁争抢激励,甚至死锁。
 可考虑多库做读写分离。
- 7.机器的本身性能较低,不符合业务需求。
 可考虑机器升级了。
3、解决题实战
3.1 top查看mysql进程号或者ps -ef | grep -i mysql
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                  
16965 mysql     20   0   32.0g   2.8g  16592 S  1566  8.8  49:40.99 mysqld 
3.2 查看CPU使用率最高的线程号
top -Hp 16965
top -p 16965 -H
  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                                   
17053 mysql     20   0   32.0g   2.8g  16668 R 62.7  9.0   4:47.45 mysqld                                                                                    
17032 mysql     20   0   32.0g   2.8g  16668 R 61.7  9.0   5:03.16 mysqld                                                                                    
17028 mysql     20   0   32.0g   2.8g  16668 R 61.3  9.0   4:38.47 mysqld                                                                                    
17033 mysql     20   0   32.0g   2.8g  16668 R 61.0  9.0   4:56.53 mysqld                                                                                    
17054 mysql     20   0   32.0g   2.8g  16668 R 59.0  9.0   5:17.14 mysqld                                                                                    
17064 mysql     20   0   32.0g   2.8g  16668 R 59.0  9.0   4:57.18 mysqld                                                                                    
17057 mysql     20   0   32.0g   2.8g  16668 R 57.0  9.0   4:47.68 mysqld                                                                                    
17065 mysql     20   0   32.0g   2.8g  16668 R 56.7  9.0   5:00.24 mysqld 
可以看到占用最高的是PID=17053
3.3 找到对应的thread_id,processlist_id
mysql> select thread_id,name ,PROCESSLIST_ID,THREAD_OS_ID from performance_schema.threads where thread_os_id = 17053; 
+-----------+---------------------------+----------------+--------------+
| thread_id | name                      | PROCESSLIST_ID | THREAD_OS_ID |
+-----------+---------------------------+----------------+--------------+
|       143 | thread/sql/one_connection |             97 |        17053 |
+-----------+---------------------------+----------------+--------------+
1 row in set (0.00 sec)
3.4 找到当前占用cpu的SQL
elect DIGEST_TEXT  from performance_schema.events_statements_current where thread_id = 143 ;
+---------------------------------------------------------------------+
| DIGEST_TEXT
SELECT * FROM t xxx ……
三、补充
1、查看死锁
Mysql 查询是否存在锁表有多种方式,这里只介绍一种最常用的
1、查看正在进行中的事务
SELECT * FROM information_schema.INNODB_TRX
2、查看正在锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
3、查看等待锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
4、查询是否锁表
SHOW OPEN TABLES where In_use > 0;
5、查看最近死锁的日志
show engine innodb status
2、解除死锁
如果需要解除死锁,有一种最简单粗暴的方式,那就是找到进程id之后,直接干掉。
2.1 查看当前正在进行中的进程
show processlist
SELECT * FROM information_schema.INNODB_TRX;
2.2 杀掉进程对应的进程 id
kill id
2.3 验证(kill后再看是否还有锁)
SHOW OPEN TABLES where In_use > 0;
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号