データベーススキーマに変更が加えられるとき、例えば、テーブルにフィールトの追加を行うなど、より注意を払って処理するべきです。さもないと、どのように特定のテーブルが作成されたかの解釈が一致しないため、異なるノード間で混乱が多少起こります。
EXECUTE SCRIPT (slonik) /schemadocddlscript( integer, text, integer ) (ストアド関数)で変更を Slony-I に伝えるのであれば、全てのノード上のトランザクションストリームの中の同一時に変更が有効になることを確信して構いません。スキーマの変更を行うのに、機能停止の何かを選べるのであれば事はさほど重要ではありませんが、トランザクションがシステムを通して未だ曲がりくねって進んで行く途中で更新をしたい場合、これは必要です。
スキームを変更するために ALTER TABLE を行うのであれば、EXECUTE SCRIPT を使用する必要があります。そうでなければ、 こので説明されている、変更されたテーブル上のトリガがスキーム変更を考慮しないと言う問題に遭遇します。
EXECUTE SCRIPT について "特別なこと"に 2、3 の解説を書く価値があります。
スクリプトは既にトランザクション内で実行されているため、スクリプトにはトランザクションの BEGIN もしくは END 命令文を含んでは決していけません。PostgreSQL バージョン 8 では、入れ子トランザクションの導入によりこの必要性が多少変更するかもしれませんが、スクリプト内の機能はトランザクション内にラップされていることを今まで通り意識する必要があります。
もしも、何らかの壊れた所がスクリプト、もしく特定のノードでどのように実行するかにある場合、そのノードの slon デーモンはパニックに陥りクラッシュします。そのノードを再稼働させると、よりありそうなことは、DDL スクリプトを反復し、ほぼ確実に最初に起こったのと同じように 2 回目の故障になります。この筋書きは"マスタ"ノードに入り、故障を繰り返すのを防ぐ事象を削除する必要があることが判りました。
その時点で、slon がパニックとなるのはたぶん正しい回答です。と言うのは故障したノードに DBA(データベース管理者)が向かい、障害のある事象を削除し、slon を再起動する以前に、手作業で物事を修復することが可能になるからです。プロバイダノードの DDL 変更の後に行われた更新は、サブスクライバに向かおうとする待状態になっていると考えて差し支えありません。ここにおいては、正常になるための DDL 変更に依存して行われる更新に期待を賭けてはなりません。
EXECUTE SCRIPT を実行すると、slonik が特定のセットのそれぞれのテーブルに対して、排他テーブルロックを要求する結果になります。
先ずロックの要求から始まり、そしてe Slony-I トリガーを削除するテーブルの変更が行われます。
BEGIN; LOCK TABLE table_name; SELECT _oxrsorg.altertablerestore(tab_id);--tab_id is _slony_schema.sl_table.tab_id
スクリプトが実行された後、それぞれのテーブルは、オリジンの更新を収集する、もしくはサブスクライバ上での更新を拒否するトリガーが元の状態に"リストア"されます。
SELECT _oxrsorg.altertableforreplication(tab_id);--tab_id is _slony_schema.sl_table.tab_id COMMIT;
頻繁に更新されるシステムにおいては、全ての必要とされるロックに現実的に問題なく関与するため、"横あいからの操作"は厄介でしょう。ロックはデッドロックになることもあります。このことに対しての 2 つの対応法があります。
より小さいテーブルのセットからなるレプリケーションセットを定義することができます。定義することで、DDL スクリプトが所定の位置に置かれるように、より少ないロックでこと足ります。
もし特定の DDL スクリプトが 1 つのテーブルにだけ影響を及ぼすのであれば、全てのアプリケーションテーブルをロックする必要はありません。
データベーススキーマを更新するのに必要なものと衝突する可能性のあるロックをアプリケーションに要求させないため、短時間のアプリケーションの中断が必要かも知れません。
残念なことに、これはそれでもなお、DDL 機能の使用はなんとなく脆弱で、かなり危険であることを意味しています。杜撰かつ無頓着なやり方で DDL の変更を決してしてはいけません。もし、アプリケーションが適切な安定した SQL スキーマを所有していない場合、レプリケーションのために Slony-I を使用することは、問題と失敗を含んだ危険に満ちたものになります。関係する問題点についての論議は ロックの問題 の節を参照してください。
ここに、Varlena General Bits Slony-I スキーマ変更管理をどうするかについての記事があります。
レプリケートされているテーブルに対する DDL 修正を伝播するため EXECUTE SCRIPT を使用することが絶対不可欠である限り、何らかの別の方法で処理をしたいと考えるいくつかの種類の変更があります。
内部関数など、 Slony-I がレプリケートしない、トリガーを所有しない種々の種類のオブジェクトがあり、もしそれらの実際にはロックされる必要の無い全ての多くのテーブルを EXECUTE SCRIPT がロックするレプリケーションセットに付随するそれらの更新を伝播させようとすると、必ずと言ってひどい目に逢うでしょう。
常に使用されていないストアドプロシージャを伝播させるのであれば(少しの時間、ノード間の同期を取らないことを心配するような)、Slony-I の特別な使用を行わないで、それぞれのノードに対し psql を使用して、単に送出すれば良いでしょう。
全てのノード上のトランザクションストリーム内で同一の場所にある伝播されるオブジェクトは大したことでないのであれば、テーブルはロックされる必要が無くなり、従って、テーブルを含まないレプリケーションセットを作成し、そこに全ての適切なノードをサブスクライブし、そしてその"空のセット"を指定して、EXECUTE SCRIPT を使用します。
そこでの性能を向上させるため、いくつかのレプリケートされたノード上に追加のインデックスが欲しい場合があります。
例えば、トランザクションを構成するテーブルは"オリジン"ノード上の参照整合性に関連したインデックスのみ必要で、どうしても必要なものを除いて、それ以上のインデックスを追加せず、性能を極大化します。レプリケーションノードに対して稼働するレポートの性能を向上するための追加的インデックスを付加してはいけないことはありません。
レプリケーションノードに制約関連の追加的インデックスを付加することは賢いことでなく、あたかも、そこに問題を見つけるように、サブスクライバが、制約に違反するオリジンからやってくる変更を適用できないため、レプリケーションが失敗することに繋がります。
とは言っても、性能向上を目的とする何らかのインデックスの追加は大きな取り引きではありません。それらの追加のためにEXECUTE SCRIPT を使用しないことはほぼ確実でしょう。それはあるレプリケーションセットがテーブルをロックし、ロックを解除することになり、そして、現在存在するオブジェクト上のロックによって、事象を適用することができなくされることになり、変更が可能になる以前に何回か再試行しなければならなくなります。代わりに、psql を使用するようなことで"直接"インデックスを適用するのであれば、テーブルロックが導入された時刻を決定することが可能です。テーブルにインデックスを追加することは、インデックスを構築する間、排他ロックを必要とします。それはインデックス構築中にレプリケーションを暗黙的に停止しますが、特定の問題を引き起こすことはしません。構築に 20 分掛かるインデックスをテーブルに追加するとすれば、レプリケーションは 20 分妨害されますが、インデックスがひとたび作成されば素早く追い付きます。
DDL 変更のテスト方法はおそらく"最上の練習"と指摘されています。
DDL スクリプトをテストするには非破壊手法が必要です。
理由の如何に係わらず、問題点は、もしノードが全く同期せず、レプリケーションがフェイルオーバしそうになり、最も支障のある時間の一つの中で発生する、つまり、動かしたいと思った瞬間です。
それぞれのノードに対して手作業で最初に BEGIN; を、最後に ROLLBACK; を追加し、スキーマスクリプトが旨く動作するか否かを、あるべきロールバックの変更を本当に検証する必要があります。
全てのノードでこのスクリプトが動作するのであれば、 Slonik で実行したとしてもあらゆる場所で動作するであろうことを暗示しています。いくつかのノードで問題に遭遇したとしても、スクリプトがエラー無しで走り得るためにそれらのノードで事態の状態を自身でできれば修正することです。
警告 |
もし SQL スクリプトの ROLLBACK; の前の何処かに COMMIT; が含まれていると、予測不可能な変更を容認することになります。 |