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

Dive into InnoDB from redo logs

tom--bo
February 28, 2024

Dive into InnoDB from redo logs

tom--bo

February 28, 2024
Tweet

More Decks by tom--bo

Other Decks in Technology

Transcript

  1. 背景(Redoログを調べたきっかけ) • Cloud NativeなDBで”Log”を活⽤するケースをよく⾒る • MySQLのRedoログってどうなっているんだっけ? 左図: Amazon Aurora: Design

    Considerations for High Throughput Cloud-Native Relational Databases 右図: AlloyDB for PostgreSQL under the hood: Intelligent, database-aware storage (⻩緑がlog 紫がmetadata) Amazon Aurora AlloyDB (Google) 2
  2. MySQLのRedoログはinnodb_redo_log • 8.0以降システムテーブル(ibdata1), データディクショナリ (mysql.ibd, 以降DD)がInnoDBで管理されている • https://dev.mysql.com/doc/refman/8.0/en/data-dictionary-transactional- storage.html •

    https://dev.mysql.com/doc/refman/8.0/en/innodb-system- tablespace.html • MySQLのシステムデータ(メタデータ)とInnoDBで作成される テーブルはinnodbのredoログで障害回復する • MySQLではInnoDB以外のSEはトランザクショナルではない • 今回はInnoDB以外のストレージエンジンは対象外 3
  3. Redoログが読めると何が嬉しい? • MySQL内部で起こったデータの更新がすべてわかる • 物理的なデータ更新の内容 • メタデータを含むデータの物理的配置 • LSN等の管理⽅法、管理場所 •

    Amazon Auroraの実装がどうなっているのか、より具体的に 想像できるようになる(はず) • AWS Auroraはインスタンス、ストレージ間でRedoログを送受信する • Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases
  4. InnoDBアーキテクチャ https://dev.mysql.com/doc/refman/8.0/en/innodb-architecture.html 1. テーブル内のデータはページ単位 で管理されている • メモリ、ディスク間のやりとりの単位 • デフォルト16KiB 2.

    データ更新時はコミット完了前に Redo Logを永続化する(WAL) 3. UndoログはUndo Tablespacesで ログレコードとして管理される • Undoの⽣成もデータ更新として、 Redoログが⽣成される
  5. ここまでのまとめ • MySQLにおけるデータの更新はすべてinnodb_redo_logに 記録される • システムテーブル、データディクショナリも内部的にinnodbの実装で 管理されている • InnoDB以外のSEで作成されるテーブルは本発表の対象外 •

    そもそもInnoDB以外はトランザクショナルではない • MySQL(innodb)のredoログを調べるためにmysqlredoコマンドを 作った • Githubで公開しています。良ければ⭐してください m(_ _)m
  6. ログレコードのフォーマット • フォーマット • type(1): ログタイプ • space_id(1~6): テーブルスペース番号 •

    page_no(1~6): ページ番号 • Payload: typeごとに固有の形式 13 type space_id page_no payload (offset, data, …etc) t1.ibd (space=2) t2.ibd (space=3)
  7. 主なログタイプ • ファイル操作 • MLOG_FILE_CREATE • MLOG_FILE_RENAME • MLOG_FILE_DELETE •

    MLOG_FILE_EXTEND • レコード操作 • MLOG_REC_INSERT • MLOG_REC_CLUST_DELETE_MARK • MLOG_REC_DELETE • MLOG_REC_UPDATE_IN_PLACE • UNDOレコード操作 • MLOG_UNDO_INIT • MLOG_UNDO_INSERT • MLOG_UNDO_HDR_CREATE • メタデータ書き込み • MLOG_1BYTE • MLOG_2BYTE • MLOG_4BYTE • MLOG_8BYTE
  8. Space_id (Tablespace ID) • 0: system table(ibdata1) • 1: sys/sysconfig

    • 2~: user table • 4294967294: mysql(dd, mysql.ibd) • 4294967278, 4294967279: undo
  9. UPDATEによるredo logを⾒てみる • データ作成 mysql> create database d1; mysql> use

    d1 mysql> create table t1(id int not null primary key auto_increment, c1 int not null); mysql> insert into …; mysql> select * from t1; +----+----+ | id | c1 | +----+----+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+----+ 3 rows in set (0.00 sec)
  10. UPDATEによるredo logを⾒てみる mysql> show global status like '%lsn%'; +-------------------------------------+----------+ |

    Variable_name | Value | +-------------------------------------+----------+ | Innodb_redo_log_checkpoint_lsn | 19529906 | | Innodb_redo_log_current_lsn | 19529906 | | Innodb_redo_log_flushed_to_disk_lsn | 19529906 | +-------------------------------------+----------+ 3 rows in set (0.00 sec) mysql> update t1 set c1=20 where id = 2; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> show global status like '%lsn%'; +-------------------------------------+----------+ | Variable_name | Value | +-------------------------------------+----------+ | Innodb_redo_log_checkpoint_lsn | 19530158 | | Innodb_redo_log_current_lsn | 19530158 | | Innodb_redo_log_flushed_to_disk_lsn | 19530158 | +-------------------------------------+----------+ 3 rows in set (0.00 sec) このUPDATE⽂によるRedoログを⾒る (開始地点) (終了地点)
  11. UPDATEによるredo logを⾒てみる • mysqlredoコマンドでダンプ • 省略なしの出⼒結果: https://gist.github.com/tom--bo/07bdd50ec0b69e77f57fc1c68aa7b3c0 • mysqlredo –header

    –b 19529906 –e 19530158 –v –f /mysql_remote/redo/#innodb_redo/#ib_redo18 $ mysqlredo --header -b 19529906 -e 19530158 –v -f /mysql_remote/redo/#innodb_redo/#ib_redo18 (…省略) - recv_multi_rec(), lsn: 19529916 type: MLOG_UNDO_HDR_CREATE, space: 4294967279, page_no: 285 -- 1 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 40, val: 1077, -- 2 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 42, val: 1077, -- 3 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 909, val: 1077, -- 4 type: MLOG_MULTI_REC_END - recv_single_rec(), lsn: 19529954 type: MLOG_UNDO_INSERT, space: 4294967279, page_no: 285, len: 31 -- 5 - recv_single_rec(), lsn: 19529992 type: MLOG_REC_UPDATE_IN_PLACE, space: 2, page_no: 4, index_log_ver: 1, index_flag: 1, cols: 4, inst_cols: 0, uniq_cols: 1,… (省略) -- 6 - recv_multi_rec(), lsn: 19530033 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 56, val: 2, -- 7 type: MLOG_4BYTES, space: 4294967279, page_no: 285, offset: 925, val: 4294967295, -- 8 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 929, val: 0, -- 9 type: MLOG_4BYTES, space: 4294967279, page_no: 285, offset: 931, val: 285, -- 10 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 935, val: 120, -- 11 type: MLOG_4BYTES, space: 4294967279, page_no: 9, offset: 50, val: 285, -- 12 type: MLOG_2BYTES, space: 4294967279, page_no: 9, offset: 54, val: 925, -- 13 type: MLOG_4BYTES, space: 4294967279, page_no: 285, offset: 120, val: 285, -- 14 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 124, val: 925, -- 15 type: MLOG_4BYTES, space: 4294967279, page_no: 9, offset: 46, val: 2, -- 16 type: MLOG_8BYTES, space: 4294967279, page_no: 9, offset: 4168, dval: 1810, -- 17 type: MLOG_8BYTES, space: 4294967279, page_no: 285, offset: 899, dval: 1810, -- 18 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 907, val: 0, -- 19 type: MLOG_MULTI_REC_END 次ページで拡⼤
  12. - recv_multi_rec(), lsn: 19529916 type: MLOG_UNDO_HDR_CREATE, space: 4294967279, page_no: 285

    -- 1 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 40, val: 1077, -- 2 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 42, val: 1077, -- 3 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 909, val: 1077, -- 4 type: MLOG_MULTI_REC_END - recv_single_rec(), lsn: 19529954 type: MLOG_UNDO_INSERT, space: 4294967279, page_no: 285, len: 31 -- 5 - recv_single_rec(), lsn: 19529992 type: MLOG_REC_UPDATE_IN_PLACE, space: 2, page_no: 4, index_log_ver: 1, index_flag: 1, cols: 4, inst_cols: 0,… (省略) -- 6 - recv_multi_rec(), lsn: 19530033 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 56, val: 2, -- 7 type: MLOG_4BYTES, space: 4294967279, page_no: 285, offset: 925, val: 4294967295, -- 8 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 929, val: 0, -- 9 type: MLOG_4BYTES, space: 4294967279, page_no: 285, offset: 931, val: 285, -- 10 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 935, val: 120, -- 11 type: MLOG_4BYTES, space: 4294967279, page_no: 9, offset: 50, val: 285, -- 12 type: MLOG_2BYTES, space: 4294967279, page_no: 9, offset: 54, val: 925, -- 13 type: MLOG_4BYTES, space: 4294967279, page_no: 285, offset: 120, val: 285, -- 14 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 124, val: 925, -- 15 type: MLOG_4BYTES, space: 4294967279, page_no: 9, offset: 46, val: 2, -- 16 type: MLOG_8BYTES, space: 4294967279, page_no: 9, offset: 4168, dval: 1810, -- 17 type: MLOG_8BYTES, space: 4294967279, page_no: 285, offset: 899, dval: 1810, -- 18 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 907, val: 0, -- 19 type: MLOG_MULTI_REC_END 拡⼤
  13. - recv_multi_rec(), lsn: 19529916 type: MLOG_UNDO_HDR_CREATE, space: 4294967279, page_no: 285

    -- 1 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 40, val: 1077, -- 2 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 42, val: 1077, -- 3 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 909, val: 1077, -- 4 type: MLOG_MULTI_REC_END - recv_single_rec(), lsn: 19529954 type: MLOG_UNDO_INSERT, space: 4294967279, page_no: 285, len: 31 -- 5 - recv_single_rec(), lsn: 19529992 type: MLOG_REC_UPDATE_IN_PLACE, space: 2, page_no: 4, index_log_ver: 1, index_flag: 1, cols: 4, inst_cols: 0,… (省略) -- 6 - recv_multi_rec(), lsn: 19530033 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 56, val: 2, -- 7 type: MLOG_4BYTES, space: 4294967279, page_no: 285, offset: 925, val: 4294967295, -- 8 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 929, val: 0, -- 9 type: MLOG_4BYTES, space: 4294967279, page_no: 285, offset: 931, val: 285, -- 10 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 935, val: 120, -- 11 type: MLOG_4BYTES, space: 4294967279, page_no: 9, offset: 50, val: 285, -- 12 type: MLOG_2BYTES, space: 4294967279, page_no: 9, offset: 54, val: 925, -- 13 type: MLOG_4BYTES, space: 4294967279, page_no: 285, offset: 120, val: 285, -- 14 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 124, val: 925, -- 15 type: MLOG_4BYTES, space: 4294967279, page_no: 9, offset: 46, val: 2, -- 16 type: MLOG_8BYTES, space: 4294967279, page_no: 9, offset: 4168, dval: 1810, -- 17 type: MLOG_8BYTES, space: 4294967279, page_no: 285, offset: 899, dval: 1810, -- 18 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 907, val: 0, -- 19 type: MLOG_MULTI_REC_END (table: t1) (undo_space)
  14. ログを書くタイミングから探る • gdb( or rr) でmtr->added_rec()を呼び出すタイミングで⽌める • mtr(Mini TRansaction)に1⾏redoログレコードを追加したことを 記録するメソッド

    • ブレークポイントで⽌まったところでstacktraceを取る • 呼び出している関数を取り出して階層表⽰ • 結果の全体 • https://gist.github.com/tom--bo/ccaca8bceaa9ca487ff0f0869f3d4e7f
  15. 各Redoログレコードの意味する操作 id 関数 内容 1 trx_undo_header_create() 確保したundoの先頭ページを記録(rseg->insert()) 2 trx_undo_header_add_space_for_xid() undo

    headerにページの空き領域を記録 (mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_START, new_free, MLOG_2BYTES, mtr);) 3 trx_undo_header_add_space_for_xid() undo headerにページの空き領域を記録 (mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE, new_free, MLOG_2BYTES, mtr);) 4 trx_undo_header_add_space_for_xid() undo headerにページの空き領域を記録 (mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, new_free, MLOG_2BYTES, mtr);) 5 trx_undo_page_report_modify() 更新対象のレコードをundoに移す(btr_cur_upd_lock_and_undo) 6 mlog_open_and_write_index() 更新対象のレコードをインプレースに更新 7 trx_undo_set_state_at_finish() ヘッダーにトランザクションのステート(TRX_UNDO_CACHED)を書く 8 ~ 15 trx_purge_add_update_undo_to_history() undoのhistory listにundoのヘッダをノードと⾒⽴ててキューに追加する。 16 trx_purge_add_update_undo_to_history() undoのhistory listのbaseノードで全体の⻑さを更新 17 trx_purge_add_update_undo_to_history() ロールバック・セグメントの最⼤トランザクション番号を更新 18 trx_purge_add_update_undo_to_history() undo log headerにトランザクション番号を記述 19 trx_purge_add_update_undo_to_history() undo log headerに削除マークを記述。
  16. - recv_multi_rec(), lsn: 19529916 type: MLOG_UNDO_HDR_CREATE, space: 4294967279, page_no: 285

    -- 1 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 40, val: 1077, -- 2 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 42, val: 1077, -- 3 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 909, val: 1077, -- 4 type: MLOG_MULTI_REC_END - recv_single_rec(), lsn: 19529954 type: MLOG_UNDO_INSERT, space: 4294967279, page_no: 285, len: 31 -- 5 - recv_single_rec(), lsn: 19529992 type: MLOG_REC_UPDATE_IN_PLACE, space: 2, page_no: 4, index_log_ver: 1, index_flag: 1, cols: 4, inst_cols: 0,… (省略) -- 6 - recv_multi_rec(), lsn: 19530033 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 56, val: 2, -- 7 type: MLOG_4BYTES, space: 4294967279, page_no: 285, offset: 925, val: 4294967295, -- 8 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 929, val: 0, -- 9 type: MLOG_4BYTES, space: 4294967279, page_no: 285, offset: 931, val: 285, -- 10 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 935, val: 120, -- 11 type: MLOG_4BYTES, space: 4294967279, page_no: 9, offset: 50, val: 285, -- 12 type: MLOG_2BYTES, space: 4294967279, page_no: 9, offset: 54, val: 925, -- 13 type: MLOG_4BYTES, space: 4294967279, page_no: 285, offset: 120, val: 285, -- 14 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 124, val: 925, -- 15 type: MLOG_4BYTES, space: 4294967279, page_no: 9, offset: 46, val: 2, -- 16 type: MLOG_8BYTES, space: 4294967279, page_no: 9, offset: 4168, dval: 1810, -- 17 type: MLOG_8BYTES, space: 4294967279, page_no: 285, offset: 899, dval: 1810, -- 18 type: MLOG_2BYTES, space: 4294967279, page_no: 285, offset: 907, val: 0, -- 19 type: MLOG_MULTI_REC_END (table: t1) (undo_space) Undoページの準備 更新前のレコードをUndoに移動 更新対象のレコードを更新 Undo領域の後処理 (trx_undo_update_cleanup())
  17. 各Redoログレコードの意味する操作 id 関数 内容 1 trx_undo_header_create() 確保したundoの先頭ページを記録(rseg->insert()) 2 trx_undo_header_add_space_for_xid() undo

    headerにページの空き領域を記録 (mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_START, new_free, MLOG_2BYTES, mtr);) 3 trx_undo_header_add_space_for_xid() undo headerにページの空き領域を記録 (mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE, new_free, MLOG_2BYTES, mtr);) 4 trx_undo_header_add_space_for_xid() undo headerにページの空き領域を記録 (mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, new_free, MLOG_2BYTES, mtr);) 5 trx_undo_page_report_modify() 更新対象のレコードをundoに移す(btr_cur_upd_lock_and_undo) 6 mlog_open_and_write_index() 更新対象のレコードをインプレースに更新 7 trx_undo_set_state_at_finish() ヘッダーにトランザクションのステート(TRX_UNDO_CACHED)を書く 8 ~ 15 trx_purge_add_update_undo_to_history() undoのhistory listにundoのヘッダをノードと⾒⽴ててキューに追加する。 16 trx_purge_add_update_undo_to_history() undoのhistory listのbaseノードで全体の⻑さを更新 17 trx_purge_add_update_undo_to_history() ロールバック・セグメントの最⼤トランザクション番号を更新 18 trx_purge_add_update_undo_to_history() undo log headerにトランザクション番号を記述 19 trx_purge_add_update_undo_to_history() undo log headerに削除マークを記述。
  18. A: undoヘッダでstateを更新している • ログ中の7番でoffset 56を2に変えている • type: MLOG_2BYTES, space: 4294967279,

    page_no: 285, offset: 56, val: 2, • trx_undo_set_state_at_finish()でundo->state = TRX_UNDO_CACHED (=2) にしている • undoのstateの7つのうち、以下4つ以外はコミット判定 • TRX_UNDO_ACTIVE • TRX_UNDO_PREPARED_80028 • TRX_UNDO_PREPARED • TRX_UNDO_PREPARED_IN_TC • クラッシュリカバリ中で未コミットのトランザクションを復活させる 関数(trx_resurrect_update(), trx_resurrect_insert())を参照のこと
  19. まとめ • MySQLのRedoログはinnodb_redo_log • innodb_redo_logをダンプするmysqlredoコマンドを作った • UPDATE⽂のRedoログから更新される内容を確認した • 追記型ではなく逐次更新型なので、更新対象の更新前レコードは Undo領域に移動させる

    • Commitを表すログタイプはなく、undoヘッダにstateを更新すること でコミット済みかを判断している • Undoのpurgeは即座にせず、history listに追加してクライアントに結果 を返している