InnoDBテーブルを持つデータベースを実行している(ほとんどの場合)MySQL 5.6.20のインスタンスは、すべてのINSERT、UPDATE、およびDELETEクエリが「クエリ終了」状態のままで、1〜4分間、すべての更新操作で時々停止します。これは明らかに最も不幸なことです。 MySQLのスロークエリログは、非常に簡単なクエリ時間でさえ、非常に簡単なクエリをログに記録しています。何百ものクエリが、失速が解決された時点に対応する同じタイムスタンプで記録されています。
# Query_time: 101.743589 Lock_time: 0.000437 Rows_sent: 0 Rows_examined: 0
SET timestamp=1409573952;
INSERT INTO sessions (redirect_login2, data, hostname, fk_users_primary, fk_users, id_sessions, timestamp) VALUES (NULL, NULL, '192.168.10.151', NULL, 'anonymous', '64ef367018099de4d4183ffa3bc0848a', '1409573850');
そして、デバイス統計は、この時間枠での過度のI/O負荷ではありませんが、増加を示しています(この場合、更新は上記のステートメントのタイムスタンプに従って14:17:30-14:19:12で停止していました):
# sar -d
[...]
02:15:01 PM DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util
02:16:01 PM dev8-0 41.53 207.43 1227.51 34.55 0.34 8.28 3.89 16.15
02:17:01 PM dev8-0 59.41 137.71 2240.32 40.02 0.39 6.53 4.04 24.00
02:18:01 PM dev8-0 122.08 2816.99 1633.44 36.45 3.84 31.46 1.21 2.88
02:19:01 PM dev8-0 253.29 5559.84 3888.03 37.30 6.61 26.08 1.85 6.73
02:20:01 PM dev8-0 101.74 1391.92 2786.41 41.07 1.69 16.57 3.55 36.17
[...]
# sar
[...]
02:15:01 PM CPU %user %Nice %system %iowait %steal %idle
02:16:01 PM all 15.99 0.00 12.49 2.08 0.00 69.44
02:17:01 PM all 13.67 0.00 9.45 3.15 0.00 73.73
02:18:01 PM all 10.64 0.00 6.26 11.65 0.00 71.45
02:19:01 PM all 3.83 0.00 2.42 24.84 0.00 68.91
02:20:01 PM all 20.95 0.00 15.14 6.83 0.00 57.07
たいていの場合、mysqlのスローログで、最も古いクエリの停止が、VARCHAR主キーと全文検索インデックスを備えた大規模な(約10 M行)テーブルへのINSERTであることに気付きます。
CREATE TABLE `files` (
`id_files` varchar(32) NOT NULL DEFAULT '',
`filename` varchar(100) NOT NULL DEFAULT '',
`content` text,
PRIMARY KEY (`id_files`),
KEY `filename` (`filename`),
FULLTEXT KEY `content` (`content`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
さらなる調査(つまり、SHOW ENGINE INNODB STATUS)は、それが確かにalwaysがストールを引き起こしているフルテキストインデックスを使用するテーブルの更新であることを示しています。 「SHOW ENGINE INNODB STATUS」のそれぞれのTRANSACTIONSセクションには、最も古い実行中のトランザクションに関する次の2つのようなエントリがあります。
---TRANSACTION 162269409, ACTIVE 122 sec doing SYNC index
6 lock struct(s), heap size 1184, 0 row lock(s), undo log entries 19942
TABLE LOCK table "vw"."FTS_000000000000224a_00000000000036b9_INDEX_1" trx id 162269409 lock mode IX
TABLE LOCK table "vw"."FTS_000000000000224a_00000000000036b9_INDEX_2" trx id 162269409 lock mode IX
TABLE LOCK table "vw"."FTS_000000000000224a_00000000000036b9_INDEX_3" trx id 162269409 lock mode IX
TABLE LOCK table "vw"."FTS_000000000000224a_00000000000036b9_INDEX_4" trx id 162269409 lock mode IX
TABLE LOCK table "vw"."FTS_000000000000224a_00000000000036b9_INDEX_5" trx id 162269409 lock mode IX
TABLE LOCK table "vw"."FTS_000000000000224a_00000000000036b9_INDEX_6" trx id 162269409 lock mode IX
---TRANSACTION 162269408, ACTIVE (PREPARED) 122 sec committing
mysql tables in use 1, locked 1
1 lock struct(s), heap size 360, 0 row lock(s), undo log entries 1
MySQL thread id 165998, OS thread handle 0x7fe0e239c700, query id 91208956 192.168.10.153 root query end
INSERT INTO files (id_files, filename, content) VALUES ('f19e63340fad44841580c0371bc51434', '1237716_File_70380a686effd6b66592bb5eeb3d9b06.doc', '[...]
TABLE LOCK table `vw`.`files` trx id 162269408 lock mode IX
そこで、重いフルテキストインデックスアクションが実行されています(doing SYNC index
)stoppingALL SUBSEQUENTが[〜#〜] any [〜#〜]テーブルに更新されます。
ログから、undo log entries
のdoing SYNC index
番号が20,000に到達するまで約150/sで進み、その時点で操作が完了するように見えます。
この特定のテーブルのFTSサイズは非常に印象的です。
# du -c FTS_000000000000224a_00000000000036b9_*
614404 FTS_000000000000224a_00000000000036b9_INDEX_1.ibd
2478084 FTS_000000000000224a_00000000000036b9_INDEX_2.ibd
1576964 FTS_000000000000224a_00000000000036b9_INDEX_3.ibd
1630212 FTS_000000000000224a_00000000000036b9_INDEX_4.ibd
1978372 FTS_000000000000224a_00000000000036b9_INDEX_5.ibd
1159172 FTS_000000000000224a_00000000000036b9_INDEX_6.ibd
9437208 total
この問題は、次のようにFTSデータサイズが大幅に少ないテーブルでもトリガーされます。
# du -c FTS_0000000000002467_0000000000003a21_INDEX*
49156 FTS_0000000000002467_0000000000003a21_INDEX_1.ibd
225284 FTS_0000000000002467_0000000000003a21_INDEX_2.ibd
147460 FTS_0000000000002467_0000000000003a21_INDEX_3.ibd
135172 FTS_0000000000002467_0000000000003a21_INDEX_4.ibd
155652 FTS_0000000000002467_0000000000003a21_INDEX_5.ibd
106500 FTS_0000000000002467_0000000000003a21_INDEX_6.ibd
819224 total
これらの場合のストールの時間もほぼ同じです。私は bugs.mysql.comのバグ を開いたので、開発者はこれを調べることができました。
ストールの性質により、最初にログフラッシュアクティビティが原因であると疑われました MySQL 5.5でのログフラッシュパフォーマンスの問題に関するこのPerconaの記事 は非常に類似した症状を説明していますが、さらに発生するとINSERT操作がこのデータベースの単一のMyISAMテーブルもストールの影響を受けるため、これはInnoDBのみの問題のようには見えません。
それでも、10秒ごとにLog sequence number
の "LOG"セクション出力からPages flushed up to
およびSHOW ENGINE INNODB STATUS
の値を追跡することにしました。 2つの値の間の広がりが減少しているため、ストール中にフラッシュアクティビティが継続しているように見えます。
Mon Sep 1 14:17:08 CEST 2014 LSN: 263992263703, Pages flushed: 263973405075, Difference: 18416 K
Mon Sep 1 14:17:19 CEST 2014 LSN: 263992826715, Pages flushed: 263973811282, Difference: 18569 K
Mon Sep 1 14:17:29 CEST 2014 LSN: 263993160647, Pages flushed: 263974544320, Difference: 18180 K
Mon Sep 1 14:17:39 CEST 2014 LSN: 263993539171, Pages flushed: 263974784191, Difference: 18315 K
Mon Sep 1 14:17:49 CEST 2014 LSN: 263993785507, Pages flushed: 263975990474, Difference: 17377 K
Mon Sep 1 14:17:59 CEST 2014 LSN: 263994298172, Pages flushed: 263976855227, Difference: 17034 K
Mon Sep 1 14:18:09 CEST 2014 LSN: 263994670794, Pages flushed: 263978062309, Difference: 16219 K
Mon Sep 1 14:18:19 CEST 2014 LSN: 263995014722, Pages flushed: 263983319652, Difference: 11420 K
Mon Sep 1 14:18:30 CEST 2014 LSN: 263995404674, Pages flushed: 263986138726, Difference: 9048 K
Mon Sep 1 14:18:40 CEST 2014 LSN: 263995718244, Pages flushed: 263988558036, Difference: 6992 K
Mon Sep 1 14:18:50 CEST 2014 LSN: 263996129424, Pages flushed: 263988808179, Difference: 7149 K
Mon Sep 1 14:19:00 CEST 2014 LSN: 263996517064, Pages flushed: 263992009344, Difference: 4402 K
Mon Sep 1 14:19:11 CEST 2014 LSN: 263996979188, Pages flushed: 263993364509, Difference: 3529 K
Mon Sep 1 14:19:21 CEST 2014 LSN: 263998880477, Pages flushed: 263993558842, Difference: 5196 K
Mon Sep 1 14:19:31 CEST 2014 LSN: 264001013381, Pages flushed: 263993568285, Difference: 7270 K
Mon Sep 1 14:19:41 CEST 2014 LSN: 264001933489, Pages flushed: 263993578961, Difference: 8158 K
Mon Sep 1 14:19:51 CEST 2014 LSN: 264004225438, Pages flushed: 263993585459, Difference: 10390 K
そして14:19:11にスプレッドが最小に達したので、ここでフラッシングアクティビティが停止したように見え、ストールの終わりとちょうど一致しています。しかし、これらの点により、私はInnoDBログのフラッシュを原因として却下しました。
innodb_max_dirty_pages_pct
充填レベルで始まる「非同期の」フラッシュフェーズがあります-私は見ていません(数字は([Log Sequence Number] - [Pages flushed up to]) / 1024
からSHOW ENGINE INNODB STATUS
まで)
この問題はinnodb_adaptive_flushing_lwm=1
を設定することで多少緩和され、ページクリーナーが以前よりも多くの作業を実行するように強制されます。
error.log
には、ストールと一致するエントリがありません。 SHOW INNODB STATUS
約24時間の操作後の抜粋は次のようになります。
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 789330
OS WAIT ARRAY INFO: signal count 1424848
Mutex spin waits 269678, rounds 3114657, OS waits 65965
RW-shared spins 941620, rounds 20437223, OS waits 442474
RW-excl spins 451007, rounds 13254440, OS waits 215151
Spin rounds per wait: 11.55 mutex, 21.70 RW-shared, 29.39 RW-excl
------------------------
LATEST DETECTED DEADLOCK
------------------------
2014-09-03 10:33:55 7fe0e2e44700
[...]
--------
FILE I/O
--------
[...]
932635 OS file reads, 2117126 OS file writes, 1193633 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 17.00 writes/s, 1.20 fsyncs/s
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
0 read views open inside InnoDB
Main thread process no. 54745, id 140604272338688, state: sleeping
Number of rows inserted 528904, updated 1596758, deleted 99860, read 3325217158
5.40 inserts/s, 10.40 updates/s, 0.00 deletes/s, 122969.21 reads/s
したがって、はい、データベースにはデッドロックがありますが、デッドロックは非常にまれです(「最新」は統計が読み込まれる前の約11時間で処理されました)。
「SEMAPHORES」セクションの値を一定期間追跡しました。特に、通常の操作の状況とストール中に(MySQLサーバーのプロセスリストをチェックし、いくつかの診断コマンドを実行するためにいくつかの診断コマンドを実行する小さなスクリプトを書きました)明らかなストールの)。数値はさまざまな時間枠で取得されているため、結果をイベント/秒に正規化しています。
normal stall
1h avg 1m avg
OS WAIT ARRAY INFO:
reservation count 5,74 1,00
signal count 24,43 3,17
Mutex spin waits 1,32 5,67
rounds 8,33 25,85
OS waits 0,16 0,43
RW-shared spins 9,52 0,76
rounds 140,73 13,39
OS waits 2,60 0,27
RW-excl spins 6,36 1,08
rounds 178,42 16,51
OS waits 2,38 0,20
ここに何が表示されているのか、よくわかりません。ほとんどの数値は桁違いに減少しています。おそらく更新操作が停止したためですが、「Mutexスピン待機」と「Mutexスピンラウンド」はどちらも4倍に増加しています。
これをさらに調査すると、ミューテックス(SHOW ENGINE INNODB MUTEX
)のリストには、通常の操作とストール中の両方で、最大480のミューテックスエントリがリストされています。 innodb_status_output_locks
を有効にして、詳細が表示されるかどうかを確認しました。
(私は明確な成功なしにそれらのほとんどをいじりました):
mysql> show global variables where variable_name like 'innodb_adaptive_flush%';
+------------------------------+-------+
| Variable_name | Value |
+------------------------------+-------+
| innodb_adaptive_flushing | ON |
| innodb_adaptive_flushing_lwm | 1 |
+------------------------------+-------+
mysql> show global variables where variable_name like 'innodb_max_dirty_pages_pct%';
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| innodb_max_dirty_pages_pct | 50 |
| innodb_max_dirty_pages_pct_lwm | 10 |
+--------------------------------+-------+
mysql> show global variables where variable_name like 'innodb_log_%';
+-----------------------------+-----------+
| Variable_name | Value |
+-----------------------------+-----------+
| innodb_log_buffer_size | 8388608 |
| innodb_log_compressed_pages | ON |
| innodb_log_file_size | 268435456 |
| innodb_log_files_in_group | 2 |
| innodb_log_group_home_dir | ./ |
+-----------------------------+-----------+
mysql> show global variables where variable_name like 'innodb_double%';
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| innodb_doublewrite | ON |
+--------------------+-------+
mysql> show global variables where variable_name like 'innodb_buffer_pool%';
+-------------------------------------+----------------+
| Variable_name | Value |
+-------------------------------------+----------------+
| innodb_buffer_pool_dump_at_shutdown | OFF |
| innodb_buffer_pool_dump_now | OFF |
| innodb_buffer_pool_filename | ib_buffer_pool |
| innodb_buffer_pool_instances | 8 |
| innodb_buffer_pool_load_abort | OFF |
| innodb_buffer_pool_load_at_startup | OFF |
| innodb_buffer_pool_load_now | OFF |
| innodb_buffer_pool_size | 29360128000 |
+-------------------------------------+----------------+
mysql> show global variables where variable_name like 'innodb_io_capacity%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| innodb_io_capacity | 200 |
| innodb_io_capacity_max | 2000 |
+------------------------+-------+
mysql> show global variables where variable_name like 'innodb_lru_scan_depth%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_lru_scan_depth | 1024 |
+-----------------------+-------+
SET GLOBAL query_cache_size=0
によるクエリキャッシュの無効化innodb_log_buffer_size
を128Mに増加innodb_adaptive_flushing
、innodb_max_dirty_pages_pct
、およびそれぞれの_lwm
の値をいじる(変更前はデフォルトに設定されていた)innodb_io_capacity
(2000)およびinnodb_io_capacity_max
(4000)の増加innodb_flush_log_at_trx_commit = 2
noop
またはdeadline
に設定するWindowsで実行されているバージョン5.6.12と5.6.16の2台のサーバーで、それぞれにスレーブのペアがある同じ問題が発生していました。私たちはあなたのように、ほぼ2か月間困惑しました。
ソリューション:
set global binlog_order_commits = 0;
変数の詳細については、 https://dev.mysql.com/doc/refman/5.6/en/replication-options-binary-log.html#sysvar_binlog_order_commits を参照してください。
説明:
InnoDBフルテキストは、ディスク上の実際のフルテキストインデックスに適用する必要がある変更を含むキャッシュ(デフォルトではサイズが8M)を使用します。
キャッシュがいっぱいになると、キャッシュに含まれていたデータをマージする作業を実行するために2つのトランザクションが作成されます。これは大量のランダムIOになる傾向があるため、フルテキストインデックス全体をロードできない場合バッファプール、それは長くて遅いトランザクションです。
Binlog_order_commitsをtrueに設定すると、長期実行のfts_sync_indexトランザクションの後に開始された挿入と更新を含むすべてのトランザクションは、コミットする前に完了するまで待機する必要があります。
これは、バイナリログが有効な場合にのみ問題になります
ログフラッシュの歴史的な問題と、適応フラッシュのしくみについて説明してみましょう。
REDOログは リングバッファ の設計です。これらは常に書き込まれ(通常の操作では決して読み取られません)、クラッシュからの回復を提供します。リングバッファーは、タンクのトレッドに似ていると表現します。
InnoDBは、まだディスク上で変更されていない変更が含まれている場合、ログファイルスペースを上書きできません。したがって、歴史的には、何が起こるかというと、InnoDBは毎秒一定量の作業を試行することになります(innodb_io_capacity
)そしてそれが十分でない場合、完全なログ領域に到達します。失速は、突然のスペースを解放するために同期フラッシュが発生する必要があり、通常はバックグラウンドタスクが突然フォアグラウンドになるために発生します。
この問題に対処するために、適応フラッシュが導入されました。 at 10%(デフォルト) ログ領域が消費されると、バックグラウンド作業は徐々に積極的になります。これの目的は、突然の失速ではなく、パフォーマンスの「短期的な低下」がより多くなることです。
アダプティブフラッシュとは別に、ワークロードに十分なログスペースを確保することが重要です(innodb_log_file_size
4Gの値は非常に安全になりました)、そしてinnodb_io_capacity
およびinnodb_lru_scan_depth
は現実的な値に設定されています。アダプティブフラッシング10%innodb_adaptive_flushing_lwm
はあまり拡張しないもので、スペース不足に対する防御メカニズムです。
InnoDBの競合を緩和するために、 innodb_purge_threads
で遊ぶことができます。
MySQL 5.6以前は、 Master Thread がすべてのページフラッシュを実行していました。 MySQL 5.6では、別のスレッドで処理できます。 MySQL 5.5の innodb_purge_threads
のデフォルト値は0でした 最大値は1です。MySQL5.6では、 デフォルトは1 で最大値は32です。
innodb_purge_threads
を設定すると、実際にはどうなりますか?
ゼロ以外の値は、1つ以上のバックグラウンドスレッドでパージ操作を実行します。これにより、InnoDB内の内部競合が減少し、スケーラビリティが向上します。値を1より大きい値にすると、多くの個別のパージスレッドが作成され、DML操作が複数のテーブルで実行されるシステムの効率が向上します。
innodb_purge_threads を4に設定して開始し、InnoDBページのフラッシュが削減されるかどうかを確認します。
ページクリーナーが犠牲者であり、MySQL 5.7が対処できることを以下のコメントでMorgan Tockerが指摘しました 。それにもかかわらず、あなたの状況はMySQL 5.6にあります。
私は再調査しましたが、あなたが innodb_max_dirty_pages_pct を50に持っていることに気付きました。
MySQL 5.5以降での innodb_max_dirty_pages_pct のデフォルトは75です。これを下げると、フラッシュによるストールの発生率が増加します。私は3つ(3)のことをします
my.cnf
から削除フラッシュ動作を変更する必要があるかもしれません
以下を動的に設定してみてください
SET GLOBAL flush = 1;
SET GLOBAL flush_time = 10;
これらの変数 flush および flush_time 、テーブルの開いているファイルハンドルを10秒ごとに閉じることにより、フラッシュをより積極的にします。 MyISAMはデータをキャッシュしないため、間違いなくメリットがあります。 MyISAMテーブルへのすべての書き込みには、完全なテーブルロックとそれに続くアトミックな書き込みが必要で、ディスクの変更はOSに依存します。
その方法でInnoDBをフラッシュすると、mysqlの再起動が必要になります。表示するオプションは innodb_flush_log_at_trx_commit および innodb_flush_method 。
再起動する前に、これらを追加してください
[mysqld]
flush = 1
flush_time = 10
innodb_flush_log_at_trx_commit = 0
innodb_flush_method = O_DIRECT
このルートに進む前に、ジャーナリングが問題かどうかを確認する必要があります。カーネルが原因でO_DIRECTが偽造されている cool mysqlperformanceblog post を見ました。同じ投稿では、影響を受けるMyISAMについても言及しています。
私は以前にこの投稿について書きました: ib_logfileがO_SYNCで開かれたときにinnodb_flush_method = O_DSYNC
試してみる !!!