メタデータロック (MDL) とは、データ定義言語 (DDL) 操作中にテーブルメタデータの整合性を確保するデータベースの内部ロックです。標準的な読み取り/書き込みトランザクションは対象テーブルの MDL 読み取りロックを取得する必要があります。一方、DDL 操作では対象テーブルの MDL 書き込みロックが必要です。DDL ステートメントを実行する場合は、メタデータロックに関連する次の問題に注意してください。
-
ブロッキング
MDL 読み取りロックを保持した長時間トランザクションにより DDL 操作がブロックされ、MDL 書き込みロックの取得待ちが長時間に及んだ結果、失敗する可能性があります。また、MySQL は MDL にフェアロックメカニズムを使用しているため、ブロックされた DDL ステートメントは、MDL 読み取りロック取得待ちのすべての新規トランザクションもブロックします。
-
デッドロックのリスク
複数の DDL ステートメントとトランザクションを同時に実行すると、MDL を異なる順序で要求する可能性があり、デッドロックにつながることがあります。
-
排他性
MDL 書き込みロックは排他ロックです。DDL 操作が MDL 書き込みロックを取得すると、すべての新規トランザクションは MDL 読み取りロックを取得できないためブロックされます。これにより、トラフィックが 0 まで低下する可能性があります。MySQL はオンライン DDL をサポートしていますが、これらの操作でも重要な段階で短時間の MDL 書き込みロック取得が必要であり、テーブルのロックを完全に回避することはできません。
これらの問題が DDL 実行中に発生すると、ブロックされたアプリケーション接続が大量に発生し、深刻な場合は一時的にトラフィックが 0 まで低下する可能性があります。PolarDB-X は、これらのメタデータロックに起因する問題に対し、リスクを排除するための最適化を提供します。
プリエンプティブ MDL 最適化
PolarDB-X はプリエンプティブ MDL 最適化をサポートします。この最適化により、DDL 実行中にメタデータロックが原因で発生するブロッキングのリスクを排除できます。
サポート対象バージョン
この機能は、PolarDB-X 5.4.17-16952556 以降で利用できます。
仕組み
MDL 書き込みロックが必要な DDL ステートメントを実行する際に、ロック取得の待機時間が長すぎる場合、PolarDB-X は DDL をブロックしている長時間トランザクションの接続を自動的に終了します。
次の表は、この最適化がない場合に、長時間トランザクションによって DDL ステートメントと新規トランザクションがブロックされるシナリオを示しています。
表 1
|
手順 |
セッション 1 |
セッション 2 |
セッション 3 |
|
1 |
begin; |
- |
- |
|
2 |
insert into tb0 values(1); -- tb0 の MDL 読み取りロックを取得します。 |
- |
- |
|
3 |
-- 長時間トランザクションをシミュレートするため、トランザクションをコミットしません。 |
- |
- |
|
4 |
- |
alter table tb0 add column col int; -- tb0 の MDL 書き込みロックの取得を試みますが、長時間トランザクションによってブロックされます。 |
- |
|
5 |
- |
- |
select id from tb0; -- tb0 の MDL 読み取りロックの取得を試みますが、ブロックされます。 |
次の出力は、プリエンプティブ MDL 最適化を有効にした場合の実行プロセスを示しています。手順は表 1 と同じです。
-- セッション 1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into tb0 values(1);
Query OK, 1 row affected (0.16 sec)
mysql> select version();
ERROR 2013 (HY000): Lost connection to MySQL server during query
No connection. Trying to reconnect...
Connection id: 46
-- セッション 2
mysql> alter table tb0 add column col int;
Query OK, 0 rows affected (29.17 sec)
-- セッション 3
mysql> select id from tb0;
Empty set (1.04 sec)
出力のとおり、プリエンプティブ MDL 最適化により、セッション 1 の長時間トランザクションの接続が終了します。これにより、セッション 2 の DDL ステートメントは正常に実行され、セッション 3 の新規トランザクションも通常どおり実行されます。
分散メタデータデッドロック検出
PolarDB-X は分散メタデータデッドロック検出をサポートします。この機能は、DDL 実行中にメタデータロックに起因するデッドロックを検出して解消し、DDL 操作とその他のトランザクションが処理を継続できるようにします。
サポート対象バージョン
この機能は、PolarDB-X 5.4.17-16952556 以降で利用できます。
仕組み
PolarDB-X は、トランザクションと DDL ステートメント間のロック待機関係を定期的にスキャンします。デッドロックが検出されると、PolarDB-X は競合しているトランザクションの 1 つを自動的に終了し、DDL とその他のトランザクションが処理を継続できるようにします。
次の表は、メタデータロックに起因する典型的なデッドロックシナリオを示しています。
表 2
|
手順 |
セッション 1 |
セッション 2 |
セッション 3 |
セッション 4 |
|
1 |
begin; -- トランザクション 1 を開始します。 |
begin; -- トランザクション 2 を開始します。 |
- |
- |
|
2 |
insert into t1 values(1); -- t1 の MDL 読み取りロックを取得します。 |
insert into t2 values(1); -- t2 の MDL 読み取りロックを取得します。 |
- |
- |
|
3 |
- |
- |
alter table t1 add column col int; -- DDL 1 を開始します。t1 の MDL 書き込みロックの取得を試みますが、ブロックされます。 |
alter table t2 add column col int; -- DDL 2 を開始します。t2 の MDL 書き込みロックの取得を試みますが、ブロックされます。 |
|
4 |
insert into t2 values(2); -- フェアロックメカニズムにより、t2 の MDL 読み取りロックの取得を試みますが、DDL 2 によってブロックされます。 |
insert into t1 values(2); -- フェアロックメカニズムにより、t1 の MDL 読み取りロックの取得を試みますが、DDL 1 によってブロックされます。 |
- |
- |
次の出力は、PolarDB-X が分散メタデータデッドロック検出を使用して表 2 のデッドロックを解消する方法を示しています。実行手順は表のとおりです。
-- セッション 1
mysql> begin;
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t1 values(1);
Query OK, 1 row affected (0.12 sec)
mysql> insert into t2 values(2);
Query OK, 1 row affected (0.02 sec)
mysql> commit;
Query OK, 0 rows affected (0.99 sec)
-- セッション 2
mysql> begin;
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t2 values(1);
Query OK, 1 row affected (0.08 sec)
mysql> insert into t1 values(2); -- MDL デッドロックが検出されました。接続が強制終了され、トランザクションがロールバックされます。
ERROR 2013 (HY000): Lost connection to MySQL server during query
No connection. Trying to reconnect...
Connection id: 14
Current database: d0
-- セッション 3
mysql> alter table t1 add column col int;
Query OK, 0 rows affected (2 min 38.30 sec)
-- セッション 4
mysql> alter table t2 add column col int;
Query OK, 0 rows affected (2 min 59.85 sec)
表 2 のデッドロックシナリオが作成されると、PolarDB-X はデッドロックを検出し、トランザクション 2 を終了することを選択します。このロールバックにより、トランザクション 2 が保持していたロックが解放され、DDL 1 と DDL 2 が完了できるようになります。
デュアルバージョン MDL 最適化
論理実行される DDL について、PolarDB-X はデュアルバージョンメタデータと、それに対応するデュアルバージョンのメタデータロックをサポートします。これにより、これらの DDL 操作はテーブルをロックすることなく、またトラフィックが 0 まで低下することもなく実行できます。
制限事項
この最適化は、PolarDB-X のすべての論理実行 DDL ステートメントに適用されます。DDL ステートメントが論理実行されるかどうかを確認するには、オンライン DDLをご参照ください。
仕組み
PolarDB-X は、オンラインスキーマ変更の原則に基づいて論理 DDL を実装します。論理 DDL 操作のメタデータバージョンを複数の小さなバージョンに分割し、PolarDB-X インスタンス内でメタデータを安全に進化させます。たとえば、PolarDB-X の CREATE GLOBAL INDEX DDL ステートメントには、ABSENT(Vn)、DELETE_ONLY(Vn+1)、WRITE_ONLY(Vn+2)、PUBLISH(Vn+3) という複数のバージョン遷移が含まれます。さらに、PolarDB-X は、これらのマイナーバージョンそれぞれに個別のメタデータロックをバインドします。
オンラインスキーマ変更の仕組みにより、2 つのメタデータバージョンは、クラスター内の異なるコンピュートノード間だけでなく、単一のコンピュートノード内でも共存できます。そのため、論理 DDL 操作がメタデータバージョンの進化を開始すると、PolarDB-X は各遷移の間、古いメタデータバージョンに対してのみ MDL 書き込みロックを取得します。これにより、新規トランザクションは新しいメタデータバージョンにアクセスし、対応する MDL 読み取りロックを取得できます。
デュアルバージョン MDL 最適化により、PolarDB-X の論理 DDL 操作は、テーブルをロックすることなく、またトラフィックが 0 まで低下することもなく実行できます。