Weitere ähnliche Inhalte Ähnlich wie DTraceによるMySQL解析ことはじめ (20) Mehr von Mikiya Okuno (20) Kürzlich hochgeladen (12) DTraceによるMySQL解析ことはじめ1. DTrace で MySQL を斬る!
〜 DTrace による MySQL 解析ことはじめ 〜
奥野 幹也
@nippondanji
mikiya (dot) okuno (at) gmail (dot) com
2. 自己紹介
●
今日は個人として来ています。
– http://nippondanji.blogspot.com/
– http://www.google.com/profiles/mikiya.okuno
●
現職は MySQL サポートエンジニア。
– 2000 年にサン・マイクロシステムズ入社
– 2007 年に MySQL KK へ転職
– 気付くとまたサン・マイクロシステムズに
– オラクル・コーポレーションに・・・
3. MySQL について
●
オープンソースのリレーショナル・データベー
ス・マネージメント・システム
●
MySQL AB => Sun Microsystems => Oracle に
よって開発。
●
Web 開発においては圧倒的なシェア
– PHP/Perl/Java/Ruby/C/C++/ODBC...
●
使い易く、安定して、高速に動作するのがウリ
5. MySQL の特徴
●
ANSI SQL 標準に準拠(一部の文法を除 ● UNION
く。) ●
ビュー
●
種々のプラットフォームをサポート ●
サブクエリ
( Windows 、 Linux 、 Mac 、各種 UNIX 系 ● INFORMATION_SCHEMA
OS ) ●
SSL による通信
●
ストレージエンジンによりデータを格納す ●
Unicode をはじめとした各種文字コードの
るレイヤーを仮想化 サポート
●
ACID 準拠のトランザクション ●
全文検索
●
XA トランザクション ●
タイムゾーンのサポート
●
非同期 Master/Slave 型レプリケーション ●
多種多様な開発言語のサポート( C 、 C+
●
水平パーティショニング + 、 Java 、 Perl 、 PHP 、 Python 、 Ruby
( Range 、 List 、 Hash 、 Key ) など)
●
ストアドプロシージャ、ストアドファンク ●
ODBC による接続のサポート
ション、トリガ
6. MySQL 構造の特徴
●
モノリシックカーネル
●
シングルプロセス・マルチスレッド
●
1 セッション= 1 スレッド
●
ストレージエンジン API による仮想化
●
プラグイン API
●
GNU Bison による Lexical Scanner
●
ソースコードは C/C++ 混在( 100 万行程度)
7. MySQL の仕組み
クライアント クライアント クライアント
Java PHP ODBC
コネクション コネクション コネクション
スレッド スレッド スレッド
SQL の解析と最
適化は共通
パーサー・オプティマイザ・アクセス管理 等
ストレージエンジン API データの格納や
MyISAM InnoDB MySQL アクセス方法は
Cluster ストレージエン
テーブル
table_name.MYI
スペース
ジンごとに違う
table_name.MYD NDB
ログファイル API
MySQL サーバ
データノード
データノード
データノード
データノード
8. MySQL の構造を知る!
●
Web ページ
– http://forge.mysql.com/wiki/MySQL_Internals
●
書籍
– 詳解 MySQL ( Understanding MySQL
Internals )
– Expert MySQL
– MySQL データベース構築バイブル
●
ソースコード!!
9. ソースコードを入手!
● http://dev.mysql.com/downloads/
● bzr branch lp:mysql-server/5.1 mysql-5.1
●
sql/mysqld.cc ... main() 関数があるよ!
●
sql/sql_parse.cc ... リクエストの入り口
●
sql/sql_yacc.yy ... SQL パーサー この辺りから
●
sql/handler.cc ... ストレージエンジン API 覗いてみよう!
●
sql/log.cc ... ログ関係
●
sql/log_event.cc ... バイナリログ
●
sql/sql_show.cc ... SHOW コマンドと I_S
●
sql/slave.cc ... レプリケーションスレーブ
●
sql/item*cc ... データ型と関数
●
sql/sql_base.cc, sql/sql_class.cc ... 基本的なデータ型等
●
storage/innodb ... InnoDB の実装
●
storage/myisam ... MyISAM の実装
●mysys/* ... MySQL Core API
10. DTrace!!
●
Solaris 10 で搭載された機能。
– Solaris/Mac OS X/FreeBSD で利用可能
●
カーネル / ユーザープロセスをトレース。
●
プローブと呼ばれる観測点を対象のプログラム
に動的に埋め込む。
●
プローブの種類に応じたプロバイダ。
●
D 言語と呼ばれるプログラムで操作。
– 参考: D 言語基本文法最速マスター( DTrace のほう)
– http://nippondanji.blogspot.com/2010/02/ddtrace.html
11. DTrace 動作イメージ
プロバイダに指示を出したり
ユーザープロセス 情報を表示したり
( mysqld など)
dtrace コマンド
プロ
ーブ
ユーザー空間 各種情報
カーネル空間 Fire
有効化
DTrace モジュール
プロバイダ プロ
ーブ
モジュール
12. プロバイダの種類
Provider名 Probeの場所 Providerのシンボル
FBT - function カーネル内における関数の fbt
boundary tracing 呼び出しとリターン。
Systrace システムコールの呼び出し syscall
とリターン。
SDT - statically ソースコードにおいて指定さ sdtまたはコンパイル時に指
defined tracing れた任意の場所。(カーネ 定
ル内)
PID ユーザープロセスにおける pid{pid}
関数の呼び出しとリターン。 (pid1234のように指定する)
Fasttrap ソースコードにおいて指定さ コンパイル時に指定
れた任意の場所。(ユー
ザープロセス内)
dtrace トレースの開始と終了、およ BEGIN/END/ERROR
び例外発生時。
profiling 一定期間ごと。 profile-n/tick-n
(nはインターバル)
14. プローブの書式
●
プロバイダ名 : モジュール名 : 関数名 : プロー
ブ名
– pid プロバイダの場合、 pid{ プロセス ID} とい
う書式になる。例 ) pid123
– C++ の関数名を指定するにはワイルドカード
( * )が便利。
15. mysqld 内に設置可能なプローブ
● pid
– 関数の entry C++ の関数名に注意
It's mangled!!
– 関数の return
– 関数オフセット
– 書式 ) pid123
● Fasttrap
– MySQL 5.4 で追加!!
– 書式 ) mysql123
16. 述語の書式
●
評価出来る式なら何でも OK
– 例 ) execname == "mysqld"
●
条件分岐がない代わりに述語で Fire するかどう
かをコントロール。
17. アクション
●
情報の出力や変数への代入。
●
セミコロン区切りで必要な数を列挙。
●
情報の出力例。
– trace( 式 )
– tracemem(address, size);
– printf(" フォーマット ", arg1, arg2, ...);
– ustack(); jstack(); stack();
etc
18. 変数の種類
●
スカラー変数… argname
– グローバルなスコープを持つ
●
スレッドローカル変数… self->argname
– 同一スレッドだけからアクセス可能
●
節固有変数… this->argname
– プローブが Fire している間だけ利用可能
●
組み込み変数…後述 ユーザープロセス
●
外部変数… `argname には使えない。
19. 組み込み変数
●
arg0 ... arg9 ・・・プローブに対する引数の最初の 10 個(数値型で取得)
●
cwd ・・・カレントワーキングディレクトリ
●
errno ・・・直前のシステムコールによって返されたエラーの値
●
execname ・・・実行プログラム名
●
uid ・・・実行中のプロセスの実効ユーザー ID
●
gid ・・・実行中のプロセスの実効グループ ID
●
pid ・・・実行中のプロセス ID
●
ppid ・・・実行中のプロセスの親プロセス ID
●
tid ・・・現在のスレッドのスレッド ID
大切な情報源!!
●
probeprov ・・・プロバイダ名
●
probemod ・・・モジュール名
●
probefunc ・・・関数名
●
probename ・・・プローブ名
●
timestamp ・・・タイムスタンプ
●
walltimestamp ・・・ 1970 年 1 月 1 日 UTC からの経過時間。単位はナノ秒。
20. MySQL 5.4 で追加されたプローブ
●
include/probes_mysql.d を見よ! Fasttrap!
connection-start(unsigned long conn_id, char *user, char *host);
connection-done(int status, unsigned long conn_id);
command-start(unsigned long conn_id, int command, char *user, char *host);
command-done(int status);
query-start(char *query, unsigned long connid, char *db_name, char *user,
char *host, int exec_type);
query-done(int status);
query-parse-start(char *query);
query-parse-done(int status);
query-cache-hit(char *query, unsigned long rows);
query-cache-miss(char *query);
query-exec-start(char *query, unsigned long connid, char *db_name,
char *user, char *host, int exec_type);
query-exec-done(int status);
insert-row-start(char *db, char *table);
insert-row-done(int status);
update-row-start(char *db, char *table);
:
:
21. プローブを設置し易い関数
●
DTrace の制約として、外部変数はユーザープ
ロセスをサポートしていない。
– 引数が重要な情報源!
– mysql_parse() 関数 ... 第 2 引数が SQL 文
●
エラー発生時に Fire する。
– vprint_msg_to_log() ... エラーログへの書
き込み
– my_error() ... クライアントへエラー送信
– my_print_error() ... シンタックスエラー
22. 例 1) SQL 文を抽出
pid$target::*mysql_parse*:entry
{
trace(copyinstr(arg1));
}
23. 例 2) メモリ不足の原因
pid$target::*mysql_parse*:entry
{
self->q = 1;
self->qstr = copyinstr(arg1);
}
pid$target::*mysql_parse*:entry
/ self->q /
{
self->q = 0;
self->qstr = 0;
}
pid$target::malloc:return
/ errno == ENOMEM /
{
printf("=== Memory allocation error at %Y ===n", walltimestamp);
ustack();
}
pid$target::malloc:return
/ errno == ENOMEM && self->q /
{
printf("QUERY: %sn", self->qstr);
}
24. 例 3) エラーメッセージを追跡
pid$target::*mysql_parse*:entry
{
self->q = 1;
self->qstr = copyinstr(arg1);
}
pid$target::*mysql_parse*:return
/ self->q /
{
self->q = 0;
self->qstr = copyinstr(arg1);
}
pid$target::*my_error:entry
/ self->q /
{
printf("Query generated an error (errno = %d): %sn",
arg0, self->qstr);
ustack();
}
pid$target::*my_printf_error:entry
/ self->q /
{
printf("Syntax error: %sn", self->qstr);
}
25. 例 4) クエリキャッシュのヒット率
mysql$target:::query-cache-hit
{
hit++;
@qhit["rows per query when qcache hit"] = quantize(arg1);
}
mysql$target:::query-cache-miss
{
miss++;
@qmiss[copyinstr(arg0)] = count();
}
tick-5sec
/ hit != 0 || miss != 0 /
{
printf("ratio: %u (%u / %u)", 100 * hit / (hit+miss), hit, hit+miss);
}
tick-5sec
/ hit == 0 && miss == 0 /
{
printf("ratio: NULL");
}
tick-5sec
{
total_hit += hit;
total_miss += miss;
hit = miss = 0;
}
26. 例 5) 1000 行以上のソートを検出
#!/usr/sbin/dtrace -s
BEGIN
{
printf("Hit Ctrl+C to exit.n");
}
mysql$target:::filesort-start
{
self->sorting = 1;
self->db = arg0 == 0 ? "NULL" : copyinstr(arg0);
self->table = copyinstr(arg1);
}
mysql$target:::filesort-done
/self->sorting && arg1 > 1000/
{
self->sorting=0;
printf("DB: %s, Table: %s, Rows: %u",
self->db, self->table, arg1);
}
27. 例 5) 1000 行以上のソートを検出
#!/usr/sbin/dtrace -s
BEGIN
{
printf("Hit Ctrl+C to exit.n");
}
mysql$target:::filesort-start
{
self->sorting = 1;
self->db = arg0 == 0 ? "NULL" : copyinstr(arg0);
self->table = copyinstr(arg1);
}
mysql$target:::filesort-done
/self->sorting && arg1 > 1000/
{
self->sorting=0;
printf("DB: %s, Table: %s, Rows: %u",
self->db, self->table, arg1);
}
28. 例 6) テーブルごとのソート統計
mysql$target:::filesort-start
{
self->sorting = 1;
self->db = arg0 == 0 ? "NULL" :
copyinstr(arg0);
self->table = copyinstr(arg1);
}
mysql$target:::filesort-done
/self->sorting/
{
self->sorting=0;
@sorts[self->db, self->table] = sum(arg1);
}
29. 例 7) ソート中断の原因
#!/usr/sbin/dtrace -s
pid$target::*mysql_parse*:entry
{
self->q = 1;
self->qstr = copyinstr(arg1);
}
pid$target::*mysql_parse*:return
/ self->q /
{
self->q = 0;
self->qstr = 0;
}
mysql$target:::filesort-done
/ self->q && arg0 /
{
printf("nnABORTED QUERY: %sn", self->qstr);
ustack();
}
30. DTrace Toolkit
●
DTrace を使ったユーティリティ群
– http://hub.opensolaris.org/bin/view/Community+
Group+dtrace/dtracetoolkit
– http://nippondanji.blogspot.com/2007/07/dtrace.
html
●
DTrace を知らなくても利用可能
●
Mac OS X ではデフォルトでインストール
– grep -I -m 1 dtrace /usr/bin/*
31. DTrace Toolkit つづき
●
dappprof ... ユーザープロセスをプロファイリングします。
●
dapptrace ... ユーザープロセスの関数呼び出しを追跡。
●
dtruss ... ユーザープロセスのシステムコール呼び出しを追跡。
●
errinfo ... システムコール呼び出しにおいてエラーの発生を追跡。
●
execsnoop ... プロセスの実行開始を追跡。意図しないプログラムが実行さ
れていないかどうかを確認することが可能。
●
iotop ... システム全体で、 I/O 帯域をたくさん消費しているプロセスをリス
トアップ。 IO の帯域を消費しているプロセス特定に便利。
●
kill.d ... プロセスにシグナルが送られた時にその送り主と送り先に関する情
報を記録。
●
opensnoop ... ファイルが open された際に情報を出力。
32. デモで利用したもの
● Random Query Generator
– http://forge.mysql.com/wiki/Random_Query_Ge
nerator
● Example DBs
– http://dev.mysql.com/doc/index-other.html
● MySQL Sand Box
– http://mysqlsandbox.net/
33. 宣伝!!
●
著書: MySQL エキスパートトラブルシュー
ティングガイド(仮)/技術評論社
– 様々な角度から MySQL のトラブルを解析するのに役立つ書
籍です。ぜひ安心な DBA 生活のお供に一冊どうぞ。
– 第一章: MySQL の概要
– 第二章:開発時における問題
– 第三章: MySQL の状態を見る。
– 第四章: DTrace
– 第五章:運用中に起きる諸問題。
– 第六章:堅牢な運用を実現するために
– 第七章:ソースコードのビルド