Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transactions in Redis with read operations

Using Redis, I want to perform an atomic sequence of commands, i.e. I need to guarantee that no other client will perform changes in the database while the sequence is being executed.

If I used write commands only, I could use MULTI and EXEC statements to assure atomicity using transactions. However, I would also like to use read commands in my transactions. Hence I cannot use MULTI, because read commands are also being queued!

Basically, in atomic manner, I need to do following:

  1. Read x from the database,
  2. Based on x, store f(x) to the database.

Both 1. and 2. should be part of a single, atomic transaction.

Is there a simple way how to do that?

like image 860
Tregoreg Avatar asked Aug 26 '13 20:08

Tregoreg


People also ask

What is the transactions in Redis?

Redis Transactions allow the execution of a group of commands in a single step, they are centered around the commands MULTI , EXEC , DISCARD and WATCH . Redis Transactions make two important guarantees: All the commands in a transaction are serialized and executed sequentially.

How many transactions can Redis handle?

Using a single AWS EC2 instance, Redis was able to achieve 1,200,000 transactions per second at <1 msec (sub millisecond) latency.

Are Redis transactions Atomic?

Redis transactions are atomic, meaning that either every command in a transaction block is processed (meaning that it's accepted as valid and queued to be executed) or none are. However, even if a command is successfully queued, it may still produce an error when executed.

How are Redis pipelining and transaction different?

Unlike pipelines, pipelines use special commands to mark the beginning and the end of the transaction, and the server also can queue the commands from a transaction (so the client can send one at a time). So transactions are stateful on the server, it actually keeps track of an ongoing transaction.


1 Answers

There are two good solutions to your problem.

Option 1:

You need to issue a WATCH on the key you are reading from. Your transaction would look something like this:

WATCH x
x = GET x
MULTI
SET y, f(x)
EXEC

In this example, the write commands inside the multi block will be executed atomically, but only if the value of key x has not changed since WATCH was called. This is called an optimistic lock. If the value of x does change your application will get an error and will need to decide what to do next, which is likely to try again using the new value of x.

Option 2:

Redis now supports lua scripting, and lua scripts are executed atomically. If you can encapsulate your logic into a lua script, you can read your key, run your f(x) logic, and store the result, all atomically. This can be tricky or even a non-option depending on the logic you are performing. You might have to even do ugly hacks like pass values to lua by hardcoding them directly into the script you want redis to execute. That said, if you get it working this method should be reliable and performant, and you don't have to deal with handling EXEC failures.

like image 181
Carl Zulauf Avatar answered Sep 21 '22 01:09

Carl Zulauf