Postgres-R
Posted on 17th 7月 2008 by yTwitter経由で知ったのだが、Postgres-Rというレプリケーション用の拡張がある。面白そうなので概要を読んだ。以下のように説明されている。
Postgres-R概要
Postgres-Rクラスタの構造
Postgres-Rは高速に相互接続された「何も共有しない」クラスタ群として設計されています。そのためギガビットイーサネットで接続されたAMD Opteronマシンのようなありふれたハードウェアで構築することができるクラスタになっています。Postgres-Rノード間の通信は全てレプリケーショングループを提供するグループコミュニケーションシステム(GCS)を介して行われます。ひとつのデータベースが各グループにレプリケーションされることになります。
グループに追加された最初のノードはまずレプリケーションを開始し、最初のデータを提供します。その後で他のノードがグループからのレプリケーションを受け付けることができるようになります。各ノードは稼動状態になる前にリカバリシステムにより初期化されます。リカバリ中にのみリカバリ提供側とリカバリを受ける側のノードとの違いを認識することができますが、通常は全てのノードは同じ内容です。
Postgres-Rノードのコンポーネント
Postgres-Rの主なコンポーネントはレプリケーションマネージャです。これはPostgres本体とは別に追加されたプロセスで、主にメッセージの調整を行い、グループコミュニケーションシステムやトランザクションを実行するバックエンドとの接続を調整します。
Postgresにはトランザクションを扱うバックエンドのプロセスがあります。それぞれのバックエンドは一度にひとつのトランザクションしか扱うことができません。リモートのノードからのトランザクションをリプレーするために、レプリケーションマネージャはレプリケーションマネージャの管理下にありクライアントとの接続はない「リモートバックエンド」というものを開始します。それに対して、ローカルのトランザクションを扱っているバックエンドのプロセスたちは「ローカルバックエンド」と呼ばれ、クライアントと直に接続されています。
レプリケーションされたトランザクションのライフサイクル
Read-onlyのトランザクションはローカルで扱われ、通常のPostgresの単一ノードの操作と何ら変わらないものとみなされます。トランザクションがデータを書き込むと(UPDATE、INSERTまたはDELETEなどのSQLコマンド)、新しいデータがすぐに書き込みセットとして集められます。ローカルバックエンドはトランザクションを処理し続け、クライアントからコミットリクエストを受け取るまで書き込みセットに変更を集め続けます。
クライアントにコミットを返す前に、ローカルバックエンドは書き込みセットをレプリケーションマネージャに送ります。レプリケーションマネージャは順に並べられたグループコミュニケーションシステムのチャンネルを使ってそれを順々に全ての他のノードに送信します。トランザクションを開始したローカルバックエンドは、書き込みセットが戻されたところでコミットできるようになります。自分でもリプレイするように書き込みセットを受け取った他のノードでは、レプリケーションマネージャがリモートバックエンドのプロセスを開始して書き込みセットをそれに引き渡します。するとリモートバックエンドは書き込みセットにあるデータからトランザクションを自分でもリプレイします。
衝突の扱い
Postgres-Rでは書き込みトランザクションはシリアライズされて元と同じ順序でレプリケーションクラスタを共有する各ノードに配信されます。これによりノード間の同期と一貫性が保証されます。トランザクションがあるノードに正常にコミットされたならば、他の全てのノードにも同じくコミットされます。そのため、他のノードの処理を待つことなくそれぞれのノードがフルスピードで稼動することが可能になります。ネットワークのトラヒックを可能な限り抑えるためにトランザクションの変更だけが転送されます。
この手法はシリアライズ可能なPostgresのトランザクションレベルで最大の効果を発揮します。READ COMMITTEDモードでは通常の単一ノードの運用時と同じトランザクションセマンティクスを提供するためにロックもレプリケーションされます。そのためレプリケーションするデータベースシステムのほとんどでボトルネックとなるであろうネットワークトラヒックの増大を引き起こします。
というわけで、実際の動作をさせてみないとなんともいえないが、面白そうな存在なのでちょくちょくチェックする。
Popularity: 7% [?]
Postgres-R使ってみてどうでしたか?僕は20081104のパッチと20081027のパッチを試しましたが、正常に動作しませんでした。ソースも見てみましたが、NULLアドレスにアクセスに行ってセグメンテーション違反で死んだり、無限ループ?で固まったり、自分なりに頑張りましたが動きません。。。まともに動くんだろうか?
コメントありがとうございます。僕もだいたい同様の手順でやりました。あと、20081104のパッチだと、コンパイル時にrecovery.cでエラーが出るかも知れません。ちょっと修正が必要です。あと、ecgsを動かすときにもエラーが出て、どっかにimport structを書き加える必要があると思います。で、さらに、セグメントフォールトするソースを見ると、プライマリキーが存在することを前提に書いてある部分があって、僕はプライマリキーが無いテーブルで実験したんですが、ここでプライマリキーの情報を取ろうとして存在しないアドレスにアクセスしてセグメント違反しているみたいです。ようするに、全然使えなさそうなレベルのように感じました。悪いところを見つけて直してね、というつもりでリリースしたのでしょうか。
pgclusterを触ってみようかな、、、と思っています。
コメントはやっ。pgpoolですか、使っているのはIですか、IIですか?
僕はpgpoolは触った事が無いのですが、HPの説明を読むと、次の問題が存在すると思っています。
問題(1)更新コンフリクト時に同期が崩れる可能性がある。つまり、ほぼ同時に複数の更新クエリが同一タプルを更新すると、複数のデータベース間で異なる結果になってしまうことがある。
問題(2)グローバルデッドロックが起きる可能性がある。つまり、複数のデータベースをまたがったデッドロックですね。これは検出が不可能なので、避けるしくみが欲しいですね。
これらの問題はどう解決していますか?僕はPosrgres-Rの原論文を読んだところ、これらの問題を解決しているので使えるかも?と思った次第です。
pgclusterもだめそうですか。。。
pgpoolの基本動作は、クライアントからのリクエストをpgpoolサーバが受け付けて、そのリクエストを複数のDBサーバへ同時に投げる、というのでよろしいですよね。ここが間違っていると大変。。。
問題(1)
INSERTの時はたいした問題だと思っていません。UPDATE、DELETEです。例えば、クライアントA、Bから同じタプルを更新するUPDATEがほぼ同時に発行されたとします。それぞれUPDATE x=10とUPDATE x=20だとします。pgpoolサーバは両方のUPDATEをほぼ同時に全てのDBサーバに投げます。DBサーバ1ではUPDATE x=10⇒UPDATE x=20の順で、DBサーバ2ではUPDATE x=20⇒UPDATE x=10の順で実行されたとします。READ COMMITTEDの場合、どちらのDBサーバでもUPDATEが成功しますが、最終的な結果はDBサーバ1では20、DBサーバ2では10となり、同期が崩れます。SERIARIZABLEの場合は後のUPDATEが失敗します。
問題(2)
クライアントA、BがそれぞれLOCK TABLE testtableをほぼ同時に投げたとします。pgpoolサーバは両方のLOCK文を全てのDBサーバへ投げます。DBサーバ1ではクライアントAのLOCKが実行され、DBサーバ2ではクライアントBのLOCKが実行されたとします。するとpgpoolサーバにはどのLOCK文に対しても全ての応答が返ってこないのでずっと待ち続けます。ここでデッドロック。
間違ってますでしょうか?長文になってしまってすいません。。。
お忙しいところ議論頂きましてありがとうございました。おかげさまで久しぶりに脳味噌が活性化しました。
参照系のクエリもレプリケートするとどうして問題(1)が解決するのかわかりませんでしたが。たとえ解決しても、負荷分散できなくなるからDBサーバ増やしても性能が出ないという問題が発生しますねえ。。。
隔離レベルはいつもREAD COMMITTEDを使ってらっしゃいますか?SERIALIZABLEだと、スナップショットまで同期する必要がありそうなので、より問題は複雑になりそうです。
おお、我が家もミニ旅行でした。どうぞ、新型フルには気をつけて楽しんでください。
pgcluster試してみました。簡単なテストはOKですが、実プログラムを動かすと一応動きますが低負荷でも途中で落ちてしまいます。なぜか、
WARNING: This query is not permitted without running replication serverという警告がたくさん出ます。。。pgreplicateも動いているし、PostgreSQL単体では問題ないクエリしか使っていないのに。
以前pgclusterをお使いとのことですが、性能はいかがでしたか?
DRDBとは名前も聞いたことが無いです。コメントから察するに、DRDBよりもpgpoolの方が性能が上ということですよね?
pgclusterとpgpoolではどっちが上でしょうか?
おっと、旅行の準備をしないと。。。
pgclusterの実験つづき。負荷が重くなると、pgreplicateが死ぬ様です。それを知らないクライアントはどんどんクエリを投げて、それを受け取った改造版postgresは「replication serverがいないよ」と警告を出すという訳でした。
pgpoolは前記問題があるし。
後は自分で作るしかないのかな。。。
