19

トランザクションのドキュメントには次のように書かれています。

「トランザクションを廃止し、最終的に削除する場合があります」および「Redisトランザクションで実行できることはすべて、スクリプトでも実行できます」

http://redis.io/topics/transactions

しかし、それはありますか?これに問題があります。

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

EVALスクリプトではそれができません。このページのドキュメントによると:

「純粋関数としてのスクリプト...スクリプトは常に、同じ入力データセットが与えられた場合に同じ引数で同じRedis書き込みコマンドを評価します。スクリプトによって実行される操作は、スクリプトとして変更される可能性のある非表示の(明示的でない)情報や状態に依存できません。実行は進行するか、スクリプトの異なる実行間で進行します。また、I/Oデバイスからの外部入力に依存することもできません。」

http://redis.io/commands/eval

EVALで見られる問題は、スクリプト内でこれらの変数の状態を取得できず、それらの変数の状態に基づいて一意の書き込みセットを作成できないことです。繰り返しますが、「スクリプトは常に、同じ入力データセットが与えられた場合に同じ引数を使用して同じRedis書き込みコマンドを評価します。」したがって、結果の書き込みはすでに決定されており(最初の実行からキャッシュされます)、EVALスクリプトはスクリプト内のGET値を気にしません。実行できる唯一のことは、EVALを呼び出す前にこれらの変数に対してGETを実行し、次にそれらの変数をEVALスクリプトに渡すことですが、ここに問題があります。GETの呼び出しとEVALの呼び出しの間にアトミック性の問題があります。

つまり、トランザクションに対してWATCHを実行するすべての変数、EVALの場合は、代わりにそれらの変数をGETしてから、EVALスクリプトに渡す必要があります。スクリプトのアトミックな性質は、スクリプトが実際に開始されるまで保証されないため、EVALを呼び出してスクリプトを開始する前に、これらの変数をGETする必要があります。これにより、これらの変数の状態がGETと受け渡しの間で変化する可能性があります。 EVALに。したがって、非常に重要な一連のユースケースでは、EVALでは得られないWATCHでのアトミック性の保証があります。

では、重要なRedis機能が失われる原因となるトランザクションの非推奨についての話があるのはなぜですか?または、私がまだ理解していないEVALスクリプトを使用してこれを行う方法は実際にありますか?または、EVALでこれを解決できる機能が計画されていますか?(架空の例:WATCHがEXECで機能するのと同じようにWATCHをEVALで機能させる場合、それは機能する可能性があります。)

これに対する解決策はありますか?または、Redisが長期的に完全にトランザクションセーフではない可能性があることを理解していますか?

4

3 に答える 3

22

lua スクリプトがトランザクションでできることは何でもできるのは事実ですが、Redis トランザクションがなくなるとは思いません。

EVAL スクリプトでは変数を監視できません

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

EVAL で見られる問題は、スクリプト内でこれらの変数の状態を取得できず、それらの変数の状態に基づいて一意の書き込みセットを作成できないことです。

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

スクリプトはまだ確定的です。そのスクリプトを取得してスレーブで実行すると、マスターとスレーブが同じデータを持っているため、同じ書き込みコマンドが実行されます。

于 2012-05-10T12:27:48.170 に答える
19

EVAL スクリプトは、実際にトランザクションの機能を拡張および簡素化します。

次の方法で、Redis の 2 種類のトランザクションを表示すると役立つ場合があります。

1.手続き型(MULTI EXEC)

純粋な MULTI EXEC は、一度に実行されるコマンドをグループ化し、各コマンドからの応答の配列を返します。これには深刻な制限があります。トランザクションの次のコマンドで、あるコマンドの中間結果を使用することはできません。この純粋な形式では、実際のアプリケーションではあまり役に立ちません。これは基本的に、原子性が保証されたパイプライン処理です。

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

2. 機能 (EVAL スクリプト)

EVAL は Redis コマンドをグループ化するだけでなく、完全なプログラミング言語 (特に条件、ループ、ローカル変数) の機能も提供します。Lua スクリプトでは、1 つのコマンドで Redis から値を読み取り、後で次のコマンドで使用できます。

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

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

于 2014-09-02T18:09:50.263 に答える