A: Introduction
Redis transactions are usually done using commands such as Multi,exec,watch, and the Redis implementation mechanism is very much different from common relational databases, such as Redis transactions that do not support rollback, and transaction execution that blocks request execution by other clients. Second: Transaction Implementation Details
Redis transactions typically go through three stages from start to finish:
1. Transaction start
2. Order the queue
3. Transaction execution
Let's look at the following example
Redis > MULTI
OK
redis > set "username" "Bugall"
QUEUED
redis > set "password" 161616
QUEUED
redis > GET "username"
redis > EXEC
1) OK
2) "Bugall"
3) "Bugall"
Marking the start of a transaction, the Multi command can switch the client executing the command from a non-transactional state to a transactional state, all in exchange for completion by opening the Redis_multi identity in the Flags property of the client state.
Let's look at the source code implementation of the corresponding part of Redis
void Multicommand (client *c) {
if (C->flags & Client_multi) {
addreplyerror (c, "MULTI calls can not is NES Ted ");
return;
}
C->flags |= Client_multi; Open transaction ID
addreply (c,shared.ok);
}
In the client that opens the transaction ID, these commands are staged in a command queue and are not executed immediately because of user input
Redis > Set "username" "Bugall"
redis > set "password" 161616
redis > GET "username"
Executes the command in the transaction queue.
Redis > EXEC
It is important to note that after the client has opened the transaction ID, only the command: The exec,discard,watch,multi command is executed immediately, and the other command servers do not execute immediately, but instead put these commands into a transaction queue. Then return a queued reply to the client
The Redis client has its own transaction state, which is stored in the client state mstate attribute, the structure type of mstate is multistate, and we look at the definition of multistate
typedef struct MULTISTATE {
multicmd *commands; The array int count that holds the multi commands
; Number of commands
} multistate;
Let's look at the structure of the structure type Multicmd
typedef struct MULTICMD {
robj **argv; parameter
int argc; Number of parameters
struct Rediscommand *cmd;//Command pointer
} multicmd;
The transaction queue is preceded by a first-in-a-go Save method, and commands that are queued first are placed in front of the array, and later queued commands are placed behind the array. Three: Executing a transaction
When the client that opens the transaction identity sends the EXEC command, the server executes the command in the client's corresponding transaction queue, and we look at the implementation details of exec
void ExecCommand (client *c) {int J;
RobJ **orig_argv;
int ORIG_ARGC;
struct Rediscommand *orig_cmd; int must_propagate = 0; Synchronous persistence, synchronizing master/Slave nodes//If the client does not have the transaction ID enabled (!)
C->flags & Client_multi) {Addreplyerror (c, "EXEC without MULTI");
Return }//Check whether you need to discard exec//If some watch key is modified, discard the IF (C->flags & (client_dirty_cas|
client_dirty_exec) {addreply (c, C->flags & client_dirty_exec? Shared.execaborterr:
Shared.nullmultibulk);
Discardtransaction (c);
Goto Handle_monitor; }//execute the command in the queue Unwatchallkeys (c);
Because Redis is single-threaded, here, when the check watch key has not been modified, the unified clear off all watch ORIG_ARGV = c->argv;
ORIG_ARGC = c->argc;
Orig_cmd = c->cmd;
Addreplymultibulklen (C,c->mstate.count);
for (j = 0; J < c->mstate.count; J + +) {C->ARGC = c->mstate.commands[j].argc; C->ARGV = c->mstate.commands[J].ARGV;
C->cmd = c->mstate.commands[j].cmd; Synchronize master and Slave nodes, and persistent if (!must_propagate &&!) (
C->cmd->flags & cmd_readonly) {Execcommandpropagatemulti (c);
Must_propagate = 1;
}//execute command Call (c,cmd_call_full);
C->MSTATE.COMMANDS[J].ARGC = c->argc;
C->MSTATE.COMMANDS[J].ARGV = c->argv;
C->mstate.commands[j].cmd = c->cmd;
} c->argv = ORIG_ARGV;
C->ARGC = ORIG_ARGC;
C->cmd = Orig_cmd;
Cancels the client's transaction identity discardtransaction (c);
if (must_propagate) server.dirty++; Handle_monitor:if (Listlength (server.monitors) &&!server.loading) replicationfeedmonitors (c,server.m
ONITORS,C->DB->ID,C->ARGV,C->ARGC); }
Four: Watch/unwatch/discard
Watch
The command is an optimistic lock that can monitor any number of database keys before the EXEC command executes and, when executing the EXEC command, determine if at least one of the watch's key values
If modified, the execution of the transaction is discarded, and if it is not modified, the watch's information is emptied and the commands in the transaction list are executed.
Unwatch:
As the name implies, its function is the opposite of Watch, is to cancel a key value of the "monitoring" function can be
Discard
Clears all the commands in the client's transaction queue and cancels the client's transaction token, and if the client discard some keys while executing the transaction, it cancels all
Key to watch. V: The ACID properties of Redis transactions
In the traditional relational database, try to use acid quality to detect the reliability and security of transactional functions.
In Redis, transactions always have atomicity (atomicity), consistency (consistency), and isolation (isolation), and when Redis runs in a particular persistence
mode, the transaction also has durability (durability).
① Atomic Nature
A transaction is atomic in that the database executes multiple operations in a transaction as a whole, and the server either executes all operations in the transaction or does not perform an operation.
But for Redis's transactional capabilities, the commands in the transaction queue are either all executed or none of them are executed, so Redis transactions are atomic. We will usually know
Two arguments about the atomicity of Redis transactions, one is that either the transaction is executed, or neither is executed. Another argument is that Redis transactions when command execution fails in a transaction
is executed, the command before the error is not rolled back. In fact, the two statements are correct. But indispensable. We'll analyze the next
Let's look at an example of a transaction that can be performed correctly "Redis > MULTI OK redis > SET username" bugall "QUEUED redis > EXEC 1) OK 2)" Bugall "" Instead, let's look at an example of a failed transaction execution. This transaction is rejected by the server when the command is placed in the transaction queue, so all the commands in the transaction will not be executed, as we have previously described that the Redis transaction commands are unified first in the transaction queue and then executed uniformly when the user enters the EXEC command. However, we use the "GET" command incorrectly, when the command is placed in the transaction queue is detected by the transaction, this time has not received the EXEC command, so this is not involved in the rollback problem, at the time of the exec found in the transaction queue there is a command error, so the command in the transaction is not executed,
So we can get to the atomic nature of the business, let's take a look at the example. "Redis > MULTI OK redis > Get (Error) ERR wrong number of arguments for ' get ' command Redis > get username Q ueued Redis > EXEC (Error) Execabort Transaction discarded because of previous errors "" The biggest difference between the transactions of Redis and traditional relational database transactions is that Redis does not support transaction rollback mechanisms, even if a command in the transaction queue has an error during execution and the entire transaction continues to execute until all the commands in the transaction queue have been executed, let's look at the following example "Redis > SET username" bugall "OK redis > MULTI OK redis > Sadd member" Bugall "" Litengfe "" Yangyifang "QUEUED Redis > Rpush username" b "" L "Y"//Error pair key username use List key command QUEUED redis > Sadd password "123456" "123456" "123456" QUEUED redis > EXEC 1) (Integ ER) 3 2) (Error) WrongtypeOperation against a key holding the wrong kind of value 3) (integer) 3 "" The author of the Redis explains in the XV feature document that the transaction rollback is not supported because of this complex functionality and the Redis pursuit of The simple and efficient design thrust does not fit, and he argues that redis transaction execution-time errors are usually caused by programming errors, which usually occur only in the development environment and rarely in the actual production environment, so he does not think it is necessary to develop transactional rollback capabilities for Redis.
So when we're talking about REDIS transaction rollback, be sure to distinguish between the time when the command error occurs.
② consistency
Transactional consistency means that if the database is consistent before the transaction executes, the database should still be consistent, regardless of whether the transaction is successful or not, after the transaction executes.
"Consistent" means that the data conforms to the definition and requirements of the database itself and does not contain illegal or invalid error data. Redis ensures transactional consistency through discreet error detection and simple design.
③ Isolation
The isolation of a transaction means that, even if there are multiple transactions in the database that are executing concurrently, the transactions do not affect each other, and transactions performed in the concurrency state and serially executed transactions produce completely
Same.
Because Redis uses a single thread to execute transactions (and the commands in a transaction queue), and the server guarantees that things will not be interrupted during a transaction, the Redis transaction is always serialized
And the transaction is always isolated.
④ Persistence
The durability of a transaction means that when a transaction is completed, the result of executing the transaction is persisted to the persistent storage medium.
Because Redis transactions simply wrap up a set of REDIS commands in a queue, Redis does not provide any additional persistence functionality for transactions, so the durability of Redis transactions is used by Redis mode
Decided
-When the server is running in a non-persistent memory mode, the transaction is not durable and all server data, including transactional data, will be lost once the server is down
-When the server is operating in RDB persistence mode, the server executes the Bgsave command only when a specific save condition is satisfied, saves the database, and asynchronously executes the bgsave without
Ensures that transaction data is saved to the hard disk for the first time, so transactions in the RDB persistence mode are not durable
-When the server is running in aof persistence mode, and the value of the Appedfsync option is always, the program calls the synchronization function after executing the command, and the command data is actually saved to the hard disk, so
Transactions in this configuration are durable.
-When the server is running in aof persistence mode, and the value of the Appedfsync option is everysec, the program synchronizes the command data to the disk every second because the outage can happen exactly the second of the wait for synchronization, which can cause transaction data loss, So the transaction under this configuration has no durability
Turn from: SF of Bugall