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

今、MySQLのバックアップを作り直すとしたら何がどう良いのかを考える旅

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for yoku0825 yoku0825
November 14, 2025

 今、MySQLのバックアップを作り直すとしたら何がどう良いのかを考える旅

Avatar for yoku0825

yoku0825

November 14, 2025
Tweet

More Decks by yoku0825

Other Decks in Technology

Transcript

  1. TL;DR MySQLのバックアップは結局xtrabackup + バイナリログが鉄板 でもmysqlshもかなりいいよ、フルバックアップも増分バックアップもmysqlshコマンドで取れるよ 日々の覚書: 最新のMySQL ShellだけでMySQLのPITR可能なバックアップを設定する(フルバックアップ編) ‐ 日々の覚書:

    最新のMySQL ShellだけでMySQLのPITR可能なバックアップを設定する(増分バックアップ編) ‐ 日々の覚書: 最新のMySQL ShellだけでMySQLのPITR可能なバックアップを設定する(実践編) ‐ yoku0825/simple-mysqlsh-pitr: PoC of PITR only using MySQL Shell ‐ 1/45
  2. 差分バックアップ A differential backup is a type of data backup

    that preserves data, saving only the difference in the data since the last full backup. Differential backup - Wikipedia 12/45
  3. 増分バックアップ An incremental backup is one in which successive copies

    of the data contain only the portion that has changed since the preceding backup copy was made. Incremental backup - Wikipedia 13/45
  4. PITR MySQLでPITRといえば今も昔もバイナリログ というか差分バックアップをバイナリログで兼ねることの方が多い フルバックアップの頻度を上げられない超巨大インスタンス(2桁テラバイト以上)ではxbの差分バックアップを使ってる事例もたまに聞く あとUberはRocksDBの差分バックアップを取りたくてxb周りで頑張ってるとか面白い話を読んだ ‐ フルバックアップを取った時点のバイナリログ情報を記録しておいて、それ以降のバイナリログを継続 的にコピーし続ける バイナリログ情報は古くはバイナリログファイル名とポジション ‐

    最近ではGTIDで済む ‐ コピーの方法もOSコマンドでも良かったりmysqlbinlogコマンドでリモートから吸い上げたり ‐ バイナリログは「データを初期コピーしてきたレプリカ」に「ソースが受け取った差分」を適用してレプリ ケーションを成立させる要素なので、「レプリカ」の部分が「フルバックアップからリストアしたdatadir」 に変わっても「バイナリログを適用していくことで時計の針を進める」のが成立する 22/45
  5. PITR バイナリログファイル単体をコピーすることは定義的には「増分バックアップ」 フルバックアップを取った時点にアクティブだったバイナリログは「差分バックアップ」としても成立する (= フルバック アップ + バイナリログ1本でリストアできるから) ‐ 一度スイッチして2本目のバイナリログファイルに差し掛かると、それは「最後の差分バックアップからの増分バック

    アップ」としてしか機能しない ‐ 「差分バックアップ」と「増分バックアップ」を混ぜるとリストアが複雑になる なのでPITRまで自動でやるなら「フルバックアップ」と「バイナリログ」だけでやるのがどう考えても楽 最終的に「差分バックアップ」の時点から「本当に戻したいタイミング」までは必ず「増分バックアップ」で埋めなければならないので、捨てる なら差分の方 ‐ 23/45
  6. PITR DBのバックアップは、一定期間(例:5分)以前のどの時点にでも戻せるかたちで(Point In Timer Restore)取得できること。 例:5分 ‐ 5分に1回バイナリログをスイッチしろってことかな 実際問題、スイッチしてないバイナリログをコピーしても「今まさに書いてるイベント」の直前まではフツーに mysqlbinlog

    でデコードできる ‐ mysqlbinlog --read-from-remote-server --raw --stop-never を使えばストリーミングで受信し続 けることもできる ( --stop-never を使わずにストリーミングじゃないファイル指定のリモートコピーもできる ) ‐ ストリーミングじゃなくてcrondでOSコマンドでも済ませられるので「ニアリアルタイムで」と言われなくてよかった ‐ 1時間って言ってもいいのかな 26/45
  7. バイナリログ ### バックアップ $ target_binlog="$(basename $(ls /path/to/backup/binlog_mysqlbinlog/*.[0-9]* | tail -1

    2> /dev/null))" $ [[ -z $target_binlog ]] && target_binlog="$(mysql -uroot -sse 'SHOW BINARY LOGS' | head -1 | awk '{print $1}')" $ mysqlbinlog -uroot -R --stop-never --raw $target_binlog ### リストア ### 「このバイナリログとそれ以降」をmysqlbinlogコマンドに引数にしたい $ target_binlog="$(cat $target_diff/xtrabackup_binlog_info | awk '{print $1}')" $ binlogs=$(for n in $(seq $binlog_sequence 1000000) ; do binlog_file="$(printf '/path/to/backup/binlog_mysqlbinlog/binlog.%06d' $n)" [[ -e $binlog_file ]] || break echo $binlog_file done) ### --start-positionはGTIDが有効ならそんなに厳密でなくていいので無視 $ mysqlbinlog --stop-datetime="$target" $binlogs | mysql -uroot 27/45
  8. 論理バックアップ MySQLは「SQLだけで自分が最後に更新されたトランザクションIDを知る」ことができない あと、「今ある行」からだけでは「今ない行」が「最初からなかったのか」それとも「最近DELETEされてなくなったの か」はわからない ‐ updated_at 的なカラムがあってレコードがイミュータブルならば差分だけ取れるといえば取れるがそれはクラウド サービスがユーザーに要求できることではない ‐ 個人的には

    MySQL Shell 使いたかったんだけどな… 論理バックアップの良いところはリモートからパラレルで実行できるところと圧縮率が良いところ セカンダリインデックスをバックアップの中に含まないので軽量な代わりにリストアに時間がかかるが 世の中、バックアップを取る回数とリストアする回数は前者の方が圧倒的に多い とはいえリストアにかけられる時間の限界というものはあるので本当は物理バックアップと論理バックアップと両方選べるのが一番いいんだ が ‐ 「差分」の用語に呪われて没 32/45
  9. ホット物理バックアップ MySQL Enterprise Backup (MEB), Percona XtraBackup (xb) ibdファイルをコピーしている間ずっとInnoDBログをコピーし続ける +

    リストアのステップでコピーし たibdファイルとInnoDBログを使ってクラッシュリカバリする InnoDBはLSN (Log Sequence Number) という単調増加のカウンターを使って「ページがど こまでストレージに永続化されたか」を管理している ibdファイルはデフォルト16kBの「ページ」単位に分かれて管理されており、それぞれのページヘッダには “最後にこ のページを更新したLSN” が書かれている これを頼りに「前回のバックアップの時のLSNより大きいLSNで更新されたページ」だけをバックアップ対象にできる 最近のMySQL Enterprise Backup(8.0.18とそれ以降)はもっと賢く(MySQLサーバと連携して)ページトラッキングするらしい ‐ まあ、これになりますよね… 33/45
  10. ホット物理バックアップ Cloneプラグイン ローカルにdatadirを, リモートのmysqldからまるっとデータ同期を, の他に、「リモートのmysqldからローカルの 別ディレクトリにdatadirをコピー」もできる リモート物理ホットバックアップ! (pg_basebackupがうらやましかったやつ) ‐ ibdファイルをコピーしている間ずっとInnoDBログをコピーし続ける

    + リストアのステップでコピーし たibdファイルとInnoDBログを使ってクラッシュリカバリする (ここはMEB, xbと一緒) ただし差分バックアップには対応していない ‐ バイナリログの切断面(ファイル名, ポジション, GTID)がなんと起動してみるまでわからない ‐ 今回は没 mysql> CLONE INSTANCE FROM user@host:port IDENTIFEID BY 'xxx' DATA DIRECTORY = '/path/to/r emote_backup'; 34/45
  11. xtrabackup(バックアップ) 差分の時にはベースバックアップのディレクトリを指定する必要があるのと ( -- stream=xbstream では差分バックアップができない) 増分バックアップはフル/差分とは関係なく常に取り続ける想定(どうせ必要だから) ### フル $

    xtrabackup -uroot --backup --target-dir="/path/to/backup/xb_full_$(date '+%Y%m%d_%H%M%S')" ### 差分 $ latest_backup="$(ls -d /path/to/backup/xb_full_* | tail -1)" $ xtrabackup -uroot --backup --incremental-basedir="$latest_backup" --target-dir="/path/to/xb_diff_$(date '+% Y%m%d_%H%M%S')" 36/45
  12. xtrabackup(リストア) ### フルバックアップからのリストア $ target="2025-11-12 14:30:00" $ target_full=$(dirname $(find /path/to/backup/xb_full*

    -type f -name "xtrabackup_binlog_info" ! -newermt "$ target" | sort | tail -1)) $ cp -r ${target_full}/* ./ $ xtrabackup --prepare --apply-log-only --target-dir=./ ### 差分バックアップがない時は --apply-log-only をつけてはいけない ### 差分のリストア $ target_diff=$(dirname $(find /path/to/backup/xb_diff* -type f -name "xtrabackup_binlog_info" ! -newermt "$ target" | sort | tail -1)) $ xtrabackup --prepare --target-dir=./ --incremental-dir="$target_diff" 37/45
  13. mysqlsh を使うと ### フルバックアップ $ mysqlsh --login-path=backup -h ipaddr --js

    -- util dumpInstance /path/to/mysqlsh_full_$(date '+%Y%m%d_ %H%M%S') ### リストア対象の識別 $ target="2025-11-12 14:30:00" $ target_full=$(dirname $(find /path/to/backup/mysqlsh_full* -type f -name "@.json" ! -newermt "$target" | so rt | tail -1)) ### @.jsonからバイナリログの情報も取り出せる -> mysqlbinlogの最初のファイルを指定するのに使 える $ jq '.binlogFile, .binlogPosition, .gtidExecuted' @.json "bin.000005" 948 "aefbe16b-aedd-11f0-8a5f-02001702f486:1-2188" 40/45
  14. まとめ MySQLのバックアップは結局xtrabackup + バイナリログが鉄板 でもmysqlshもかなりいいよ、フルバックアップも増分バックアップもmysqlshコマンドで取れるよ 日々の覚書: 最新のMySQL ShellだけでMySQLのPITR可能なバックアップを設定する(フルバックアップ編) ‐ 日々の覚書:

    最新のMySQL ShellだけでMySQLのPITR可能なバックアップを設定する(増分バックアップ編) ‐ 日々の覚書: 最新のMySQL ShellだけでMySQLのPITR可能なバックアップを設定する(実践編) ‐ yoku0825/simple-mysqlsh-pitr: PoC of PITR only using MySQL Shell ‐ 44/45