Upgrade to Pro — share decks privately, control downloads, hide ads and more …

バッファープールが大きいMySQL v5.7でDROP DATABASEが詰まった原因と対策 / Causes and Remedies for DROP DATABASE Stuck in MySQL v5.7 with Large Buffer Pool

バッファープールが大きいMySQL v5.7でDROP DATABASEが詰まった原因と対策 / Causes and Remedies for DROP DATABASE Stuck in MySQL v5.7 with Large Buffer Pool

Otsuka Tomoaki / LINE株式会社 ITサービスセンター Database室 MySQL1チーム

バッファプールが100GB以上あるMySQL 5.7でDROP TABLEを実行すると準同期レプリケーションとの兼ね合いでロックが発生し、予期しないフェイルオーバが発生する事態になりました。 今回はこの原因と対策を紹介します。なお、MySQLの最新メジャーバージョンである8.0では解決しています。

イベントページ
https://line.connpass.com/event/255090/

A3966f193f4bef226a0d3e3c1f728d7f?s=128

LINE Developers
PRO

August 02, 2022
Tweet

More Decks by LINE Developers

Other Decks in Technology

Transcript

  1. MySQL 5.7でDROP DATABASEが 詰まった原因の調査過程と対策 LINE, ITSC Database department MySQL1 team,

    ⼤塚知亮(@tom__bo) 1
  2. ⾃⼰紹介 • 所属: LINE ITSC, DB室 MySQL 1チーム • 業務内容:

    • MySQLの運⽤・⾃動化 • MySQL関連の技術調査(TiDB, Vitess, etc...) • Blog: https://tombo2.hatenablog.com/ • Twitter: @tom__bo 2
  3. 今回発表する内容 • DELETE⽂と別のスキーマに対するDROP DATABASE⽂の実⾏ でMySQLがハングしてメンテ失敗になった事例紹介 • 障害後の原因調査・対策作りまでの流れ • MySQL 5.7

    • 準同期レプリケーション • Innodb_buffer_pool_sizeが⼤きい • 削除対象のテーブルが⼤きい 3
  4. 問題に⾄るまでの経緯 4

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

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

    New shard1 New shard2 data data data data data data 前半部分 後半部分
  7. 分割作業 • メンテ後、新シャードで新しいスキーマを作成して必要なデータを抽出 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
  8. 分割作業 • メンテ後、新シャードで新しいスキーマを作成して必要なデータを抽出 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
  9. 分割作業 • メンテ後、新シャードで新しいスキーマを作成して必要なデータを抽出 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
  10. 分割作業 • メンテ後、新シャードで新しいスキーマを作成して必要なデータを抽出 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
  11. 分割作業 • メンテ後、新シャードで新しいスキーマを作成して必要なデータを抽出 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
  12. 分割作業 • メンテ後、新シャードで新しいスキーマを作成して必要なデータを抽出 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
  13. 分割作業 • メンテ後、新シャードで新しいスキーマを作成して必要なデータを抽出 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
  14. 再現実験 14

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

    15
  16. 調査⽅法 • dstatコマンドによるOSメトリックの観測 • myStatusgoによるクエリ実⾏状況監視 • 毎秒1⾏INSERTするスクリプト • 毎秒SHOW ENGINE

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

    INNODB STATUS • 詰まっている間のgstack `pidof mysqld`取得 • DROP DATABASE中のperf record, frameグラフ作成 CPU, Disk IOに異常なし DROP DATABASE実⾏後、 すべてのDMLが実⾏詰まった ことを確認 後述 (省略) 17
  18. 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
  19. 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
  20. 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<GenericPolicy>::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<TTASEventMutex<GenericPolicy> >::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=<optimized out>, thd=<optimized out>) at /PATH/TO/mysql-5.7.27/sql/rpl_handler.cc:343 #10 0x0000000000c84d80 in Trans_delegate::prepare_table_info (this=<optimized out>, thd=0x7fbf3c816000, table_info_list=@0x7fdaa70b1f78: 0x0, nu… #11 0x0000000000c86038 in Trans_delegate::before_dml (this=0x1e770a0 <delegates_init()::trans_mem>, thd=<optimized out>, result=@0x7fdaa70b2... #12 0x0000000000cc0af1 in run_before_dml_hook (thd=<optimized out>) 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=<optimized out>) 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=<optimized out>) 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
  21. 実装調査 21

  22. 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 (...省略)
  23. DROP DATABASEが取るDICT_SYS Mutex • DROP DATABASE ... がrow0mysql.cc line 5106

    を呼ぶまで 23
  24. 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解放) (テーブルをループ) (テーブル削除)
  25. 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
  26. 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<TTASEventMutex<GenericPolicy> >::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=<optimized out>, thd=<optimized out>) at /PATH/TO/mysql-5.7.27/sql/rpl_handler.cc:343 #10 0x0000000000c84d80 in Trans_delegate::prepare_table_info (this=<optimized out>, thd=0x7fbf3c816000, table_info_list=@0x7fdaa70b1f78: 0x0, number_of_... #11 0x0000000000c86038 in Trans_delegate::before_dml (this=0x1e770a0 <delegates_init()::trans_mem>, thd=<optimized out>, result=@0x7fdaa70b20dc: 0) at … #12 0x0000000000cc0af1 in run_before_dml_hook (thd=<optimized out>) 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
  27. 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
  28. 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
  29. 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
  30. observer_info_list.is_empty() • Obser v er_info_listはList <> • typedef List<Observer_info> 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
  31. 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.
  32. 結論 • 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
  33. 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
  34. 対策 • 8.0にアップグレード! • 5.7の最初のGA release(5.7.9)は約7年前(2015/10/21) • できるだ け⼩ さい

    単位 でDROP • スキーマ単位でDROPしない • サイズ が ⼤ きいテー ブ ルはデータを削除してからDROPする 34
  35. まとめ • 準同期 レプリケーションプラグ イ ンを イ ンストールしている MySQL 5.7.xでは

    、 DROP DATABASE …が取得するdict_sys MutexとDML実⾏時にRUN_HOOK 経由 で取得する 同 ロックが 競合 し 、 DMLをつまら せ る • こ れを 回避 するためには 以下 の ⽅法 が取れる • 8.0にアップグレード • TABLE単位でDROPする (TABLEのデータは事前に削除しておく) 35
  36. MySQLチームメンバー積極採⽤中! (2022/08/02時点) • https://linecorp.com/ j a/career/position/2377 36

  37. Q&A 37

  38. 38

  39. 補⾜資料 39

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