Slide 1

Slide 1 text

MySQL 5.7でDROP DATABASEが 詰まった原因の調査過程と対策 LINE, ITSC Database department MySQL1 team, ⼤塚知亮(@tom__bo) 1

Slide 2

Slide 2 text

⾃⼰紹介 • 所属: LINE ITSC, DB室 MySQL 1チーム • 業務内容: • MySQLの運⽤・⾃動化 • MySQL関連の技術調査(TiDB, Vitess, etc...) • Blog: https://tombo2.hatenablog.com/ • Twitter: @tom__bo 2

Slide 3

Slide 3 text

今回発表する内容 • DELETE⽂と別のスキーマに対するDROP DATABASE⽂の実⾏ でMySQLがハングしてメンテ失敗になった事例紹介 • 障害後の原因調査・対策作りまでの流れ • MySQL 5.7 • 準同期レプリケーション • Innodb_buffer_pool_sizeが⼤きい • 削除対象のテーブルが⼤きい 3

Slide 4

Slide 4 text

問題に⾄るまでの経緯 4

Slide 5

Slide 5 text

シャード分割概要 • シャード数を2倍にする作業をメンテありで実施 • 既存シャードそれぞれから2つの新シャードにレプリケーション • メンテ中に半分のデータを削除・アプリの向き先変更 5 Old shard New shard1 New shard2 data data data data data data

Slide 6

Slide 6 text

シャード分割概要 • シャード数を2倍にする作業をメンテありで実施 • 既存シャードそれぞれから2つの新シャードにレプリケーション • メンテ中に半分のデータを削除・アプリの向き先変更 6 Old shard New shard1 New shard2 data data data data data data 前半部分 後半部分

Slide 7

Slide 7 text

分割作業 • メンテ後、新シャードで新しいスキーマを作成して必要なデータを抽出 or テーブルを移動して不要なデータを消し込み 7 OLD OLD OLD -- 新規、移⾏先スキーマ・テーブル作成 CREATE DATABASE NEW; CREATE TABLE NEW.{not_big_tables} like OLD.{not_big_tables}; -- データ量が少ないテーブルの抽出 INSERT INTO NEW.{not_big_tables} SELECT * from OLD. {not_big_tables} where data_match_to(new_shardN); -- データ量が多いテーブルの移動 RENAME TABLE OLD.{big_tables} to NEW.{big_tables} -- データ量が多いテーブルの消込み (Lazy Delete) LOOP: DELETE FROM NEW.{big_tables} where data_not_match_to(new_shardN) LIMIT 1000; -- 古いスキーマの削除 DROP DATABASE OLD; Old shard NEW shard1 NEW shard2

Slide 8

Slide 8 text

分割作業 • メンテ後、新シャードで新しいスキーマを作成して必要なデータを抽出 or テーブルを移動して不要なデータを消し込み 8 OLD OLD OLD NEW NEW -- 新規、移⾏先スキーマ・テーブル作成 CREATE DATABASE NEW; CREATE TABLE NEW.{not_big_tables} like OLD.{not_big_tables}; -- データ量が少ないテーブルの抽出 INSERT INTO NEW.{not_big_tables} SELECT * from OLD. {not_big_tables} where data_match_to(new_shardN); -- データ量が多いテーブルの移動 RENAME TABLE OLD.{big_tables} to NEW.{big_tables} -- データ量が多いテーブルの消込み (Lazy Delete) LOOP: DELETE FROM NEW.{big_tables} where data_not_match_to(new_shardN) LIMIT 1000; -- 古いスキーマの削除 DROP DATABASE OLD; CREATE DATABSE… CREATE TABLE… Old shard NEW shard1 NEW shard2

Slide 9

Slide 9 text

分割作業 • メンテ後、新シャードで新しいスキーマを作成して必要なデータを抽出 or テーブルを移動して不要なデータを消し込み 9 OLD OLD OLD NEW NEW -- 新規、移⾏先スキーマ・テーブル作成 CREATE DATABASE NEW; CREATE TABLE NEW.{not_big_tables} like OLD.{not_big_tables}; -- データ量が少ないテーブルの抽出 INSERT INTO NEW.{not_big_tables} SELECT * from OLD. {not_big_tables} where data_match_to(new_shardN); -- データ量が多いテーブルの移動 RENAME TABLE OLD.{big_tables} to NEW.{big_tables} -- データ量が多いテーブルの消込み (Lazy Delete) LOOP: DELETE FROM NEW.{big_tables} where data_not_match_to(new_shardN) LIMIT 1000; -- 古いスキーマの削除 DROP DATABASE OLD; INSERT INTO … SELECT Old shard NEW shard1 NEW shard2

Slide 10

Slide 10 text

分割作業 • メンテ後、新シャードで新しいスキーマを作成して必要なデータを抽出 or テーブルを移動して不要なデータを消し込み 10 OLD OLD OLD NEW NEW -- 新規、移⾏先スキーマ・テーブル作成 CREATE DATABASE NEW; CREATE TABLE NEW.{not_big_tables} like OLD.{not_big_tables}; -- データ量が少ないテーブルの抽出 INSERT INTO NEW.{not_big_tables} SELECT * from OLD. {not_big_tables} where data_match_to(new_shardN); -- データ量が多いテーブルの移動 RENAME TABLE OLD.{big_tables} to NEW.{big_tables} -- データ量が多いテーブルの消込み (Lazy Delete) LOOP: DELETE FROM NEW.{big_tables} where data_not_match_to(new_shardN) LIMIT 1000; -- 古いスキーマの削除 DROP DATABASE OLD; RENAME TABLE OLD to NEW Old shard NEW shard1 NEW shard2

Slide 11

Slide 11 text

分割作業 • メンテ後、新シャードで新しいスキーマを作成して必要なデータを抽出 or テーブルを移動して不要なデータを消し込み 11 OLD OLD OLD NEW NEW -- 新規、移⾏先スキーマ・テーブル作成 CREATE DATABASE NEW; CREATE TABLE NEW.{not_big_tables} like OLD.{not_big_tables}; -- データ量が少ないテーブルの抽出 INSERT INTO NEW.{not_big_tables} SELECT * from OLD. {not_big_tables} where data_match_to(new_shardN); -- データ量が多いテーブルの移動 RENAME TABLE OLD.{big_tables} to NEW.{big_tables} -- データ量が多いテーブルの消込み (Lazy Delete) LOOP: DELETE FROM NEW.{big_tables} where data_not_match_to(new_shardN) LIMIT 1000; -- 古いスキーマの削除 DROP DATABASE OLD; Loop: DELETE FROM NEW WHERE … LIMIT 1000 (Lazy Delete) Old shard NEW shard1 NEW shard2

Slide 12

Slide 12 text

分割作業 • メンテ後、新シャードで新しいスキーマを作成して必要なデータを抽出 or テーブルを移動して不要なデータを消し込み 12 OLD OLD OLD NEW NEW -- 新規、移⾏先スキーマ・テーブル作成 CREATE DATABASE NEW; CREATE TABLE NEW.{not_big_tables} like OLD.{not_big_tables}; -- データ量が少ないテーブルの抽出 INSERT INTO NEW.{not_big_tables} SELECT * from OLD. {not_big_tables} where data_match_to(new_shardN); -- データ量が多いテーブルの移動 RENAME TABLE OLD.{big_tables} to NEW.{big_tables} -- データ量が多いテーブルの消込み (Lazy Delete) LOOP: DELETE FROM NEW.{big_tables} where data_not_match_to(new_shardN) LIMIT 1000; -- 古いスキーマの削除 DROP DATABASE OLD; Loop: DELETE FROM NEW WHERE … LIMIT 1000 (Lazy Delete) DROP DATABASE OLD Old shard NEW shard1 NEW shard2

Slide 13

Slide 13 text

分割作業 • メンテ後、新シャードで新しいスキーマを作成して必要なデータを抽出 or テーブルを移動して不要なデータを消し込み 13 OLD OLD OLD NEW NEW -- 新規、移⾏先スキーマ・テーブル作成 CREATE DATABASE NEW; CREATE TABLE NEW.{not_big_tables} like OLD.{not_big_tables}; -- データ量が少ないテーブルの抽出 INSERT INTO NEW.{not_big_tables} SELECT * from OLD. {not_big_tables} where data_match_to(new_shardN); -- データ量が多いテーブルの移動 RENAME TABLE OLD.{big_tables} to NEW.{big_tables} -- データ量が多いテーブルの消込み (Lazy Delete) LOOP: DELETE FROM NEW.{big_tables} where data_not_match_to(new_shardN) LIMIT 1000; -- 古いスキーマの削除 DROP DATABASE OLD; Loop: DELETE FROM NEW WHERE … LIMIT 1000 (Lazy Delete) DROP DATABASE OLD MySQL ハング! Old shard NEW shard1 NEW shard2

Slide 14

Slide 14 text

再現実験 14

Slide 15

Slide 15 text

調査内容 • なぜDROP DATABASEと関係ないスキーマへのDMLも詰まっ たのか? • なぜDROP DATABASEに時間がかかったのか? • (省略、次回?) 15

Slide 16

Slide 16 text

調査⽅法 • dstatコマンドによるOSメトリックの観測 • myStatusgoによるクエリ実⾏状況監視 • 毎秒1⾏INSERTするスクリプト • 毎秒SHOW ENGINE INNODB STATUS • 詰まっている間のgstack `pidof mysqld`取得 • DROP DATABASE中のperf record, frameグラフ作成 16

Slide 17

Slide 17 text

調査⽅法 • dstatコマンドによるOSメトリックの観測 • myStatusgoによるクエリ実⾏状況監視 • 毎秒1⾏INSERTするスクリプト • 毎秒SHOW ENGINE INNODB STATUS • 詰まっている間のgstack `pidof mysqld`取得 • DROP DATABASE中のperf record, frameグラフ作成 CPU, Disk IOに異常なし DROP DATABASE実⾏後、 すべてのDMLが実⾏詰まった ことを確認 後述 (省略) 17

Slide 18

Slide 18 text

SHOW ENGINE INNODB STATUS • SEMAPHORESセクションにミューテックス・セマフォ情報 ---------- SEMAPHORES ---------- OS WAIT ARRAY INFO: reservation count 2469847 --Thread 140577082132224 has waited at ha_innodb.cc line 15015 for 13 seconds the semaphore: Mutex at 0x7fdaa4b5a9d8, Mutex DICT_SYS created dict0dict.cc:1172, lock var 1 --Thread 140457661146880 has waited at row0purge.cc line 862 for 14 seconds the semaphore: S-lock on RW-latch at 0x7fc005af2858 created in file dict0dict.cc line 1183 a writer (thread id 140577049569024) has reserved it in mode exclusive number of readers 0, waiters flag 1, lock_word: 0 Last time read locked in file row0purge.cc line 862 Last time write locked in file /PATH/TO/mysql-5.7.27/storage/innobase/row/row0mysql.cc line 5106 --Thread 140577048487680 has waited at ha_innodb.cc line 5614 for 11 seconds the semaphore: Mutex at 0x7fdaa4b5a9d8, Mutex DICT_SYS created dict0dict.cc:1172, lock var 1 --Thread 140577083217664 has waited at ha_innodb.cc line 15015 for 13 seconds the semaphore: Mutex at 0x7fdaa4b5a9d8, Mutex DICT_SYS created dict0dict.cc:1172, lock var 1 --Thread 140577049028352 has waited at ha_innodb.cc line 15015 for 13 seconds the semaphore: Mutex at 0x7fdaa4b5a9d8, Mutex DICT_SYS created dict0dict.cc:1172, lock var 1 (...省略) (* /PATH/TOになっている部分は置換済み) 18

Slide 19

Slide 19 text

SHOW ENGINE INNODB STATUS • SEMAPHORESセクションにミューテックス・セマフォ情報 ---------- SEMAPHORES ---------- OS WAIT ARRAY INFO: reservation count 2469847 --Thread 140577082132224 has waited at ha_innodb.cc line 15015 for 13 seconds the semaphore: Mutex at 0x7fdaa4b5a9d8, Mutex DICT_SYS created dict0dict.cc:1172, lock var 1 --Thread 140457661146880 has waited at row0purge.cc line 862 for 14 seconds the semaphore: S-lock on RW-latch at 0x7fc005af2858 created in file dict0dict.cc line 1183 a writer (thread id 140577049569024) has reserved it in mode exclusive number of readers 0, waiters flag 1, lock_word: 0 Last time read locked in file row0purge.cc line 862 Last time write locked in file /PATH/TO/mysql-5.7.27/storage/innobase/row/row0mysql.cc line 5106 --Thread 140577048487680 has waited at ha_innodb.cc line 5614 for 11 seconds the semaphore: Mutex at 0x7fdaa4b5a9d8, Mutex DICT_SYS created dict0dict.cc:1172, lock var 1 --Thread 140577083217664 has waited at ha_innodb.cc line 15015 for 13 seconds the semaphore: Mutex at 0x7fdaa4b5a9d8, Mutex DICT_SYS created dict0dict.cc:1172, lock var 1 --Thread 140577049028352 has waited at ha_innodb.cc line 15015 for 13 seconds the semaphore: Mutex at 0x7fdaa4b5a9d8, Mutex DICT_SYS created dict0dict.cc:1172, lock var 1 (...省略) (* /PATH/TOになっている部分は置換済み) 19

Slide 20

Slide 20 text

gstackでスレッドのスタック取得 • 140577082132224 (0x7fdaa70b4700)を抜粋 (はみ出してます) Thread 9 (Thread 0x7fdaa70b4700 (LWP 3499)): #0 0x00007fdaa6c03a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0 #1 0x000000000107111b in wait (this=0x7fc005af28f8) at /PATH/TO/mysql-5.7.27/storage/innobase/os/os0event.cc:171 #2 os_event::wait_low (this=0x7fc005af28f8, reset_sig_count=193) at /PATH/TO/mysql-5.7.27/storage/innobase/os/os0event.cc:358 #3 0x0000000001118259 in sync_array_wait_event (arr=0x7fda986fa7f8, cell=@0x7fdaa70b1cf8: 0x7fda98006018) at /PATH/TO/mysql-5.7.27/storage/… #4 0x0000000001000d64 in TTASEventMutex::wait (this=0x7fdaa4b5a9d8, filename=0x1617ee0 "/PATH/TO/mysql-5.7.27/storage/inn… #5 0x0000000001000edb in spin_and_try_lock (line=15015, filename=0x1617ee0 "/PATH/TO/mysql-5.7.27/storage/innobase/handler/ha_innodb.cc", th… #6 enter (line=15015, filename=0x1617ee0 "/PATH/TO/mysql-5.7.27/storage/innobase/handler/ha_innodb.cc", max_delay=6, max_spins=30, this=0x7f… #7 PolicyMutex >::enter (this=0x7fdaa4b5a9d8, n_spins=30, n_delay=6, name=0x1617ee0 "/PATH/TO/mysql-5.7.27… #8 0x0000000000ff5aec in ha_innobase::get_foreign_key_list (this=0x7fbf3ac78030, thd=0x7fbf3c816000, f_key_list=0x7fdaa70b1e20) at /PATH/TO/my… #9 0x0000000000c841ff in has_cascade_foreign_key (table=, thd=) at /PATH/TO/mysql-5.7.27/sql/rpl_handler.cc:343 #10 0x0000000000c84d80 in Trans_delegate::prepare_table_info (this=, thd=0x7fbf3c816000, table_info_list=@0x7fdaa70b1f78: 0x0, nu… #11 0x0000000000c86038 in Trans_delegate::before_dml (this=0x1e770a0 , thd=, result=@0x7fdaa70b2... #12 0x0000000000cc0af1 in run_before_dml_hook (thd=) at /PATH/TO/mysql-5.7.27/sql/sql_base.cc:5334 #13 0x0000000000e9aa4d in Sql_cmd_delete::mysql_delete (this=0x7fbf3c825fb8, thd=0x7fbf3c816000, limit=18446744073709551615) at /PATH/TO/m… #14 0x0000000000e9c17f in Sql_cmd_delete::execute (this=0x7fbf3c825fb8, thd=0x7fbf3c816000) at /PATH/TO/mysql-5.7.27/sql/sql_delete.cc:1393 #15 0x0000000000d1c7cb in mysql_execute_command (thd=0x7fbf3c816000, first_level=true) at /PATH/TO/mysql-5.7.27/sql/sql_parse.cc:3606 #16 0x0000000000d20cdd in mysql_parse (thd=0x7fbf3c816000, parser_state=) at /PATH/TO/mysql-5.7.27/sql/sql_parse.cc:5570 #17 0x0000000000d21f05 in dispatch_command (thd=0x7fbf3c816000, com_data=0x7fdaa70b3da0, command=COM_QUERY) at /PATH/TO/mysql-5.7…. #18 0x0000000000d22de4 in do_command (thd=0x7fbf3c816000) at /PATH/TO/mysql-5.7.27/sql/sql_parse.cc:1025 #19 0x0000000000df4734 in handle_connection (arg=) at /PATH/TO/mysql-5.7.27/sql/conn_handler/connection_handler_per_thread.cc:306 #20 0x0000000000f71ea4 in pfs_spawn_thread (arg=0x7fdaa481be20) at /PATH/TO/mysql-5.7.27/storage/perfschema/pfs.cc:2190 #21 0x00007fdaa6bffea5 in start_thread () from /lib64/libpthread.so.0 #22 0x00007fdaa56b7b0d in clone () from /lib64/libc.so.6 (* /PATH/TOになっている部分は置換、⻑い⾏は…で省略) 20

Slide 21

Slide 21 text

実装調査 21

Slide 22

Slide 22 text

DROP DATABASEが取るDICT_SYS Mutex • SEMAPHORESセクションにはMutexをとっているスレッドの 情報は出⼒されない • とりあえずSHOW ENGINE INNODB STATUSのSEMAPHORE セクションに出るMutexにbreakpointを張って処理内容を⾒る 22 ---------- SEMAPHORES ---------- OS WAIT ARRAY INFO: reservation count 2469847 --Thread 140577082132224 has waited at ha_innodb.cc line 15015 for 13 seconds the semaphore: Mutex at 0x7fdaa4b5a9d8, Mutex DICT_SYS created dict0dict.cc:1172, lock var 1 --Thread 140457661146880 has waited at row0purge.cc line 862 for 14 seconds the semaphore: S-lock on RW-latch at 0x7fc005af2858 created in file dict0dict.cc line 1183 a writer (thread id 140577049569024) has reserved it in mode exclusive number of readers 0, waiters flag 1, lock_word: 0 Last time read locked in file row0purge.cc line 862 Last time write locked in file /PATH/TO/mysql-5.7.27/storage/innobase/row/row0mysql.cc line 5106 --Thread 140577048487680 has waited at ha_innodb.cc line 5614 for 11 seconds the semaphore: Mutex at 0x7fdaa4b5a9d8, Mutex DICT_SYS created dict0dict.cc:1172, lock var 1 (...省略)

Slide 23

Slide 23 text

DROP DATABASEが取るDICT_SYS Mutex • DROP DATABASE ... がrow0mysql.cc line 5106 を呼ぶまで 23

Slide 24

Slide 24 text

row_drop_database_for_mysql() • row0mysql.cc row_drop_database_for_mysql()の中⾝ • DROP DATABASEの実⾏中はdict_sys mutexがロックされる 24 5071 row_drop_database_for_mysql() { 5106 row_mysql_lock_data_dictionary(trx); 5107 5108 while ((table_name = dict_get_first_table_name_in_db(name))) { 5192 err = row_drop_table_for_mysql(table_name, trx, TRUE); 5193 trx_commit_for_mysql(trx); 5206 } 5224 row_mysql_unlock_data_dictionary(trx); 5229 } (Mutex Lock取得) (Mutex Lock解放) (テーブルをループ) (テーブル削除)

Slide 25

Slide 25 text

dict_sys Mutex? • Data dictionaryを保護するための排他ロック • https://github.com/mysql/mysql-server/blob/mysql- 5.7.27/storage/innobase/include/dict0dict.h#L1695 25 /** the dictionary system */ extern dict_sys_t* dict_sys; ... /* Dictionary system struct */ struct dict_sys_t{ DictSysMutex mutex; /*!< mutex protecting the data dictionary; protects also the disk-based dictionary system tables; this mutex serializes CREATE TABLE and DROP TABLE, as well as reading the dictionary dat

Slide 26

Slide 26 text

DELETE⽂のとるDICT_SYS Mutex • 最初に⾒たMutexの情報がDELETE処理 • ロック待ちする直前は… • run_before_dml_hook()経由のha_innobase::get_foreign_key_list() ---------- SEMAPHORES ---------- OS WAIT ARRAY INFO: reservation count 2469847 --Thread 140577082132224 has waited at ha_innodb.cc line 15015 for 13 seconds the semaphore: Mutex at 0x7fdaa4b5a9d8, Mutex DICT_SYS created dict0dict.cc:1172, lock var 1 (...省略) Thread 9 (Thread 0x7fdaa70b4700 (LWP 3499)): (省略) #7 PolicyMutex >::enter (this=0x7fdaa4b5a9d8, n_spins=30, n_delay=6, name=0x1617ee0 "/PATH/TO/mysql-5.7.27/storage/… #8 0x0000000000ff5aec in ha_innobase::get_foreign_key_list (this=0x7fbf3ac78030, thd=0x7fbf3c816000, f_key_list=0x7fdaa70b1e20) at /PATH/TO/mysql-5.7.27/… #9 0x0000000000c841ff in has_cascade_foreign_key (table=, thd=) at /PATH/TO/mysql-5.7.27/sql/rpl_handler.cc:343 #10 0x0000000000c84d80 in Trans_delegate::prepare_table_info (this=, thd=0x7fbf3c816000, table_info_list=@0x7fdaa70b1f78: 0x0, number_of_... #11 0x0000000000c86038 in Trans_delegate::before_dml (this=0x1e770a0 , thd=, result=@0x7fdaa70b20dc: 0) at … #12 0x0000000000cc0af1 in run_before_dml_hook (thd=) at /PATH/TO/mysql-5.7.27/sql/sql_base.cc:5334 #13 0x0000000000e9aa4d in Sql_cmd_delete::mysql_delete (this=0x7fbf3c825fb8, thd=0x7fbf3c816000, limit=18446744073709551615) at /PATH/TO/mysql-5.7.27… (省略) 26

Slide 27

Slide 27 text

run_before_dml_hook()とは? • ⼿元でビルドした環境だとRUN_HOOKは呼ばれない!? • こ のあたりから 読ん でい く int run_before_dml_hook(THD *thd) { int out_value= 0; (void) RUN_HOOK(transaction, before_dml, (thd, out_value)); if (out_value) my_error(ER_BEFORE_DML_VALIDATION_ERROR, MYF(0)); return out_value; } 27

Slide 28

Slide 28 text

RUN_HOOK()マクロ • RUN_HOOKマクロ • https://github.com/mysql/mysql-server/blob/mysql- 5.7.27/sql/rpl_handler.h#L325 • ##はマクロ内のトークン連結演算⼦ • 前出のrun_before_dml_hookの呼び出しと合わせると、以下のように 呼び出される(はず) #define RUN_HOOK(group, hook, args) (group ##_delegate->is_empty() ? \ 0 : group ##_delegate->hook args) transaction_delege->is_empty() ? \ 0 : transaction_delegate->before_dml(thd, out_value)) 28

Slide 29

Slide 29 text

Transaction_deleate->is_empty() • 宣⾔部 分 • https://github.com/mysql/mysql-server/blob/mysql- 5.7.27/sql/rpl_handler.h#L168 • Trans_delegateクラスでis_empty()の オ ー バ ーラ イ ドはな く、 親 クラスのDelegateクラスを⾒る • https://github.com/mysql/mysql-server/blob/mysql- 5.7.27/sql/rpl_handler.h#L101 inline bool is_empty() { DBUG_PRINT("debug", ("is_empty: %d", observer_info_list.is_empty())); return observer_info_list.is_empty(); } 29

Slide 30

Slide 30 text

observer_info_list.is_empty() • Obser v er_info_listはList <> • typedef List Observer_info_list; • Obser v er_infoにはinstallされたpluginが ⼊ っている • gdbで刺してみるとSemi-syncレプリのプラグインが⾒つかる • リストへの追加と削除はDelegateクラスのadd_observer(), remove_observer() class Observer_info { public: void *observer; st_plugin_int *plugin_int; plugin_ref plugin; Observer_info(void *ob, st_plugin_int *p); }; 30

Slide 31

Slide 31 text

RUN_HOOKは何者なのか? • サ ー バ プラグ イ ンがDMLの前に 任意 のコードを実⾏できるよ う にするフック ポイ ント • 準同期レプリケーションのときだけFKをチェックするのかわからず • https://github.com/mysql/mysql-server/blob/mysql- 5.7.27/sql/sql_base.cc#L5319 31 Run the server hook called "before_dml". This is a hook originated from replication that allow server plugins to execute code before any DML instruction is executed.

Slide 32

Slide 32 text

結論 • DROP DATABASEではテー ブ ルを1つずつ削除する間 、 dict_sys mutexを 握 りっ ぱ なし • 準同期 レプリケーションのプラグ イ ンを イ ンストールしている と 、 DML実⾏時にRUN_HOOK() 経由 でdict_sys mutexを取る • インストールしただけで有効化していなくてもロックを取る • rpl_semi_sync_master / rpl_semi_sync_slave plugin (5.7表記) • こ れらが 競合 してDROP DATABASE中はDMLがロックされる • 単純な⽅法で回避することはできない 32

Slide 33

Slide 33 text

8.0では? • has_cascade_foreign_key() からha_innobase::get_foreign_key_list() を 呼ばないよ う に 修正 されている • 8.0.4から修正されている (コミット) • 8.0からはDD API(データディクショナリのAPI)からFKの情報を取れるようにな たので、ストレージエンジンからFKリストを取得する必要はなくなったらしい • データを⼊れて実験してもDMLが詰まることはなかった • has_cascade_foreign_key() のコード 33

Slide 34

Slide 34 text

対策 • 8.0にアップグレード! • 5.7の最初のGA release(5.7.9)は約7年前(2015/10/21) • できるだ け⼩ さい 単位 でDROP • スキーマ単位でDROPしない • サイズ が ⼤ きいテー ブ ルはデータを削除してからDROPする 34

Slide 35

Slide 35 text

まとめ • 準同期 レプリケーションプラグ イ ンを イ ンストールしている MySQL 5.7.xでは 、 DROP DATABASE …が取得するdict_sys MutexとDML実⾏時にRUN_HOOK 経由 で取得する 同 ロックが 競合 し 、 DMLをつまら せ る • こ れを 回避 するためには 以下 の ⽅法 が取れる • 8.0にアップグレード • TABLE単位でDROPする (TABLEのデータは事前に削除しておく) 35

Slide 36

Slide 36 text

MySQLチームメンバー積極採⽤中! (2022/08/02時点) • https://linecorp.com/ j a/career/position/2377 36

Slide 37

Slide 37 text

Q&A 37

Slide 38

Slide 38 text

38

Slide 39

Slide 39 text

補⾜資料 39

Slide 40

Slide 40 text

Perfによるframeグラフ • (io_wait, lock待ちの処理は 含 まれないため 参考 にならず) 40