Linux性能优化实战学习笔记:第二十八讲
一、案例环境描述
1、环境准备
2CPU,4GB内存
预先安装docker sysstat工具
1 |
|
案例总共由三个容器组成:
1、包括一个 MySQL 数据库应用、
2、一个商品搜索应用
3、一个数据处理的应用。
其中,商品搜索应用以 HTTP 的形式提供了一个接口:
/:返回 Index Page;
/db/insert/products/:插入指定数量的商品信息
/products/:查询指定商品的信息,并返回处理时间。
2、架构图
今天的案例需要两台虚拟机,其中一台作为案例分析的目标机器,运行 Flask 应用,它的 IP 地址是 192.168.0.10;另一台则是作为客户端,请求单词的热度。我画了一张图表示它们的关系。
3、测试环境准备
首先、我们在第一个终端中执行下面命令,拉去本次案例所需的脚本:
1 2 |
|
接着,执行下面的命令,运行本次的目录应用,正常情况下,你应该可以看到下面的输出
1 2 3 4 5 6 7 |
|
注意容器下面的碎字符串是容器ID,每次运行均会不同,并且你不需要关注它,因为我们只会用到名字
然后,再次运行docker ps命令,确认三个容器都处在运行(Up)状态;
1 2 3 4 5 6 |
|
MySQL数据库的启动过程,需要做一些初始化工作,这通常需要花费几分钟时间,你可以运行dockers log命令、查看它的启动过程
1 2 3 4 5 6 7 8 9 10 11 |
|
确认商品搜索应用在10000端口监听,确认它也已经正常运行
1 2 |
|
二、故障现象
1、发现故障
运行make init命令,初始化数据库、插入10000条商品信息(这个过程比较慢,大约需要十几分钟的时
1 2 3 4 |
|
在第二个终端,访问一下商品搜索的接口、看看能不能找到想要的商品、执行如下的curl命令
1 2 |
|
2、故障现象
稍等一会儿,你会发现,这个接口返回的是空数据,而且处理时间超过15秒,这么慢的响应速度让人无法忍受,到底出了什么问题呢?
三、分析过程
在第二个终端继续执行下面的命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
1、首先、我们在中断执行top命令、分析系统的CPU使用情况:
观察top的输出,我们发现:
1、两个CPU的iowat都比较高、特别是cpu0,iowat已经超过了60%
2、而具体到各个进程, CPU 使用率并不高,最高的也只有17.2
2、既然CPU嫌疑不大,那问题应该在I/O上,停止top命令;然后执行iostat命令,看看有没有I/O性能问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
1、磁盘 sda 每秒的读数据为 32 MB
2、而 I/O 使用率高达 97%
3、接近饱和,这说明,磁盘 sda 的读取确实碰到了性能瓶颈
3、如何知道这些进程是那些进程导致的呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
4、分析进程的数据读取 需要用到strace+ lsof 组合。
为什么mysqld会读取大量的磁盘数据呢?按照前面猜测,我们提到过、这有可能是慢查询问题
可是、回想一下、慢查询的现象大多是cpu使用率高,但这里的看到的确实I/O问题,看来、这并不是一个单纯的
慢查询问题,我们有必要分析一下mysql读取的数据
我们知道,MySQL 是一个多线程的数据库应用,为了不漏掉这些线程的数据读取情况,你要记得在执行stace 命令时,加上 -f 参数:
1 2 3 4 5 6 7 8 9 10 |
|
线程 10919 正在读取大量数据、且读取文件的描述符编号为 37。
5、这儿的 37 又对应着哪个文件呢?
1 2 3 |
|
为什么 lsof 命令执行失败了呢?
遇到现象解释不了,先去查查工具文档。事实上,通过查询 lsof 的文档,你会发现,-p 参数需要指定进程号,而我们刚才传入的是线程号,所以 lsof 失败了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
你会发现,mysqld 其实还有很多正在运行的其他线程:
6、找到了原因,lsof 的问题就容易解决了。把线程号换成进程号、继续执行 lsof 命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
|
mysqld 进程确实打开了大量文件
而根据文件描述符(FD)的编号,我们知道,描述符为 37 的是一个路径为/var/lib/mysql/test/products.MYD的文件,这里注意37后面的U表示,mysqld读写的方式访问文件
看到这个文件,熟悉 MySQL 的你可能笑了:
1、MYD 文件,是 MyISAM 引擎用来存储表数据的文件;
2、文件名就是数据表的名字;
3、而这个文件的父目录,也就是数据库的名字。
换句话说,这个文件告诉我们,mysqld 在读取数据库 test中的products表
7、查看 mysqld 在管理数据库 test 时的存储文件
1 2 |
|
从这里你可以发现,/var/lib/mysql/test/ 目录中有四个文件,每个文件的作用分别是:
1、MYD 文件用来存储表的数据;
2、MYI 文件用来存储表的索引;
3、frm 文件用来存储表的元信息(比如表结构);
4、opt 文件则用来存储数据库的元信息(比如字符集、字符校验规等
8、这些文件到底是不是 mysqld 正在使用的数据库文件呢?
1 2 3 4 5 6 |
|
9、数据库中正在执行什么样的 SQL 了
不过,为了保证 SQL 语句不截断、这里我们可以执行 show full processlist命令。如果一切正常,你应该可以看到如下输出:
1 2 3 4 5 6 7 8 |
|
10、explain 命令确认是否建立索引
根据这些信息,我们可以确定,这条查询语句压根儿没有使用索引,所以查询时,会扫描全表,并且扫描行数高达 20000 行。响应速度那么慢也就难怪了。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
查询 products 表的结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
你会看到,它只有一个 id 主键,并不包括 productName 的索引:
11、创建索引
1 2 |
|
你会看到,它只有一个 id 主键,并不包括 productName 的索引:就必须为 productName 指定一个前缀长度
1 2 3 |
|
现在可以看到,索引已经建好了。能做的都做完了,最后就该检查一下,性能问题是否已经解决了。
查看还在执行的 curl 命令的结果:
1 2 3 4 5 6 7 8 9 |
|
查看还在执行的 curl 命令的结果:
四、DataService 是一个严重影响 MySQL 性能的干扰应用
1、停止DataService容器
1 2 3 |
|
2、删除索引
1 2 3 4 5 |
|
3、观察性能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
4、观察 curl 的结果:
1 2 3 4 5 6 7 8 9 10 11 |
|
作者:罗阿红 出处:http://www.cnblogs.com/luoahong/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。