📝

TiDBにおけるオンラインDDLの動作

2024/04/24に公開

はじめに

PingCAPの小板橋です。はじめまして!
TiDBの入門記事から上級者編まで幅広く取り扱う本アカウント第6回目は「TiDBにおけるオンラインDDLの動作」についてをまとめていきたいと思います。
TiDBのアーキテクチャなどについては、下記の記事をご確認ください。

https://zenn.dev/koiping/articles/fc54076d2e6845

オンラインDDL実行の仕組み

TiDBの運用上のメリットとして、分散データベースのアーキテクチャ上による特性により障害発生時/何かしらのアップデート時、オンラインによる変更の時に、ダウンタイムなしを実現しています。
今回深掘りしていくのは、このオンラインでのDDL変更時の動きについてになります。
TiDBでは、アプリケーションの実行中にオンラインおよび非同期にてDDLのステートメントを仕様し、データベースのスキーマ設定を変更することができます。

イメージしやすいのは、例えば、ECサイトで利用されるデータベースにTiDBを使っていたとしましょう。すでに稼働しているアプリケーションでたくさんのユーザがそのECサイトを使ってトランザクションを張っています。ビジネス側から新たな要件が生まれました。Orderテーブルに、その商品の販売日を持たせたいというものです。新たなカラムを追加しなければいけません。となると、よくあるパターンは、サービスのメンテナンス時間を設け、そのメンテナンス時間(夜間帯)に新たなDDLステートメントの適用をさせるみたいな流れです。

ただ、TiDBについては、このオンラインですでに動いているアプリケーションがある中で無停止で新たなDDLを適用できるとしており、今回はそのオンラインDDLの実行の仕組みについてを深ぼっていくという流れになります。

DDLステートメントの種類

DDLステートメントは2種類存在します。
この種類の違いとしては、DDLステートメント実行がユーザのアプリケーションをブロックするのかどうかで分かれます。

オフラインDDLステートメント

  • ユーザからDDLステートメントを受け取った際に、変更がかかるデータベースオブジェクトをロックします。
  • その後、メタデータを変更します。

※ DDLステートメント実行中にアプリケーション側からデータの変更については、ブロックされる動きになります。

オンラインDDLステートメント

DDLステートメントをデータベースで実行される際に下記の2つの方法が使用されます。

  • Logical DDL ステートメント
  • Physical DDL ステートメント

Logical DDL ステートメント

  • データベースオブジェクトのメタデータのみを変更し、格納されているデータ(テーブル名や列名の変更など)は処理しない動きをします。

=> なので、このステートメントについては実行時間が完了までに数十ミリ秒~数秒程度になることが多いです。
つまりはアプリケーション側への影響が少ないステートメント実行になるということですね。

Physical DDL ステートメント

  • こちらは変更されるものがメタデータだけではなく、格納されているデータ含めた変更をする時のものです。
  • 例えば、テーブルへIndexを作成する際に、テーブル定義を変更するだけではなく、テーブル全体をスキャンし、インデックスを構築します。
    => TiDBでは、Physical DDL ステートメントを[reorg DDL]とも呼びます。
    このステートメントの実行には時間を要しますし、コンピュータリソースも使うので、アプリケーションのワークロードの影響を受けます。
    具体的に下記の2つの観点で影響があると言えます。

1: データの読み取りと新しいデータの書き込みのためにTiKVのCPU, I/Oリソースの消費します。
2: DDLオーナ(後ほど説明します。)として機能するTiDBノードとタスク実行のためにスケジュールされたTiDBノードは、計算実行のためCPUリソースを消費します

TiDB DDLモジュール

DDLステートメントを実行するプロキシとして動くDDLオーナーというものがあります。
現時点での動きとしては、TiDBクラスター全体でDDLオーナーは1つのTiDBノードのみとなります。
このDDLオーナーがTiDBノードから選出されると、TiDBクラスターないのDDLタスクを処理できるようになります。

DDLオーナーの選出方法

TiDBでは、etcdの選出メカニズムを使用しています。
デフォルトの動きとしては、複数のTiDBノードがDDLオーナーとして選出可能性があります。
このDDLオーナーのTiDBノードには期間があります。
ただ期間自体も更新することができますし、DDLオーナーのTiDBノードがダウンしている場合は、etcdを通して、別のTiDBノードが新しいDDLオーナーとして選出される動きとなります。

オンラインDDLステートメントの動きを見ていきましょう!

DMLによるロングトランザクションと追加のオンラインDDL トランザクションの動き

まずは、下記のようなパターンを見ていきましょう。
下記は、DMLによるロングトランザクションが走りつつ、オンラインDDLとして、カラムの追加のトランザクションが走り、データのInsert/Selectなどをするクエリが横で動くパターンです。
※ なお、今回の場合はメタデータロックは無効になっている前提となります。

基本的にこのパターンについては、何の問題もなく動作が完了する動きとなります。

DMLのショートトランザクションが連続で来る場合の動き

次に、下記のようなパターンを見ていきましょう。
下記は、DMLのショートトランザクションが連続で走りつつ、オンラインDDLとして、カラムの追加のトランザクションが走り、データのInsert/Selectなどをするクエリが横で動くパターンです。
※ なお、この場合もメタデータロックは無効になっている前提となります。

この場合だと、連続でDMLのショートトランザクション中に、カラムの追加のトランザクションが入ると、タイミングによってはDML側がエラーとなりますが、単純に再試行すれば問題は解決します。

DMLによるロングトランザクションと追加のオンラインDDL トランザクションもロングトランザクションとなる場合の動き

最後に、下記のようなパターンを見ていきましょう。
下記は、DMLによるロングトランザクションと追加のオンラインDDLのロングトランザクションが走り、データのInsert/Selectなどをするクエリが横で動くパターンです。
※ なお、この場合はメタデータロックが有効になっている前提となります。

少し前提条件を追加すると、DMLによるロングトランザクションというのは、何かしらの重要な日時バッチ処理のようなものを想像してみてください。
この時、追加のオンラインDDLのロングトランザクションが走り、日時バッチのDMLトランザクションに影響を与えてしまうとマズい、そんな時にメタデータロックをOnにしておくことで、DDL側はDMLトランザクションの処理が終わるのを待ってから処理が実行されることで影響を与えないような動きとなります。

まとめ

いかがだったでしょうか?
TiDBの世界は奥が深いです。引き続き様々な機能についてを深掘りブログ化していきたいと思います。

公式ブログ/資料等

https://docs.pingcap.com/ja/tidb/stable/ddl-introduction

https://www.youtube.com/watch?v=e8Ineja5oR8

Discussion