【アーキテクチャ性能分析(1)】MySQL性能ボトルネック調査の位置づけ


リード:
         (  /   ),             ,        MySQL              。

OSレベルのチェック確認
まず、現在どのプロセスが負荷が高いのか、これらのプロセスカードがどこにあるのか、ボトルネックが何なのかを確認します.通常、サーバ上で最もボトルネックになりやすいのは、ディスクI/Oサブシステムです.これは、通常、読み書き速度が最も遅いためです.現在のPCIe SSDでも、ランダムI/Oの読み書き速度はメモリほど速くありません.もちろん、ディスクI/Oが遅くなる原因もいろいろありますが、どれが原因なのか確認する必要があります.
第一歩は、一般的に全体の負荷を見てみましょう.負荷が高いと、すべてのプロセスが遅くなるに違いありません.
負荷データを表示するコマンドwまたはsar-q 1を実行します.
[ly@imysql.com:~ ]# w
 11:52:58 up 702 days, 56 min, 1 user, load average: 7.20, 6.70, 6.47
USER   TTY   FROM       LOGIN@  IDLE  JCPU  PCPU WHAT
root   pts/0  1.xx.xx.xx    11:51  0.00s 0.03s 0.00s w

sar-qの観察結果:
[ly@imysql.com:~ ]# sar -q 1
Linux 2.6.32-431.el6.x86_64 (ly.imysql.com)   01/13/2016   _x86_64_  (24 CPU)
02:51:18 PM  runq-sz plist-sz  ldavg-1  ldavg-5 ldavg-15  blocked
02:51:19 PM     4   2305   6.41   6.98   7.12     3
02:51:20 PM     2   2301   6.41   6.98   7.12     4
02:51:21 PM     0   2300   6.41   6.98   7.12     5
02:51:22 PM     6   2301   6.41   6.98   7.12     8
02:51:23 PM     2   2290   6.41   6.98   7.12     8

load averageは、現在のCPUでどれだけのタスクがキューに並んで待っているかを意味します.待つほど負荷が高くなり、データベースを走るサーバでは、一般的にload値が5を超えると、すでに高いと言えます.
loadの高さを引き起こす原因はいくつかあります.
一部のプロセス/サービスはより多くのCPUリソースを消費する(サービスはより多くの要求に応答するか、またはいくつかの応用ボトルネックがある).
比較的深刻なswapが発生した(使用可能な物理メモリが不足している).
比較的深刻な割り込みが発生する(SSDやネットワークの原因で割り込みが発生する);
ディスクI/Oが比較的遅い(CPUがディスクI/O要求をずっと待つことになる);
ボトルネックがどのサブシステムにあるかを判断するには、次のコマンドを実行します.
[ly@imysql.com:~ ]# top
top - 11:53:04 up 702 days, 56 min, 1 user, load average: 7.18, 6.70, 6.47
Tasks: 576 total,  1 running, 575 sleeping,  0 stopped,  0 zombie
Cpu(s): 7.7%us, 3.4%sy, 0.0%ni, 77.6%id, 11.0%wa, 0.0%hi, 0.3%si, 0.0%st
Mem: 49374024k total, 32018844k used, 17355180k free,  115416k buffers
Swap: 16777208k total,  117612k used, 16659596k free, 5689020k cached
 PID USER   PR NI VIRT RES SHR S %CPU %MEM  TIME+ COMMAND
14165 mysql   20  0 8822m 3.1g 4672 S 162.3 6.6 89839:59 mysqld
40610 mysql   20  0 25.6g 14g 8336 S 121.7 31.5 282809:08 mysqld
49023 mysql   20  0 16.9g 5.1g 4772 S 4.6 10.8  34940:09 mysqld

明らかに、前の2つのmysqldプロセスが全体的な負荷を高めた.また,Cpu(s)行の統計結果からも分かるように,%usと%waの値が高く,現在の大きなボトルネックはユーザプロセスで消費されるCPUおよびディスクI/O待ちにある可能性があることを示している.まずディスクI/Oの状況を分析します.
sar-dを実行してディスクI/Oが本当に大きいかどうかを確認します.
[ly@imysql.com:~ ]# sar -d 1
Linux 2.6.32-431.el6.x86_64 (yejr.imysql.com)   01/13/2016   _x86_64_  (24 CPU)
11:54:32 AM  dev8-0  5338.00 162784.00  1394.00   30.76   5.24   0.98   0.19  100.00
11:54:33 AM  dev8-0  5134.00 148032.00 32365.00   35.14   6.93   1.34   0.19  100.10
11:54:34 AM  dev8-0  5233.00 161376.00  996.00   31.03   9.77   1.88   0.19  100.00
11:54:35 AM  dev8-0  4566.00 139232.00  1166.00   30.75   5.37   1.18   0.22  100.00
11:54:36 AM  dev8-0  4665.00 145920.00  630.00   31.41   5.94   1.27   0.21  100.00
11:54:37 AM  dev8-0  4994.00 156544.00  546.00   31.46   7.07   1.42   0.20  100.00

iotop(注意バージョン)を再利用して、どのプロセスで最も多くのディスクI/Oリソースが消費されているかを確認します.
[ly@imysql.com:~ ]# iotop
Total DISK READ: 60.38 M/s | Total DISK WRITE: 640.34 K/s
 TID PRIO USER   DISK READ DISK WRITE SWAPIN   IO>  COMMAND
16397 be/4 mysql    8.92 M/s  0.00 B/s 0.00 % 94.77 % mysqld --basedir=/usr/local/m~og_3320/mysql.sock --port=3320
 7295 be/4 mysql   10.98 M/s  0.00 B/s 0.00 % 93.59 % mysqld --basedir=/usr/local/m~og_3320/mysql.sock --port=3320
14295 be/4 mysql   10.50 M/s  0.00 B/s 0.00 % 93.57 % mysqld --basedir=/usr/local/m~og_3320/mysql.sock --port=3320
14288 be/4 mysql   14.30 M/s  0.00 B/s 0.00 % 91.86 % mysqld --basedir=/usr/local/m~og_3320/mysql.sock --port=3320
14292 be/4 mysql   14.37 M/s  0.00 B/s 0.00 % 91.23 % mysqld --basedir=/usr/local/m~og_3320/mysql.sock --port=3320

ポート番号が3320のインスタンスで消費されるディスクI/Oリソースが多いことがわかりますが、このインスタンスでどのようなクエリーが走っているかを見てみましょう.
MySQLレベルチェック確認
まず、現在実行されているクエリーを見てみましょう.
[ly@imysql.com(db)]> mysqladmin pr|grep -v Sleep
+----+----+----------+----+-------+-----+--------------+-----------------------------------------------------------------------------------------------+
| Id |User| Host   | db |Command|Time | State    | Info                                             |
+----+----+----------+----+-------+-----+--------------+-----------------------------------------------------------------------------------------------+
| 25 | x | 10.x:8519 | db | Query | 68 | Sending data | select max(Fvideoid) from (select Fvideoid from t where Fvideoid>404612 order by Fvideoid) t1 |
| 26 | x | 10.x:8520 | db | Query | 65 | Sending data | select max(Fvideoid) from (select Fvideoid from t where Fvideoid>484915 order by Fvideoid) t1 |
| 28 | x | 10.x:8522 | db | Query | 130 | Sending data | select max(Fvideoid) from (select Fvideoid from t where Fvideoid>404641 order by Fvideoid) t1 |
| 27 | x | 10.x:8521 | db | Query | 167 | Sending data | select max(Fvideoid) from (select Fvideoid from t where Fvideoid>324157 order by Fvideoid) t1 |
| 36 | x | 10.x:8727 | db | Query | 174 | Sending data | select max(Fvideoid) from (select Fvideoid from t where Fvideoid>324346 order by Fvideoid) t1 |

スロークエリがまだ完了していないことが多く、slow query logからもこのようなSQLが発生する頻度が高いことがわかります.
これは非常に非効率なSQLの書き方で、プライマリ・キー全体をスキャンする必要がありますが、実際には最大値を取得するだけで、slow query logから次のように見えます.
Rows_sent: 1 Rows_examined:5502460は毎回500万行以上のデータをスキャンしますが、最大値を1つ読むだけで、効率が非常に低いです.
分析を経て、このSQLは少し簡単な改造をして1桁のミリ秒級で完成することができて、もとは150-180秒で完成することができて、N次方を昇格させました.
改造の方法は,クエリ結果を逆順序で並べ替え,最初のレコードを取得すればよい.従来のやり方では、結果を順に並べ替えて、最後のレコードを取ります.
MySQLが持参したコマンドで調べることもできます
スローSQLとmysqlの現在のデータベース接続数の表示方法は次のとおりです.
  • command:queryは実行状態
  • command:sleepはアイドル状態
  • 現在の実行時間が50 msを超えるスローSQLのクエリ
    SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE TIME > 50 AND command = 'query' ORDER BY state DESC LIMIT 0,10000

    すべての接続を表示
    SHOW FULL PROCESSLIST
  • KILLから接続
  • KILL 256115

  • クエリこのデータベースに接続されているサーバのリクエスト数
    SELECT hostid,COUNT(hostid) FROM
    (SELECT SUBSTRING_INDEX(HOST,':',1) AS hostid FROM INFORMATION_SCHEMA.PROCESSLIST WHERE TIME > 5 AND command = 'sleep' LIMIT 0,10000) AS hosttable GROUP BY hostid ORDER BY COUNT(hostid) DESC

    ブロックされたプロセスを表示し、killを削除します.
    SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE command !='Sleep' LIMIT 100000
  • KILL 811478