MySQL ShellのdumpInstance()/dumpSchemas()とは
MySQLからのダンプエクスポートといえば、mysqldumpでした。しかし、シリアルに動くので、大量テーブル、大量データを対象としたdump処理には時間がかかることがネックとなることがありました。
有償拡張版のMySQL Enterpriseには、Enterprise Backupという高速バックアップを実現する機能が提供されています。
MySQLを大規模運用されている企業では、問題を解決するためにEnterpriseを採用するケースもあります。(それだけがEnterpriseの採用理由ではないだろうけど)
2020-07-21にGAした「MySQL 8.0.21」と合わせて、MySQL Shellも8.0.21になりましたが、「dumpInstance()/dumpSchemas()*1」という、ダンプコマンドが追加されています。
MySQL :: MySQL Shell 8.0 :: 7.4 Instance Dump Utility and Schema Dump Utility
公式ブログにベンチマークが掲載されていますが、内部的にはパラレルで動くこともあり、非常に高速に動作します。
MySQL Shell Dump & Load part 2: Benchmarks | MySQL Server Blog
これからは、これを使わない手は無いでしょう。MySQL5.7から使えますし。
(MySQL5.6のExtended Suportは2021年2月に終了するので、この先対応されることも無いでしょうし、5.7以降に引き上げる計画を立てましょう)
なお、MySQL ShellはX Protocol必須の機能とそうでない機能がありますが、この「dumpInstance()/dumpSchemas()」はX Protocol不要なようで、従来どおりTCP:3306ポートで接続すれば実行できます。
RDSとAuroraに対しては、そのままでは動かない件
ダメなんだろうな、と思って試してみて、やっぱりダメでした。
実際にAurora MySQL 5.7に対して実行すると
Util.dumpInstance: Unable to acquire global read lock: MySQL Error 1045 (28000): Access denied for user <使用したユーザー> (using password: YES) (RuntimeError)
というメッセージが出ます。
MySQL ShellのdumpInstance()の挙動については三谷さんの MySQL Shell dumpInstance でバックアップ中はDDL が待機させられる - mita2 database lifeが詳しいので、詳細はこちらを読んで頂くとして、ここで
FLUSH TABLE WITH READ LOCK と LOCK INSTANCE FOR BACKUP でロックする
MySQL Shell dumpInstance でバックアップ中はDDL が待機させられる - mita2 database life
という記述が目に止まります。(LOCK INSTANCE FOR BACKUPはMySQL8.0からのコマンド。MySQL5.7に対する実行時には使用されない。)
たしかに、FLUSH TABLE WITH READ LOCKはglobal read lockを取得します。そのことは、MySQLの公式ドキュメントにも書いてあります。
・FLUSH TABLES WITH READ LOCK
開かれているすべてのテーブルを閉じ、グローバルな読み取りロックを保持しているすべてのデータベースのすべてのテーブルをロックします。これは、特定時点のスナップショットを取得できる、Veritas または ZFSなどのファイルシステムがある場合にバックアップを取得するための非常に便利な方法です。このロックを解放するには、UNLOCK TABLES を使用します。FLUSH TABLES WITH READ LOCK は、グローバルな読み取りロックを取得しますが、テーブルロックは取得しないため、テーブルロックと暗黙的なコミットに関して LOCK TABLES および UNLOCK TABLES と同じ動作には従いません。
MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.7.6.3 FLUSH 構文
必要な権限ですが、MySQLの公式ドキュメント上、
FLUSH を実行するには、RELOAD 権限が必要です。あとで説明されているように、特定のフラッシュオプションには追加の権限が必要になることがあります。
MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.7.6.3 FLUSH 構文
とありつつも、この「FLUSH TABLES WITH READ LOCK」について、具体的に追加が必要な権限が記載されているわけではありません。
AWSのナレッジセンターのドキュメント(公開情報)には、MySQL Shell-dumpInstanceではなくmysqldumpのエラーの話として、以下のことが書いてあります。
「FLUSH TABLES WITH READ LOCK」を実行できませんでしたというエラー
mysqldump で --master-data オプションを使用してデータをエクスポートすると、次のようなエラーが表示されることがあります。
「mysqldump: 'FLUSH TABLES WITH READ LOCK'を実行できませんでした: 'user'@'%'のアクセスが拒否されました (パスワード使用: はい) (1045)」
- master-data オプションは FLUSH TABLES WITH READ LOCK を取得します。これには、Amazon RDS マスターのユーザーが持っていない SUPER 権限が必要です。また、Amazon RDS は GLOBAL READ LOCK をサポートしていません。MySQLがログ情報を取得するために CHANGE MASTER TO ステートメントを実行すると、バイナリログファイルの名前と位置 (座標) が mysqldump ファイルに記録されます。詳細については、ER_ACCESS_DENIED_ERROR に関する MySQLのドキュメントを参照してください。
「FLUSH TABLES WITH READ LOCK」には「SUPER」が必要?
MySQL本家の公式ドキュメントには、そんなこと書いてないんですけど。
よろしい、ならば試してみよう。
Linux on VirtualBoxにMySQL5.7と8.0を用意して、SUPER権限の無いユーザーから「FLUSH TABLES WITH READ LOCK」投げてみます。
mysql> select version(); +-----------+ | version() | +-----------+ | 5.7.28 | +-----------+ 1 row in set (0.00 sec) mysql> show grants\G *************************** 1. row *************************** Grants for test2@%: GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'test2'@'%' 1 row in set (0.00 sec) mysql> FLUSH TABLES WITH READ LOCK; Query OK, 0 rows affected (0.00 sec)
通るじゃないですかやだー。
エビデンス貼らないけど、MySQL ShellからのdumpSchemas()も動いたし。
以下は、RDSおよびAurora MySQLマスターユーザー(FLUSH TABLES WITH READ LOCK取れない)と、ノーマルなMySQL5.7、MySQL8.0でrootユーザーの権限から「SUPER」を除外したユーザー (FLUSH TABLES WITH READ LOCK取れた)の権限一覧です。
DB | 権限 |
---|---|
ノーマルMySQL5.7 | GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER,CREATE TABLESPACE ON *.* |
AuroraMySQL5.7 | GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, LOAD FROM S3, SELECT INTO S3, INVOKE LAMBDA, INVOKE SAGEMAKER, INVOKE COMPREHEND ON *.* |
RDS MySQL5.7 | GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER ON *.* |
ノーマルMySQL8.0 | GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER ON *.* |
RDS MySQL8.0 | GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER ON *.* |
MySQL5.7のところに「CREATE TABLESPACE」の有無の差がみつかったのですが、まさかコレが原因なわけないよね、と思いつつ、これもノーマル側で権限剥がして試したところ、やはり関係なかったです。これもエビデンス貼らないけど。
MySQL8.0については、デフォルトで作成されるrootユーザーのSHOW GRANTSで3行表示されますが、別途作ったユーザーにRDS/MySQL8.0のマスターユーザーと同じ権限をつけても、dumpSchemas()が動くことを確認しています。
まあ、仕方がないですよね。色々制約ありつつも、それ以外のところがめちゃくちゃ便利なので、これ1つでRDSやAuroraを弾く理由にはならないし。
そもそもバックアップ周りは、ほぼ何も気にしなくていいのがマネージドデータベースの良いところ。
なお、AWSのドキュメントにおけるmysqldumpのエラーについては、回避方法までちゃんと記載されています。
回避方法あった!だがしかし。。。
MySQL Shellのドキュメントに、以下の記載があります。
consistent: [ true | false ]
Enable (true) or disable (false) consistent data dumps by locking the instance for backup during the dump. The default is true. When true is set, the utility sets a global read lock using the FLUSH TABLES WITH READ LOCK statement. The transaction for each thread is started using the statements SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ and START TRANSACTION WITH CONSISTENT SNAPSHOT. When all threads have started their transactions, the instance is locked for backup and the global read lock is released.
https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-utilities-dump-instance-schema.html
(DeepL翻訳)
ダンプ中にバックアップ用のインスタンスをロックすることで、一貫性のあるデータダンプを有効(true)または無効(false)にします。既定値は true です。true が設定されている場合、ユーティリティは、FLUSH TABLES WITH READ LOCK ステートメントを使用してグローバル読み取りロックを設定します。各スレッドのトランザクションは、SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READおよびSTART TRANSACTION WITH CONSISTENT SNAPSHOTステートメントを使用して開始されます。すべてのスレッドがトランザクションを開始すると、インスタンスはバックアップのためにロックされ、グローバルリードロックが解除されます。
たしかに、
MySQL 接続先データベース JS > util.dumpSchemas(["スキーマ名"],"出力先ディレクトリ",{consistent:false})
のように、consistent:falseのオプションを指定すると、RDSやAuroraが相手でも動くようにはなりました。
しかし、「When true is set(trueが設定されているとき)」が、後ろのどの部分までにかかっているのか、これだとちょっとわからないですね。「The transaction for each thread is」以降にもかかっているのか、かかっていないのか(trueのときしか後述の挙動にならないのか)で、全然意味が違ってしまいます。
これ、「When true is set(trueが設定されているとき)」が文の最後までかかっているとなると、一貫性のあるdumpは取れなくなりそう。
その場合(consistent:falseだと「SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ and START TRANSACTION WITH CONSISTENT SNAPSHOT」が適用されず、一貫性が全く保証できない場合)、RDSやAuroraの場合、RDSならばリードレプリカを立てつつレプリケーションを停止した状態からconsistent:falseで取得、Auroraの場合は、RDSや生のMySQLをレプリカを立ててレプリケーションを切るか、スナップショットから別インスタンスを立てつつ、そこからconsistent:falseで取得する、という方法が取れると思います。
mysqldumpで---single-transaction オプション付与するとLOCK TABLE権限なくても一貫性のあるダンプが取れるのと同じような動きをしてくれているとありがたいんだけどなあ。
確かめるの大変そう。