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

MySQL のクラッシュからの復旧を ちょっとだけ速くする裏技/Techniques to make mysql crash recovery a bit faster

Cybozu
April 17, 2020

MySQL のクラッシュからの復旧を ちょっとだけ速くする裏技/Techniques to make mysql crash recovery a bit faster

Cybozu

April 17, 2020
Tweet

More Decks by Cybozu

Other Decks in Programming

Transcript

  1. 当社サービスの MySQL の構成 2010.12 MySQL 5.5 GA 2013.02 MySQL 5.6

    GA (GTID) 2015.10 MySQL 5.7 GA (loss-less semi-sync) 2018.4 MySQL 8.0 GA
  2. 当社サービスの MySQL の構成 2010.12 MySQL 5.5 GA 2013.02 MySQL 5.6

    GA (GTID) 2015.10 MySQL 5.7 GA (loss-less semi-sync) 2018.4 MySQL 8.0 GA 2011.11 cybozu.com 提供開始
  3. 当社サービスの MySQL の構成 2010.12 MySQL 5.5 GA 2011.11 cybozu.com 提供開始

    2013.02 MySQL 5.6 GA (GTID) 2015.10 MySQL 5.7 GA (loss-less semi-sync) 2018.4 MySQL 8.0 GA 当時は GTID も loss-less semi-sync レプリケーションもなく レプリケーションを使わない 共有ストレージ方式 で運用を始めました
  4. ある日実際に起きたフェイルオーバー時のログ 04:04:34 [Note] InnoDB: Starting crash recovery. … 04:04:45 [Note]

    InnoDB: Apply batch completed 04:13:19 [Note] InnoDB: Starting in background the rollback of uncommitted transactions … 04:13:21 [Note] /opt/cybozu/mysql/bin/mysqld: ready for connections.
  5. ある日実際に起きたフェイルオーバー時のログ 04:04:34 [Note] InnoDB: Starting crash recovery. … 04:04:45 [Note]

    InnoDB: Apply batch completed 04:13:19 [Note] InnoDB: Starting in background the rollback of uncommitted transactions … 04:13:21 [Note] /opt/cybozu/mysql/bin/mysqld: ready for connections. ここで起動完了
  6. ある日実際に起きたフェイルオーバー時のログ 04:04:34 [Note] InnoDB: Starting crash recovery. … 04:04:45 [Note]

    InnoDB: Apply batch completed 04:13:19 [Note] InnoDB: Starting in background the rollback of uncommitted transactions … 04:13:21 [Note] /opt/cybozu/mysql/bin/mysqld: ready for connections. ここまで11秒くらい
  7. ある日実際に起きたフェイルオーバー時のログ 04:04:34 [Note] InnoDB: Starting crash recovery. … 04:04:45 [Note]

    InnoDB: Apply batch completed 04:13:19 [Note] InnoDB: Starting in background the rollback of uncommitted transactions … 04:13:21 [Note] /opt/cybozu/mysql/bin/mysqld: ready for connections. この時間は何??
  8. ある日実際に起きたフェイルオーバー時のログ 04:04:34 [Note] InnoDB: Starting crash recovery. … 04:04:45 [Note]

    InnoDB: Apply batch completed 04:13:19 [Note] InnoDB: Starting in background the rollback of uncommitted transactions … 04:13:21 [Note] /opt/cybozu/mysql/bin/mysqld: ready for connections. この時間は何?? このダウンタイムが私たちを苦しめていました
  9. クラッシュからの復旧時の処理 1. クラッシュリカバリ ◼ redo log の内容をテーブルスペースに反映する ◼ 「innodb_log_file_size を大きくしすぎると

    復旧に時間がかかるので注意」 とよく言われるもの 2. ??? クラッシュリカバリが 遅いのだと思っていました
  10. この発表で共有したいこと 1. 私たちを苦しめていた 謎のダウンタイム の正体 2. 復旧を高速化するためのワークアラウンド 04:04:34 [Note] InnoDB:

    Starting crash recovery. … 04:04:45 [Note] InnoDB: Apply batch completed 04:13:19 [Note] InnoDB: Starting in background the rollback of uncommitted transactions … 04:13:21 [Note] /opt/cybozu/mysql/bin/mysqld: ready for connections.
  11. スタックトレースの調査 #6 Datafile::read_first_page at storage/innobase/fsp/fsp0file.cc:338 #7 Datafile::validate_first_page at storage/innobase/fsp/fsp0file.cc:552 #8

    Datafile::validate_to_dd at storage/innobase/fsp/fsp0file.cc:404 #9 fil_ibd_open at storage/innobase/fil/fil0fil.cc:3968 #10 dict_check_sys_tables at storage/innobase/dict/dict0load.cc:1465 #11 dict_check_tablespaces_and_store_max_id at storage/innobase/dict/dict0load.cc:1525 #12 innobase_start_or_create_for_mysql at storage/innobase/srv/srv0start.cc:2329 #13 innobase_init at storage/innobase/handler/ha_innodb.cc:4048
  12. スタックトレースの調査 #6 Datafile::read_first_page at storage/innobase/fsp/fsp0file.cc:338 #7 Datafile::validate_first_page at storage/innobase/fsp/fsp0file.cc:552 #8

    Datafile::validate_to_dd at storage/innobase/fsp/fsp0file.cc:404 #9 fil_ibd_open at storage/innobase/fil/fil0fil.cc:3968 #10 dict_check_sys_tables at storage/innobase/dict/dict0load.cc:1465 #11 dict_check_tablespaces_and_store_max_id at storage/innobase/dict/dict0load.cc:1525 #12 innobase_start_or_create_for_mysql at storage/innobase/srv/srv0start.cc:2329 #13 innobase_init at storage/innobase/handler/ha_innodb.cc:4048 起動時に呼ばれそうな 関数から
  13. スタックトレースの調査 #6 Datafile::read_first_page at storage/innobase/fsp/fsp0file.cc:338 #7 Datafile::validate_first_page at storage/innobase/fsp/fsp0file.cc:552 #8

    Datafile::validate_to_dd at storage/innobase/fsp/fsp0file.cc:404 #9 fil_ibd_open at storage/innobase/fil/fil0fil.cc:3968 #10 dict_check_sys_tables at storage/innobase/dict/dict0load.cc:1465 #11 dict_check_tablespaces_and_store_max_id at storage/innobase/dict/dict0load.cc:1525 #12 innobase_start_or_create_for_mysql at storage/innobase/srv/srv0start.cc:2329 #13 innobase_init at storage/innobase/handler/ha_innodb.cc:4048 validate や check といった 関数が呼ばれている
  14. コードを追ってみると 1. 存在するはずの ibd ファイルを列挙 2. open(3) で開く 3. pread(3)

    で先頭 64 KiB を読み込む (64KiB は innodb_page_size の最大値) 4. 不整合が発生していないか検証 innodb_file_per_table = ON なら テーブルの数だけ存在する
  15. マルチテナント サイボウズでの実現方法 ➡ テナントごとに MySQL の DATABASE を作成して テナントごとにテーブルを作る A社環境

    (aaaaa.cybozu.com) B社環境 (bbbbb.cybozu.com) • users • schedule • comments • … • users • schedule • comments • …
  16. テーブル数はどうなる? ▌N : テナントあたりのテーブル数 ◼ 作りこんだアプリケーションなら 100 を超える ことはよくある ◼

    パーティショニングを駆使しているともっと増える ▌M : テナント数 ◼ 高性能なインスタンスに高密度に集約すると 数百 程度になることも
  17. テーブル数はどうなる? ▌N : テナントあたりのテーブル数 ◼ 作りこんだアプリケーションなら 100 を超える ことはよくある ◼

    パーティショニングを駆使しているともっと増える ▌M : テナント数 ◼ 高性能なインスタンスに高密度に集約すると 数百 程度になることも N × M ≈ 数万
  18. クラッシュからの復旧時の処理 1. クラッシュリカバリ ◼ redo log の内容をテーブルスペースに反映する ◼ 「innodb_log_file_size を大きくしすぎると

    復旧に時間がかかるので注意」 とよく言われるもの 2. ibd ファイルのベリファイ ◼ ファイルの先頭 64 KiB を読む ◼ テーブルが多い環境ではとても遅い 遅い原因は こっちだった
  19. ボトルネックはどこ? 1. 存在するはずの ibd ファイルを列挙 2. open(3) で開く 3. pread(3)

    で先頭 64 KiB を読み込む (64KiB は innodb_page_size の最大値) 4. 不整合が発生していないか検証
  20. ボトルネックはどこ? 1. 存在するはずの ibd ファイルを列挙 2. open(3) で開く 3. pread(3)

    で先頭 64 KiB を読み込む (64KiB は innodb_page_size の最大値) 4. 不整合が発生していないか検証 直列に
  21. ボトルネックはどこ? 1. 存在するはずの ibd ファイルを列挙 2. open(3) で開く 3. pread(3)

    で先頭 64 KiB を読み込む (64KiB は innodb_page_size の最大値) 4. 不整合が発生していないか検証 同期読み込み
  22. ページキャッシュに乗せるためのプログラム ▌Go で書きました ▌ibd ファイルを Open して先頭 64KiB を Read

    するような goroutine(軽量スレッド)をたくさん立てるだけ ▌systemd の設定を書いて MySQL の前に起動するようにした
  23. 参考情報 Percona のブログに「テーブルが増えすぎるとロクなことがないので注意」という記事あり ▌MySQL 8.0 General Tablespaces: File per Database

    (and no FRM files) https://www.percona.com/blog/2016/10/03/mysql-8-0-general- tablespaces-file-per-database-no-frm-files/ ▌One Million Tables in MySQL 8.0 https://www.percona.com/blog/2017/10/01/one-million-tables- mysql-8-0/