2012-05-10 17 views
11

取引のためのドキュメントは言う:「私たちは廃止し、最終的に取引を削除することができる」とRedis:なぜLuaスクリプトはトランザクションを置き換えますか?

http://redis.io/topics/transactionsを「あなたは はRedisのトランザクションでできることのすべてを、あなたはまた、スクリプトを使って行うことができます」

しかし、それはありますか?私はこれに問題があると思う。

トランザクション内では、複数の変数を監視し、それらの変数を読み込み、それらの変数の一意の状態に基づいて、EXECを呼び出す前に完全に異なる書き込みセットを作成できます。介入時に何かがそれらの変数の状態に干渉すると、EXECはトランザクションを実行しません。 (再試行することができます。これは完璧な取引システムです)。

エバールスクリプトではできません。このページのドキュメントによると:。

「純粋な関数などのスクリプト...スクリプトは常に同じ Redisのは、同じ入力データ セット与えられた同じ引数でコマンドを記述したスクリプトの動作ができないと評価します(非明示的)の情報や状態は、スクリプト の実行が進むにつれて変わる可能性があります。または、 はI/Oデバイスからの外部入力に依存しません。

http://redis.io/commands/eval

私がEVALで見る問題は、スクリプトの内部にこれらの変数の状態を取得し、それらの変数の状態に基づいて、書き込みのユニークなセットを作ることができないということです。繰り返しますが、「同じ入力データ・セットの場合、スクリプトは常に同じ引数を持つ同じRedis書き込みコマンドを評価します。したがって、結果の書き込みはすでに決定されており(最初の実行からキャッシュされます)、EVALスクリプトはGET値がスクリプトの内部にあるかどうかを気にしません。 EVALを呼び出す前にこれらの変数に対してGETを実行し、EVALスクリプトにそれらの変数を渡すだけですが、ここでは問題があります:GETを呼び出すこととEVALを呼び出すことの間に原子性の問題があります。

つまり、EVALの場合は、これらの変数を取得してEVALスクリプトに渡す必要がある、つまり、トランザクションのためにWATCHを実行したすべての変数。実際にスクリプトが開始されるまで、スクリプトのアトミック性は保証されていないので、スクリプトを開始するためにEVALを呼び出す前にこれらの変数を取得する必要があるため、変数の状態がGETとパスEVALにしたがって、非常に重要なユースケースについては、EVALを使用しているわけではありません。

重要なRedisの機能が失われるとトランザクションが非推奨になってしまうのはなぜですか?または、私がまだ理解していないEVALスクリプトでこれを行う方法が実際にありますか?または、EVALのためにこれを解決できる機能が計画されていますか? (仮説的な例:もしWATCHがEVATと同じようにEVATを使ってWATCHを動作させたのであれば、それはうまくいくかもしれません)

これには解決策がありますか?あるいは、私はレディスが長期的に完全な取引で安全でないかもしれないことを理解していますか?

答えて

15

ルアスクリプトはどんなトランザクションでも実行できますが、私はRedisトランザクションが去っていくとは思っていません。

EVALスクリプトは

evalのスクリプトが実行されて、他に何も同時に実行することはできません変数を監視することはできません。したがって、変数はwatchで無意味です。スクリプト内の値を読み込んだら誰も変数を変更していないことを確認できます。

私がEVALで見る問題は、スクリプトの内部でこれらの変数の状態を取得し、それらの変数の状態に基づいて、書き込みのユニークなセットを作ることができないということです。

本当ではありません。 evalスクリプトにキーを渡すことができます。 evalスクリプト内で、Redisから値を読み取り、その値に基づいて条件付きで他のコマンドを実行することができます。

スクリプトは依然として確定的です。そのスクリプトを実行してスレーブ上で実行すると、マスターとスレーブが同じデータを持つので、同じ書き込みコマンドを実行します。

+0

あなたの言うことが実践的な経験に基づいているなら、それは良いことです!それはドキュメントの私の解釈よりも優先されます: "スクリプトは常に、同じ入力データセットで同じ引数を持つ同じRedis書き込みコマンドを評価します。私にとって、これは、スクリプトが2度目で評価されないように、キャッシュ機構が存在することを意味します。同じ入力を与えられた一連の書き込みを想定しているだけです。決定的には聞こえません。しかし、あなたが実際にこの経験をしていれば、私はあなたの専門知識を延期し、あなたの答えに感謝します。 – OCDev

+1

また、私の仮説的な例については、EVATが実行され、* EVALが実行される前に* WATCHが使用できる仮想的な機能について話していました。 (この意味でEVALがEXECのような振る舞いをする新しい機能)このようにして、GETはEVALに渡し、変更を心配する必要はありません。 (EVALの内部が結局は決定論的であるにもかかわらず、MUTポイント。)もう一度ありがとう。 :) – OCDev

+0

Redis DB Serverがトランザクション(MULTI/EXEC)とEvalの間に落ちるとどうなりますか? POP/PUSHのようなコマンドはほとんど実行されていないと思っています。 –

12

EVALスクリプトは、実際にトランザクションの機能を拡張し、単純化します。

それは次のようにRedisの中に2つのタイプのトランザクションを表示するのに役立つことがあります。

(MULTI EXEC)手続き1.

ピュアMULTI EXECは、一度に実行するコマンドをグループ化しています各コマンドからの応答の配列を返します。それには深刻な限界があります。それはではないは、次の1つのコマンドで中間結果を使用できるようにします以内トランザクション。この純粋な形では、実際のアプリケーションではそれほど有用ではありません。これは基本的に保証された原子性を持つパイプラインです。

トランザクションの前にWATCH キーを追加すると、楽観的なロックが可能になり、トランザクション外でRedisから取得した値をトランザクション外で使用できます。競合状態が発生した場合、トランザクションは失敗し、再試行する必要があります。これはアプリケーションロジックを複雑にし、無限の再試行ループに終わるかもしれないので、楽観主義はしばしば不当です。

EVALのみRedisのコマンドをグループ化するだけでなく、あなたの完全なプログラミング言語、特に条件のパワーを与えていない

ループ2.機能(EVALスクリプティング)、およびローカル変数。 Luaスクリプトでは、あるコマンドでRedisから値を読み込み、次のコマンドで後で使用することができます。

アトミックな方法で実行されるスクリプトを送信します。シングルスレッドの「世界を止める」アプローチによって保証されています。スクリプトの実行中は、他のスクリプトやRedisコマンドは実行されません。したがって、EVALにも制限があります。スクリプトは、他のクライアントをブロックするのを防ぐために小さくて速いものでなければなりません。

また、他のクライアントがプログラミングエラーと見なされる遅いスクリプトを提出しないようにする必要があります。 「信頼できる環境の中で信頼できるクライアントがアクセスするようにRedisが設計されている」のため、セキュリティモデルに適しています。

+0

Redis DB ServerがTransaction(MULTI/EXEC)とEvalの間になった場合はどうなりますか? POP/PUSHのようなコマンドはほとんど実行されていないと思っています。 –

関連する問題