MySQL道普請便り

第38回performance_schemaのthreadsテーブル

MySQLはOracle DatabaseやPostgreSQLなどのデータベースと違い、シングルプロセス・マルチスレッド型のデータベースです。Oracle DatabaseやPostgreSQLは、マルチプロセス型のデータベースです。このマルチプロセス型の場合は、OSのコマンドps等を使用することで、内部プロセスやユーザ接続プロセスなど実行されているプロセス名がわかります。

MySQLは、OSコマンドからでは1つのプロセスとして表示されるため内部スレッドを特定することは難しく、MySQLのテーブルやSHOW構文から確認することになります。今回はperformance_schemaのthreadsテーブルを使用して、MySQLの内部スレッドやユーザ接続スレッドを見てみましょう。

MySQLのスレッドの確認方法

一般的にMySQLのスレッド状態は、SHOW PROCESSLISTで表示することが多いと思います。このコマンドでわかるのは、フォアグラウンドで実行されているスレッドです。たとえば、ユーザ接続スレッドやIO_threadなどです。このSHOW PROCESSLISTinformation_schema.processlistテーブルは、同等のものを表示します。

運用ではこれらが示す情報が分かれば十分なのですが、MySQLでは複数の内部スレッドがバックグラウンドで稼働しており(以降、バックグラウンドスレッド⁠⁠、performance_schemathreadsテーブルはフォアグラウンドスレッドとバッググラウンドスレッド両方を確認することができます。バックグラウンドスレッドにはパージスレッドやページクリーナスレッドなどのInnoDB関連のスレッドがあります。

そして、SHOW PROCESSLISTは実行するとmutexロックを取得するため高負荷時は結果がなかなか返ってこないこともありますが、threadsテーブルへのアクセスはmutexロックを取得しないのでパフォーマンスの影響は少なくなります。

threadsテーブル

MySQL5.7.17を使用して、threadsテーブルカラムを見てみます。以下がカラムの情報です。

カラム名説明
THREAD_ID一意のスレッド識別子
NAME実行している処理
TYPEFOREGROUND または BACKGROUND
PROCESSLIST_IDSHOW PROCESSLISTIdカラムに表示される値
PROCESSLIST_USER接続元のユーザー名
PROCESSLIST_HOST接続元のホスト名
PROCESSLIST_DBスレッドのデフォルトのデータベース
PROCESSLIST_COMMAND実行しているコマンドの種類
PROCESSLIST_TIME現在の状態になってからの秒数
PROCESSLIST_STATESHOW PROCESSLISTStateカラムに表示される値
PROCESSLIST_INFO実行しているステートメント
PARENT_THREAD_ID親スレッドID
ROLE未使用
INSTRUMENTEDスレッドが統計情報を取得されるかどうか(YES/NO)
HISTORYスレッドの履歴イベントを記録するかどうか(YES/NO)
CONNECTION_TYPETCP/IPやSocketなどの接続タイプ
THREAD_OS_IDOSで管理されているスレッドID

threadsテーブルの中身を見てみましょう。

mysql> SELECT * FROM performance_schema.threads;
+-----------+----------------------------------------+------------+----------------+------------------+------------------+--------------------+---------------------+------------------+--------------------------------------------------------+------------------------------------------+------------------+------+--------------+---------+-----------------+--------------+
| THREAD_ID | NAME                                   | TYPE       | PROCESSLIST_ID | PROCESSLIST_USER | PROCESSLIST_HOST | PROCESSLIST_DB     | PROCESSLIST_COMMAND | PROCESSLIST_TIME | PROCESSLIST_STATE                                      | PROCESSLIST_INFO                         | PARENT_THREAD_ID | ROLE | INSTRUMENTED | HISTORY | CONNECTION_TYPE | THREAD_OS_ID |
+-----------+----------------------------------------+------------+----------------+------------------+------------------+--------------------+---------------------+------------------+--------------------------------------------------------+------------------------------------------+------------------+------+--------------+---------+-----------------+--------------+
|         1 | thread/sql/main                        | BACKGROUND |           NULL | NULL             | NULL             | NULL               | NULL                |            11142 | NULL                                                   | NULL                                     |             NULL | NULL | YES          | YES     | NULL            |       142210 |
|         2 | thread/sql/thread_timer_notifier       | BACKGROUND |           NULL | NULL             | NULL             | NULL               | NULL                |             NULL | NULL                                                   | NULL                                     |                1 | NULL | YES          | YES     | NULL            |       142211 |
|         3 | thread/innodb/io_ibuf_thread           | BACKGROUND |           NULL | NULL             | NULL             | NULL               | NULL                |             NULL | NULL
|        19 | thread/innodb/srv_purge_thread         | BACKGROUND |           NULL | NULL             | NULL             | NULL               | NULL                |             NULL | NULL                                                   | NULL                                     |             NULL | NULL | YES          | YES     | NULL            |       142231 |
    (一部割愛)
|        32 | thread/sql/slave_io                    | FOREGROUND |              7 | root             | localhost        | NULL               | Connect             |            11121 | Waiting for master to send event                       | NULL                                     |               31 | NULL | YES          | YES     | NULL            |       142769 |
|        34 | thread/sql/one_connection              | FOREGROUND |              9 | root             | localhost        | NULL               | Sleep               |             9483 | NULL                                                   | NULL                                     |             NULL | NULL | YES          | YES     | Socket          |       142721 |
|        38 | thread/sql/slave_sql                   | FOREGROUND |             13 | root             | localhost        | NULL               | Connect             |              159 | Slave has read all relay log; waiting for more updates | NULL                                     |               37 | NULL | YES          | YES     | NULL            |       152871 |
+-----------+----------------------------------------+------------+----------------+------------------+------------------+--------------------+---------------------+------------------+--------------------------------------------------------+------------------------------------------+------------------+------+--------------+---------+-----------------+--------------+

NAMEカラムは実行している処理を表し、'/' 文字で区切られた一連のコンポーネントから構成されます。たとえば、thread/sql/slave_ioはIO_thread、thread/sql/slave_sqlはsql_threadでthread/sql/one_connectionはユーザ接続スレッドです。

PROCESSLIST_*のカラムはSHOW PROCESSLISTに表示されている内容で、フォアグラウンドスレッドの行には値がありますが、バックグラウンドスレッドは基本的にNULLが多いです。

SHOW PROCESSLISTIdカラムはTHREAD_IDカラムではなく、PROCESSLIST_IDカラムと紐付いています。

INSTRUMENTEDカラムとHISTORYカラムはフォアグラウンドスレッドの場合、setup_actorsテーブルのユーザー名とホスト名に一致していればYESとなり、バックグラウンドプロセスの場合はデフォルトYESです。

setup_actorsテーブルはフォアグラウンドスレッドのモニタリングを有効にしたいユーザー名とホスト名を格納します。デフォルトではすべてのユーザ名とホスト名に対して有効です。

また、HISTORYカラムとCONNECTION_TYPEカラムはMySQL5.7.8から、THREAD_OS_IDカラムはMySQL5.7.9から追加されました。

gdbを使用して特定のスレッドにアタッチする

gdbとはLinuxで使用されるデバッガです。さまざまな言語に対してプロセスの状態を見たり、変数の中身を確認することができます。MySQLではクラッシュ時に吐かれるコアファイルの分析に用いたり、稼働中のMySQLのPIDを指定して実行することでMySQLにアタッチします。アタッチするとMySQLはgdbによって制御させるため実行が停止します。デタッチすることで実行が開始されます。

そして、threadsテーブルにMySQL5.7.9から追加されたTHREAD_OS_IDカラムの値を使用して特定のスレッドのみに対してアタッチすることもできます。たとえば、sql_threadにアタッチしてみます。ただし、この内容は本番環境では実行しないでください。あくまでも検証を目的としたものです。

sql_threadのOSIDを確認する

GTIDを使用したマスタースレーブ構成のMySQLを用意して、スレーブに対して実行します。前述の通り、NAMEカラムがthread/sql/slave_sqlのものがsql_threadなので、条件を指定してTHREAD_OS_IDを取得します。

mysql> SELECT thread_os_id FROM performance_schema.threads WHERE name ='thread/sql/slave_sql';
+--------------+
| thread_os_id |
+--------------+
|       142770 |
+--------------+

IDが142770であることがわかりました。そのIDに対してgdbを実行します。

# gdb -p 142770
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Attaching to process 142770

warning: process 142770 is a cloned process
(一部割愛)
(gdb)

この状態でsql_threadのみ実行が停止しています。マスターに対して更新をかけ、スレーブのSHOW SLAVE STATUSを確認してみます。

mysql> show slave status\G
(一部割愛)
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
        Seconds_Behind_Master: 0
Retrieved_Gtid_Set: b93409b3-d7d6-11e6-9ad9-fa163e3796a9:1-303
 Executed_Gtid_Set: b93409b3-d7d6-11e6-9ad9-fa163e3796a9:1-4

このように、Slave_SQL_RunningはYESでSeconds_Behind_Masterは0のため問題ないように思えますが、Retrieved_Gtid_Setは1-303と進んでもExecuted_Gtid_Set1-4と、適用されていないことがわかります。このように特定のスレッドの実行を停止させることが可能です。sql_threadはデタッチすることで実行が再開されます。ちなみに、sql_threadを停止させるにはSTOP SLAVE SQL_THREADコマンドで可能なため、このような方法は使うことないと思います。

まとめ

今回は、performance_schemaのthreadsテーブルとthreadsテーブルからIDを取得して、gdbで特定のスレッドにアタッチする方法について紹介しました。実運用では、SHOW PROCESSLISTの結果が返ってこなかったり、詳細なスレッド情報を確認したい場合などは、このテーブルを参照すれば良いでしょう。

おすすめ記事

記事・ニュース一覧