Redis study notes 6--Redis transaction (collection)

Redis's support for transactions is relatively simple at present. Redis can only guarantee that commands in a transaction initiated by a client can be executed continuously, without inserting commands from other clients in the middle. Since redis is single-threaded to handle all client requests, this is easy to do. Under normal circumstances, redis will process and return the processing result immediately after receiving a command from a client, but when a client issues a multi command in a connection, the connection will enter a transaction context, and the subsequent commands of the connection are not Executed immediately, but put into a queue first. After receiving the exec command from this connection, redis will execute all commands in the queue sequentially. And package the results of all commands and return them to the client. Then the connection ends the transaction context.  

An example can be seen below:

return 127.0.0.1:6379> multi
OK
return 127.0.0.1:6379> incr a
QUEUED
redis 127.0.0.1:6379> incr b
QUEUED
return

From this example, we can see that the incr a and incr b commands are not executed but placed in the queue after they are issued. After calling exec, the two commands are executed continuously, and the result of the execution of the two commands is finally returned.
       We can call the discard command to cancel a transaction. Following the above example:

redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> incr a
QUEUED
redis 127.0.0.1:6379> incr b
QUEUED
redis 127.0.0.1:6379> discard
OK
redis 127.0.0.1:6379> get a
"1"
redis 127.0.0.1:6379> get b
"1"

It can be found that incr a incr b has not been executed this time. The discard command actually clears the transaction's command queue and exits the transaction context.
       Although redis transactions are essentially equivalent to serialization isolation levels. However, since the commands of the transaction context are only queued and not executed immediately, the write operation in the transaction cannot depend on the result of the read operation in the transaction. It is very likely that two clients do this operation at the same time, that is to say, if we want to implement a function similar to the incr command, first get a to take out my value, then a++, and then set a, we expect to add a twice from the original The 1 becomes 3. But it is very likely that the get a of the two clients will both get 1, resulting in the final result of adding two times is 2. The main problem is that we don't have any synchronization of access to shared resource a. That is to say, redis does not provide any locking mechanism to synchronize access to a.

Fortunately, the watch command was added after redis 2.1, which can be used to implement optimistic locking. See an example of a properly implemented incr command, just prepended with watcha:

redis 127.0.0.1:6379> watch a
OK
redis 127.0.0.1:6379> get a
"1"
redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> set a 2
QUEUED
redis 127.0.0.1:6379> exec
1. OK
redis 127.0.0.1:6379> get a
"2"

The watch command will monitor the given key. When exec, if the monitored key has changed since calling watch, the entire transaction will fail. You can also call watch multiple times to monitor multiple keys. In this way, you can add optimistic locking to the specified key. Note that the watch key is valid for the entire connection, as is the transaction. If the connection is lost, both the watch and the transaction are automatically cleared. Of course, the exec, discard, and unwatch commands will clear all monitoring in the connection.
       The transaction implementation of redis is so simple, of course, there will be some problems. The first problem is that redis can only guarantee that each command of the transaction is executed continuously, but if one command in the transaction fails, other commands are not rolled back, such as the type of command used does not match.

redis 127.0.0.1:6379> set a 5
OK
redis 127.0.0.1:6379> lpush b 5
(integer) 1
redis 127.0.0.1:6379> set c 5
OK
redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> incr a
QUEUED
redis 127.0.0.1:6379> incr b
QUEUED
redis 127.0.0.1:6379> incr c
QUEUED
redis 127.0.0.1:6379> exec
1. (integer) 6
2. (error) ERR Operation against a key holding the wrong kind of value
3. (integer) 6

It can be seen that although incr b failed, the other two commands were still executed.

Another problem is that if redis hangs unexpectedly during the execution of the transaction. It's a pity that only some of the commands are executed, and the rest are discarded. Of course, if we use append-only file persistence, redis will write the entire transaction content with a single write operation. Even in this way it is still possible that the transaction is only partially written to disk. In the case of a partial write transaction, redis will detect this when restarting, and then fail to exit. It can be repaired using the redis-check-aof tool, which deletes partially written transaction content. After repairing it can be restarted.


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325490964&siteId=291194637