2012-05-10 15 views
11

Die Dokumentation für Transaktionen sagt:Redis: Warum ersetzt Lua Scripting die Transaktionen?

„wir verbitten können und schließlich entfernen Transaktionen“ und „alles, was Sie mit einer Redis Transaktion tun können, können Sie auch mit einem Skript tun“

http://redis.io/topics/transactions

Aber tut es? Ich sehe ein Problem damit.

Innerhalb einer Transaktion können Sie mehrere Variablen beobachten, diese Variablen lesen, und basierend auf dem eindeutigen Status dieser Variablen können Sie vor dem Aufruf von EXEC eine komplett andere Reihe von Schreibvorgängen vornehmen. Wenn irgendetwas in der Zwischenzeit den Zustand dieser Variablen beeinträchtigt, führt EXEC die Transaktion nicht aus. (Dies ermöglicht es Ihnen, es erneut zu versuchen. Dies ist ein perfektes Transaktionssystem.)

Ein EVAL-Skript lässt Sie das nicht tun. Gemäß der Dokumentation auf dieser Seite:

„Scripts als reine Funktionen ... Das Skript wertet immer die gleichen Redis Schreibbefehle mit den gleichen Argumenten bei gleichen Eingabedaten Satz Operationen des Skripts nicht. abhängig von irgendwelchen versteckten (nicht explizite) Informationen oder Status, die sich ändern können, wie Skript Ausführung fährt oder zwischen verschiedenen Ausführungen des Skripts, noch kann es von jeder externen Eingabe von E/A-Geräten abhängen. "

http://redis.io/commands/eval

Das Problem, das ich mit EVAL sehen ist, dass Sie nicht den Status dieser Variablen innerhalb des Skripts bekommen und einen einzigartigen Satz von Schreibvorgängen auf Basis machen über den Zustand dieser Variablen. Nochmals: "Das Skript wertet immer die gleichen Redis-Schreibbefehle mit den gleichen Argumenten bei gleichem Eingabedatensatz aus." Daher werden die resultierenden Schreibvorgänge bereits bestimmt (zwischengespeichert aus dem ersten Durchlauf), und das EVAL-Skript kümmert sich nicht darum, was die GET-Werte innerhalb des Skripts sind. Sie können GET nur für diese Variablen ausführen, bevor Sie EVAL aufrufen, und diese Variablen dann an das EVAL-Skript übergeben. Hier ist das Problem: Sie haben jetzt ein Problem mit der Atomarität zwischen dem Aufruf von GET und dem Aufruf von EVAL.

Mit anderen Worten, alle Variablen, die Sie eine WATCH für eine Transaktion gemacht hätten, müssen Sie im Falle von EVAL stattdessen diese Variablen holen und sie dann an das EVAL-Skript übergeben. Da die atomare Natur des Skripts erst beim Start des Skripts garantiert wird und Sie diese Variablen vor dem Aufruf von EVAL abrufen müssen, um das Skript zu starten, bleibt eine Öffnung, bei der sich der Status dieser Variablen zwischen dem GET ändern und übergeben kann zu EVAL. Daher haben Sie die Atomaritätsgarantie, die Sie mit WATCH haben, nicht mit EVAL für einen sehr wichtigen Anwendungsfall.

Warum wird von ablehnenden Transaktionen gesprochen, wenn dadurch wichtige Redis-Funktionen verloren gehen? Oder gibt es tatsächlich eine Möglichkeit, dies mit EVAL-Skripten zu tun, die ich noch nicht verstehe? Oder sind Features geplant, die das für EVAL lösen können? (Hypothetisches Beispiel: Wenn WATCH mit EVAL genauso wie WATCH mit EXEC arbeitet, könnte das funktionieren.)

Gibt es dafür eine Lösung? Oder muss ich verstehen, dass Redis auf lange Sicht nicht absolut sicher ist?

Antwort

15

Es stimmt, dass Lua-Skripts alle Transaktionen ausführen können, aber ich glaube nicht, dass Redis-Transaktionen weggehen.

EVAL Skript nicht lassen Sie Variablen beobachten

Wenn ein eval-Skript ausgeführt wird, nichts anderes kann gleichzeitig ausgeführt werden. Also, watch Variablen ist sinnlos. Sie können sicher sein, dass niemand sonst die Variablen geändert hat, nachdem Sie die Werte im Skript gelesen haben.

Das Problem, das ich mit EVAL sehen ist, dass Sie nicht den Status dieser Variablen innerhalb des Skripts bekommen und einen einzigartigen Satz von Schreibvorgängen auf Basis machen über den Zustand dieser Variablen.

Nicht wahr. Sie können Schlüssel an das Eval-Skript übergeben. Innerhalb Ihres eval-Skripts können Sie die Werte von Redis lesen und dann basierend auf diesen Werten bedingt andere Befehle ausführen.

Das Skript ist noch deterministisch. Wenn Sie dieses Skript ausführen und es auf dem Slave ausführen, führt es immer noch dieselben Schreibbefehle aus, da der Master und der Slave dieselben Daten haben.

+0

Wenn das, was Sie sagen, auf praktischer Erfahrung basiert, dann ist das gut! Es übertrumpft meine Interpretation der Dokumentation: "Das Skript wertet immer dieselben Redis-Schreibbefehle mit den gleichen Argumenten bei gleichem Eingabedatensatz aus." Für mich bedeutet das, dass ein Caching-Mechanismus läuft, so dass das Skript beim zweiten Mal nicht einmal ausgewertet wird. Es nimmt nur eine Reihe von Schreibvorgängen mit der gleichen Eingabe an. Klingt nicht deterministisch. Aber wenn Sie tatsächliche Erfahrung damit haben, schiebe ich auf Ihre Expertise und ich danke Ihnen für Ihre Antwort. – OCDev

+1

Auch über mein hypothetisches Beispiel sprach ich über ein hypothetisches Feature, bei dem WATCH * außerhalb * von EVAL und * vor * EVAL verwendet werden könnte. (Ein neues Feature, bei dem sich EVAL in diesem Sinne wie EXEC verhält.) Auf diese Weise könnten die GETs in Vorbereitung darauf durchgeführt werden, sie an EVAL weiterzuleiten und sich nicht darum kümmern zu müssen, dass sie sich ändern. (Moot Punkt obwohl wenn innerhalb von EVAL ist schließlich deterministisch.) Nochmals vielen Dank. :) – OCDev

+0

Was passiert, wenn Redis DB Server zwischen Transaktion (MULTI/EXEC) und Eval? Nehmen Sie an, dass einige Befehle wie POP/PUSH ausgeführt wurden ... und bevor einige weitere Befehle ausgeführt wurden. –

12

EVAL Scripting erweitert und vereinfacht die Funktionalität von Transaktionen.

Es kann helfen, die zwei Arten von Transaktionen in Redis in der folgenden Art und Weise zu lesen:

1. Verfahren (MULTI EXEC)

Reiner MULTI EXEC wird Befehle Gruppierung in einem Rutsch ausgeführt werden und gibt ein Array von Antworten von jedem Befehl zurück. Es hat eine ernsthafte Einschränkung. Es nicht ermöglicht die Verwendung eines Zwischenergebnisses von einem Befehl in der nächsten innerhalb der Transaktion. In dieser reinen Form ist es in praktischen Anwendungen nicht sehr nützlich. Es ist im Grunde ein Pipelining mit garantierter Atomarität.

die UHR-Taste vor der Transaktion, ermöglicht eine optimistische Sperre und unter Verwendung von in der Transaktion, die von außerhalb der Transaktion Redis erhaltenen Werte addieren. Wenn eine Race-Bedingung eintritt, schlägt die Transaktion fehl und muss wiederholt werden. Dies kompliziert die Anwendungslogik, und der Optimismus ist oft nicht gerechtfertigt, da Sie möglicherweise in der endlosen Wiederholungsschleife landen.

2. Funktions (EVAL-Scripting)

EVAL nicht nur Redis Befehle Gruppierung, sondern gibt Ihnen auch die Kraft des vollen Programmiersprache, insbesondere Bedingungen, Schleifen und lokalen Variablen. Im Lua-Skript können Sie Werte aus Redis in einem Befehl lesen und später im nächsten Befehl verwenden.

Sie reichen das Skript ein, das auf atomare Weise ausgeführt wird. Es ist garantiert durch den Single-Thread-, "Stop the World" -Ansatz. Während der Skriptausführung wird kein anderes Skript oder Redis-Befehl ausgeführt. Folglich hat EVAL auch eine Einschränkung: Skripte müssen klein und schnell sein, um zu verhindern, dass andere Clients blockiert werden.

Wir müssen auch darauf vertrauen, dass andere Clients kein langsames Skript übergeben, das als Programmierfehler betrachtet werden sollte. Es passt gut in das Sicherheitsmodell seit "Redis wurde entwickelt, um von vertrauenswürdigen Clients in vertrauenswürdigen Umgebungen zugegriffen werden".

+0

Was passiert, wenn Redis DB Server zwischen Transaction (MULTI/EXEC) und Eval? Nehmen Sie an, dass einige Befehle wie POP/PUSH ausgeführt wurden ... und bevor einige weitere Befehle ausgeführt wurden. –

Verwandte Themen