メタデータの末尾にスキップ
メタデータの先頭に移動

オンラインのスキーマ変更

Clustrixはテーブルへのreadまたはwriteのブロッキング無しにオンラインでスキーマを変更することができます。These changes can range from as simple as adding an index or column to completely redesigning the schema. Many other database systems require partial or full table locks while schema changes process each row moving the data structure into its new form.

Clustrixデータベースは新しい一時的なコンテナ(あるいはコンテナのセット)を作成し、データをその新しい構造にコピーすることで、ロッキングの問題を回避しています。変更されているテーブルへのDML操作がある場合は、一時的なトランザクションログは古いコンテナンへのwriteあるいはupdateのトランザクションを記録し、その後新しいコンテナに適用します。全ての元のレコードがコピーされ、記録されたトランザクションが処理されると、ALTERトランザクションがcommitされ、新しいテーブルがliveになり、古いテーブルが削除されます。

Clustrixはalterの間のreadの一貫性を維持します - ALTERがcommitする前にテーブルへ実行されるreadとwriteクエリは、元のテーブルスキーマを見ます。. ALTERがcommitした後のreadとwriteは新しいスキーマを見ます。一つのクエリあるいはユーザの視点からすると、ALTERは瞬間的です。

準備

Clustrixデータベースエンジンは簡単にオンラインでどのようなサイズのテーブルでもスキーマの変更をサポートするように設計されていますが、以下のbest practiceがアプリケーションへの否定的な予期せぬ影響を最小限にするのに役立つです。以下のものが含まれます: 

  1. データのバックアップ

  2. 隔離された環境で新しいスキーマをアプリケーションのクエリでテストするクエリのプランが否定的な影響を受けていないことを確認するために、EXPLAIN <query> プランの出力を変更の前後で比較します。 

  3. ピークではない時間あるいはメンテナンスwindowの間に、スキーマの変更を実行します。

  4. 十分なディスク容量があることを書くにしてください(以下を参照)。

  5. リプリケーションの影響を理解し、それに応じてプランを変更します。

ディスクスペース要件の見積もり

ALTERを実行する前にどれだけのスペースが必要かを理解するために、私たちがBigCと呼ぶClustrixのガベージコレクションの処理をまず理解する必要があります。

BigCは基本的にトランザクションが完了するにつれて時間を常に前に進むチェックポイントです。The BigC value of the cluster (shown in system.stats) will always show the point in time at which the longest currently-running transaction has started. Any explicit transaction will “pin” BigC. While garbage collection is pinned, the cluster will log any write, delete, update, and DDL transactions into the undo-log for the possible event in which the long-running transaction fails and needs to be rolled back.

Because ALTERs are DDL transactions, they pin BigC which means that all garbage collection is suspended during the ALTER.

ALTERのためにどれだけの空き領域が必要かを計算するために、以下のそれぞれを評価しなければなりません:

  • 現在の総使用領域。
  • 望ましい最小の総空き領域。 
    • ClustrixDBは空き領域が5%以下になると長く実行しているトランザクションをkillするでしょう。これによりALTERはロールバックされるでしょう。 
    • スキーマの変更の間は少なくとも最小で10%の空き領域を確保する予定です。
  • ALTERされるテーブルのサイズ。 
    • テーブルのコピーを保持するのに十分な空き領域があることを確認。
    • テーブルのサイズは system.table_sizesから推測することができます。
  • ALTERが完了するのに掛かる時間の推定。 
    • クラスタのサイズによります(例えば、サーバが多いと速くなります)。 
    • これは、以前のもっと小さなALTERの操作のスピードに基づいて推測することができます。 
  • 新しいデータの成長率。
  • undoログの成長率。ALTERの間の全てのINSERT、UPDATE、DELETEのundoログは蓄積されるでしょう。
  • リプリケートしている場合は、binlogの成長率。 
    • binlogの切り取りはまだ実行されますが、ディスク容量はBigCが非固定になるまで解放されないでしょう。

計画された成長とテーブルコピーのサイズに加えて現在の消費容量を合計した時に、計画のディスクの残容量の少なくとも10%がまだ残っている必要があります。そうでなければ、ALTERを開始する前にback binlogの切り取り、テーブルの剪定、あるいはサーバを追加してクラスタを拡張することをお勧めします。

レプリケーションの懸念

リプリケートされた環境でALTERを実行するには、計画の追加が必要です。The ALTER can be performed in-line with replication, or independently, depending on whether schema structure is changed. Whenever possible, it is highly recommended to allow the ALTER to run over the replication stream in order to avoid errors in replication where transactions are looking for either the old or new schema when the other is present.

リプリケーションの上でALTERを実行することは、ALTERが最初にマスター上で、次にスレーブ上で順番に実行されなければならないことを意味します。更に、スレーブはリプリケーションストリームの中でALTERを順番に実行しなければなりません。スレーブがALTERを完了するまでの間、他のwriteは一時停止されます。大きなテーブルのALTERの場合、これによりスレーブがマスターより遅れることがあります。Plan to adjust binlog retention on the master and monitor replication regularly to ensure the slave does not fall off the back of your master's binlog retention during this process.

列のマッチング

行ベースのbinlogを使ってリプリケートする場合、列の同期が重要です。RBR (row-based replication) は古い行と新しい行の両方をスレーブに送信し、新しい行が適用される前に古い行が一致する必要があります。Alters that modify columns must be executed within replication and in sequence to avoid slave errors trying to applying writes for one schema to the other.

ステートメントベース(SBR)のbinlogを使ってリプリケートしている場合は、ステートメントは古いスキーマと新しいスキーマの上で同じく実行するという条件でもっと柔軟性が許可されています。However, for environments with high concurrency, it is extremely difficult to asses whether all statements are equivalent on the old and schemas. 

Exceptions to these column matching concerns include ALTERs adding an index, changing the storage type, or number of slices. これらは行の挿入または更新に影響しないため、それらはリプリケーションストリームの外部で並行して実行されるかも知れません。

オンラインスキーマ変更のスケールアウトの懸念点

ユーザデータでのALTERのパフォーマンスは環境の特異性と負荷によって変わるでしょう。以下をガイダンスとして解釈し、経験とテストに基づいて適用してください。

単純、小さなテーブルの変更

約 N*10^6 行のテーブルまたは 同時実効制御が軽い場合、ALTERはライブでクラスタのサイズ、行数、全体の負荷によりますが、数分以内に完了すべきです。Cache and query plan refreshes occur regularly and the automatic refresh should handle any performance issues.

オンラインスキーマ変更での中程度のスケールアウトの問題点

高い同時実行性あるいはn*10^7の行のテーブルは、ALTERが完了してすぐにクラスタのパフォーマンスの後遺症を経験するかも知れません。Clustrixはそれぞれのテーブルについて統計とクエリプランを格納し、それらの値はキャッシュされます。Clustrixはパフォーマンスの影響を避けるためにそれらのキャッシュを十分早くリフレッシュあるいはフラッシュしないかも知れません。ですので一端ALTERが完了すれば以下のコマンドを使ってキャッシュをフラッシュします:

clustrix> ALTER TABLE ....
$ clx cmd 'mysql system -e "call qpc_flush()"';
$ clx cmd 'mysql system -e "call pdcache_update()"';

qpc_flushとpdcache_updateはノードごとを基本として実行されることに注意してください。従って、これらはclx cmd ユーティリティを使って実行されなければなりません。

ALTERの完了とキャッシュのフラッシュの間の遅延を避けるために、command && command && command のようにシェル内でこれらのコマンドを連結することがお勧めです。

オンラインスキーマ変更に関する極端なスケールアウト

N*10^8以上の行のテーブルに関しては、ALTERは完了するまで数時間あるいは数日も掛かるかもしれません。容量についての考慮、同時実効制御等々に関して上の全てのルールと推奨に特に注意を払ってください。更に、一端ALTERが完了すると、BigCガベージコレクションはALTERに追いつくまで長期間に渡ってシステムにパフォーマンスの影響を与えるかも知れません。Should this occur during your application's peak hours, you may want to temporarily throttle BigC via the adjustment of the following system variable to its minimum value of 524,288:

clustrix> set global layer_copy_speed = 524288;

以下のクエリを使って、どれだけの数のキューされたlayer_mergesを残っているか、それらはいつ開始されたかを測定することができます。Once the longest running merges have fairly recent start timestamps, you are probably past any merges related to your ALTER.

clustrix> select * from system.layer_merges where finished is null order by start;

一端layer_mergesが追いつくと、 set global layer_copy_speed = default;を使ってlayer_copy_speed変数を設定することができます。

If you have adequate free space you may want to pin BigC with a separate transaction so you can control the release to a time of your choosing. これを実施するには、 別個のセッションでCOMMIT無しの明示的なBEGINを使って、一端ピークを過ぎると、COMMITまたはセッションからctrl+cを実行します。しかしながら、ほとんどの場合には本番の負荷への過大な影響を避けるには layer_copy_speed を下げるので十分だということを発見しました。人為的にBigCを固定することはidle_trx_timeout killerの影響を受けやすいということを心に留めておいてください。Be sure to check that global in the database to prevent that session from being killed.

オンラインスキーマ変更の例

以下の例では、1テラバイトのテーブルが追加の列を含むようにALTERされるでしょう。必要な時間を見積もることは科学というよりも芸術であり、ALTERを実行するクラスタのサイズにも依存します。この例では、以前に小さなテーブルで行ったALTERによって、1テラバイトのテーブルがALTERを完了するまで~25時間掛かると信じるに至りました。

10TBのクラスタの空き容量の計画について考えてみましょう: 

容量の要求の説明
必要とされるもの

クラスタは現在のところ10TBの利用可能な容量があり、内部走査のためにシステムが5%を確保すると知っています。これを超過すると、writeはブロックされ、ALTERはロールバックされるかも知れません。

0.5 TB
負荷の急増を処理するために常に少なくとも10%の空き容量を残すようにユーザがリクエストした。1.0 TB
新しいテーブルは追加の列により1TB以上のビットを消費するでしょう。バイトの行数倍で計算できますが、1.1TBと仮定します。これはコピーのため、ALTERが完了するまでこの容量は確保しなければなりません。1.1 TB

クラスタ全体では、1日あたり約~1.5TBのwriteトランザクションを受け取ります(binlogへのwriteを含む)、ですので (1.5 / 24) * 25 hours = 1.5625 TB

1.6 TB
ALTERを安全にbeginするために必要な総空き容量:4.2 TB

慎重な見積もりとしては、ALTERが完了するにはクラスタ上に少なくとも4.5TBの利用可能な容量があるべきです。

ALTERのパフォーマンス

外部からクラスタに接続している場合は、もしセッションが切断されたら以下の長く実行しているトランザクションが失敗しロールバックするだろうことを忘れないでください。screenまたはその他のなんらかのdetach可能なターミナルの利用をお勧めします。

一つのターミナルの接続を利用して、Session Aを初期化しBigCを固定するトランザクションを開始します:

clustrix> set global layer_copy_speed = 524288; -- optional
clustrix> BEGIN;

別の端末では、SessionBを初期化しALTERを開始します。以下の3つのコマンドがぴったりと連続して実行される必要があるため、それらを以下のように一つに連結します:

mysql -e "ALTER TABLE database.hugetable ADD COLUMN foo varchar(255)"; \
clx cmd 'mysql -e "call system.task_run(\'pdcache_update\')"'; \
clx cmd 'mysql -e "call system.qpc_flush()"'

ずっと後、ALTERとその後キャッシュフラッシュが終わった後で、Session Aに保持されているトランザクションを開放することができます。ガベージコレクションは多少重いため、ロードのピークが過ぎるまで待ちたいと思うかも知れませんが、layer_merges を小さくすると分からないくらいになることが分かりました。

セッションAのターミナルから:

clustrix> COMMIT;

結果の観察

Over the next few hours (depending on the size of your ALTER) you can examine the system.layer_merges relation for status of post-alter cleanup. この時間の間、システムができるだけ早く空き容量を回復できるように、他の大きな延期することができるタスクを避けます。

一端終了すると、layer_copy_speed を default に再設定します:

clustrix> set global layer_copy_speed = default;
TOP
inserted by FC2 system