1. top命令查询状态
发现CPU0的 wa (iowait)很大,但CPU很小,属于异常。
2. iostat 查询磁盘状态
磁盘 sda 每秒的读数据为 32 MB, 而 I/O 使用率高达 97%,这说明磁盘sda遇到了性能瓶颈。
3. pidstat 查询进程状态
找到了磁盘 I/O 瓶颈的根源,即 mysqld 进程
4. 分析:这有可能是个慢查询问题。
但是慢查询的现象大多是 CPU 使用率高,但这里的CPU并不高,而是IO高。
那么,有必要分析一下 MySQL 读取的数据。
5. strace 命令查看进程运行堆栈。mysqld 的进程号是 27458
线程 28014 正在读取大量数据,且读取文件的描述符编号为38
6. lsof 命令,看看进程 27458都打开了哪些文件
而根据文件描述符(FD)的编号38,确认打开的文件是 /var/lib/mysql/test/products.MYD
MYD 文件,是 MyISAM 引擎用来存储表数据的文件;
文件名product是数据表的名字;
而这个文件的父目录test,是数据库的名字。
所以, mysqld 在读取数据库 test 中的 products表。
7. 确认数据库使用的文件路径
上面查出来的路径就是正在使用的路径,没错。
8. 执行mysql的 show processlist 查看mysql正在做什么
可看到 select * from products where productName=‘geektime’ 这条 SQL 语句的执行时间比较长。
9. MySQL 的慢查询问题,很可能是没有利用好索引导致的。 确认这条语句是不是没有利用索引:
使用explain 命令查看
possible_keys 表示可能选用的索引,这里是 NULL;
key 表示确切会使用的索引,这里也是 NULL;
10. 给 productName 建立索引
11. 确认结果
查询时间已经从 15 秒缩短到了 3 毫秒。
1. top命令查询状态
CPU0 的 iowait 比较高,已经达到了 84%。而CPU使用率都不高,只有8.6%和5%
2. iostat 查询磁盘状态
磁盘 sda 每秒的写数据(wkB/s)为 2.5MB,I/O 使用率(%util)是 0。
虽然有些 I/O 操作,但并没导致磁盘的 I/O 瓶颈。
CPU 和内存使用没问题,I/O 也没有瓶颈,那问题在哪里呢?
思考:该例子只有查询操作,不应该有磁盘写。
虽说 I/O 本身并没有性能瓶颈,但这里的磁盘写也是比较奇怪的。
3. pidstat 查询进程状态
写文件的进程是redis-server
4. strace 命令查看进程运行堆栈
跟磁盘写有关的,就应该是write和fdatasync 这些系统调用
5. lsof 命令,看看进程 9085 都打开了哪些文件
只有 7 号普通文件才会产生磁盘写,而它操作的文件路径是/data/appendonly.aof
相应的系统调用包括 write 和 fdatasync。
6. appendonly.aof 文件对应 Redis 持久化配置中的 appendonly 和 appendfsync 选项
appendfsync 配置的是 always,意味着每次写数据时,都会调用一次 fsync,从而造成比较大的磁盘 I/O 压力。
7. 使用trace查看调用fdatasync的情况,(通过 -e 选项指定 fdatasync)
可以看到,每隔 10ms 左右,就会有一次 fdatasync 调用,并且每次调用本身也要消耗 7~8ms。
这就找出了 Redis 正在进行写入的文件,也知道了产生大量 I/O 的原因。
8. 再来审查一下 strace -f -T -tt -p 9085 的结果
编号为 8 的是 TCP socket,对应的 TCP 读写,是一个标准的“请求 - 响应”格式
从 socket 读取 GET uuid:53522908-… 后,响应 good;
再从 socket 读取 SADD good 535… 后,响应 1。
对 Redis 来说,SADD 是一个写操作,所以 Redis 还会把它保存到用于持久化的 appendonly.aof 文件中。
每当 GET 返回 good 时,随后都会有一个 SADD 操作,这也就导致了,明明是查询接口,Redis 却有大量的磁盘写。
9. 解决办法:
(1) 把 appendfsync 改成 everysec:
(2) 不要执行SAdd,把临时和中间数据放内存。