通常关于io相关的问题,我们可以使用top及iostat进行分析系统CPU及磁盘IO情况,然后使用strace lsof等工具进行追踪,以及新的工具 filetop及opensnoop,进行分析write及open的函数追踪

我们这次拿的案例,是一个数据库的性能案例,一个基于Python Flask的商品搜索应用,商品信息存在于MySQL中,应用可以通过MySQL进行查询

准备了两个容器,一个MySQL数据库实例,一个商品搜索实例

商品搜索的应用以HTTP的形式提供一个接口

支持的接口有

/products 查询指定商品的信息

我们首先在一台虚拟机上启动这些Docker实例

然后另一台作为客户端,去请求单词,查看热度

我们尝试搜索对应的商品

curl http://192.168.0.10:10000/products/helloworld

返回的数据为0,且处理时间超过15秒,这是为什么呢?

15秒的慢查询,一看就不对,我们需要对其进行相关的查找和修改

我们现将curl命令放在一个循环中执行,同时为了避免压力过大,在每次的查询之后,等待5秒,之后进行新的请求

while true:

do

curl http://192.168.0.10:10000/products/helloworld;

sleep 5;

done

在之后进行分析为何响应变慢

首先是top命令,分析系统的CPU使用情况

图片

获得输出如上,可以看出top的输出中,CPU的iowait都比较高,特别是CPU0,超过60%

但CPU使用率并不高,最高只有1.7%

既然发现了IO的问题,我们就继续使用iostat进行查看io相关问题

iostat -d -x 1

$ iostat -d -x 1

Device            r/s     w/s     rkB/s     wkB/s   rrqm/s   wrqm/s  %rrqm  %wrqm r_await w_await aqu-sz rareq-sz wareq-sz  svctm  %util

sda            273.00    0.00  32568.00      0.00     0.00     0.00   0.00   0.00    7.90    0.00   1.16   119.30     0.00   3.56  97.20

在其中,sda的每秒读写大小为32MB/S,IO使用率为97% 发现了是io性能

然后我们使用对应的pidstat来查看是哪个进程导致的IO升高

pidstat -d 1

图片

pidstat中输出了PID为27458的mysqld的进程正在进行大量的读,读取的速度为32MB/s

跟刚才的iostat的输出对比发现,根源自然是mysqld进程

继续使用老一套的打法,我们接下来使用strace进行查看mysqld的执行

而且因为mysql是一个多线程的数据库应用,执行strace的时候,别忘了加上 -f参数

strace -f -p 27458

发现其正在读取大量的数据,这时候呢,就是lsof进行上场的时候

lsof -p 27458查看对应的lsof的输出(这一步要给出的是对应的pid,而非是线程号,如果不知道pid,可使用pstree 查看)

获取到对应的输出

mysqld 27458 999 38u REG 8,1 512440000 2601895 /var/lib/mysql/test/products.MYD

上面的输出中,32u是说明了mysqld是以读写的方式访问的文件,

MYD则是MyISAM引擎用于存储表数据的文件

MYI 是存储表索引的

frm 是表的元数据

opt是存储数据库的元信息

文件名就是数据表的名字

文件的父目录,就是数据库的名字

这说明mysql在使用test库中的products的表

那么我们需要进入mysqld中进行查看,分析mysqld执行的数据

执行show prcesslist命令,查看正在执行的SQL语句

获取到下面的执行sql

图片

在对应的输出中

info中说明了完整的SQL语句

那么这个语句如果出现了慢查询的情况,第一可能性就是没有索引

故,我们使用explain命令查看是否没有索引

图片

key为null,故真的没有索引

而且这个字段是一个text字段,我们需要给其建立一个前缀索引

CREATE INDEX products_index on products(productName(64));

这样,索引就基本建好了,我们可以检查一下性能问题

检查可以发现基本就没有性能问题了

这样,我们解决了因为mysql查询无索引导致的io性能问题

除此外,还额外提供一个小的问题Demo

就是有一个应用

在每次读取文件之前,会将/proc/sys/vm/drop_caches改为1

这样会导致 /proc/sys/vm/drop_cache 释放pageCache,即文件缓存,导致mysql的读取数据每次都要从磁盘重新读取

发表评论

邮箱地址不会被公开。 必填项已用*标注