2011-09-09 7 views
2

私は同じデータストア(ある種のキュー)にアクセスし、データで何かをする必要がある複数の子プロセスを同時に起動するRubyスクリプトを作成しようとしています。問題は、データの各行が一度だけ処理される必要があり、子プロセスは、同じ瞬間に別の子プロセスが同じデータで動作しているかどうかを知る方法がないことです。1つのデータストア。複数のプロセス。このSQLは競合状態を防ぎますか?

私はまだ、データストアを選んしていないが、それは私が使用してるものだというだけの理由私は、PostgreSQLに向かって傾いています。

UPDATE jobs 
SET status = 'processed' 
WHERE id = (
    SELECT id FROM jobs WHERE status = 'pending' LIMIT 1 
) RETURNING id, data_to_process; 

しかし、これは実際に動作します:SELECTが行われる前にUPDATE句は、おそらくテーブルの行をロックしますので、私は、競合状態を避けるための方法として提案され、次のSQLの断片を見てきましたか? Postgres(または他のデータベース)がSELECTを実行する前にテーブル行をロックするのは直感的ではないようです。SELECTを実行して、更新のためにロックする必要があるテーブル行を判断する必要があるからです。言い換えれば、私は、このSQLの断片が、2つの別々のプロセスが同じテーブル行で選択されて動作することを本当に妨げないことに懸念しています。

私は妄想していますか?このような並行処理の状況を処理するために、従来のRDBMSより優れたオプションがありますか?

答えて

0

本当に、単一のデータストアで連続して動作する必要がある多くの並行子プロセスが必要ですか?私はあなたがデータベースに単独でアクセスできる(あなたが使用するものであれ)ライタープロセスを作成し、必要なデータベース操作を行うために他のプロセスからの要求を受け入れることをお勧めします。次に、データベースを作成するのではなく、そのスレッドで適切なキュー管理を行います.1つのプロセスだけがいつでもデータベースにアクセスすることが保証されています。

+0

実際には1つの問題は、あなたがロックの問題を持っているし、あなたの取引が長い場合、彼らは他のキューの要求を保持することです。これがほんの少しであればそれは問題ではありません。何百ものリスナーと仕事が1秒間に処理されている場合、大きな問題になる可能性があります。これは、Skypeがpg_message_queueを書いたときよりも複雑な解決策をとったと考えている理由の1つです。 –

0

あなたが記述されている状況は「非反復可能読み取り」と呼ばれています。これを解決するには2つの方法があります。

好ましい方法は、少なくともREPEATABLE READにトランザクション分離レベルを設定することであろう。これは、説明した性質の並行更新が失敗する行を意味します。重複しているトランザクションで2つのプロセスが同じ行を更新した場合、そのうちの1つが取り消され、その変更は無視され、エラーが返されます。そのトランザクションは再試行する必要があります。これは、呼び出しによって実現されます。

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ 

トランザクションの開始時に呼び出します。私はルビーのためにこれを行う慣習的な方法を説明するドキュメントを見つけることができないようです。そのSQLを明示的に発行する必要があります。テーブルがフリーになるまで

他のオプションは、トランザクションがブロック(そしておそらくデッドロック)することがありますmanage the locking of tables explicitlyにあります。トランザクションは上記と同じ方法で失敗することはありませんが、競合ははるかに高いので、詳細は説明しません。

+0

私はこれが実際には反復不可能な読みだとは思わない。 SQL読み取り現象は、参加セッションに複数の照会がある場合にのみ発生します。もちろん、彼が何を書き終えるかは、反復不可能な読み込み問題がありますが、上記で与えられたコード自体はそれではありません。 –

2

あなたが言ったように、キューを使用します。 PostgreSQLの標準ソリューションはPgQです。それはあなたのために働いたこれらの並行性の問題すべてを持っています。私はPostgreSQLのためのシンプルなキューの実装ですpg_message_queueを書いたとき、私は取ったアプローチにかなり近いです

0

。 PgQとは異なり、PostgreSQL以外のコンポーネントは使用する必要がありません。

正常に動作します。 MVCCが救助に来るでしょう。私はこれを見ることができます

+0

これはうまくいくかもしれませんが、1人の作業者に比べてパフォーマンス上の利点はありますか?このアプローチでは、一番上のレコードのロックですべてのワーカーを効果的にシリアライズする必要があります。 –

+0

通常、あなたはあなたの特定のアプローチについてかなり注意する必要があると思うpg_message_queueのために考える。他のプロセスが復帰するのを待っていることが完璧な意味を成す、厄介な条件がたくさんあります。これ以外の場合があります。 今、FIFOキューが必要な場合は、待機動作が発生します。私はすぐにこれが変わるとは思わない。実行時間が長くなると、引き出されて保留中のメッセージをスキップする方法を構築するでしょう。 –

+0

OK、pg_message_queueは厳密にFIFOキューマネージャで、一度に "飛行中"のジョブは1つしかありませんか?もしそうなら、それは理にかなっており、OPのような質問をする多くの人々が解決しようとしている問題と同じ問題を解決することはできません。 –

関連する問題