Please help me to vote, thank you
What is distributed locking
Locking is a very common mechanism for programs with a shared memory model, such as JAVA programs. Generally simple for pessimistic lock and optimistic lock. A pessimistic lock is a lock in which you acquire the data and no one else can access or manipulate the data until you release the lock. Optimistic locks are generally CAS updates. A memory lock in a single process that controls only the data in the process is a non-distributed lock. In contrast, a cross-process lock that requires multiple processes to access data is a distributed lock.
Pessimistic locks are generally implemented by SETNXEX of Redis, where Key is the resource name, EX sets a reasonable timeout period, and Value is set to a random string generated by the client that will not be repeated within the timeout period.
Lua script feature description
Because Redis is single-threaded, lua scripts are executed without other client commands at the same time, which ensures concurrency safety to a certain extent
Single process Redis distributed pessimistic lock implementation idea
Pessimistic lock is generally implemented by SETNX of Redis, through SETNX to obtain a lock, release the lock to delete the Key. For example, to obtain a lock named TestLock, use SETNX TestLock TestLockValue, TestLockValue to set a random value. SETNX is SET IF NOT EXISTS. 1 is returned on success, 0 is returned on failure. 1 indicates that the lock was successfully obtained, 0 indicates that the lock was not successfully obtained. To release a lock, use DEL TestLock to release the lock. Returns 1 to indicate that the lock was released successfully and 0 to indicate that the lock was not released.
However, if implemented as simply as this, there are problems in the following scenarios:
- Client 1 successfully obtains the lock.
- Client 1 died and failed to release the lock.
- Other clients can no longer acquire the lock.
So, with this in mind, we typically set a timeout for locks. Redis automatically removes the key after the timeout period is exceeded. This will not result in the lock never being released after client 1 dies.
The redis command set becomes: get lock:
> SETNX TestLock TestLockValue
> EXPIRE TestLock 8
Copy the code
Release the lock:
> DEL TestLock
Copy the code
Since SETNX and EXPIRE are two commands, problems can occur in the following scenarios:
- Client 1 executes
SETNX TestLock TestLockValue
Success. - Client 1 died. No expiration time is set.
- Other clients can no longer acquire the lock.
In Redis 2.8, the author added an extension to the set directive to enable the setnx and EXPIRE directives to be executed together
The redis command set becomes: get lock:
> SET TestLock TestLockValue EX 5 NX
Copy the code
Release the lock:
> DEL TestLock
Copy the code
These two commands can also be executed using Redis transactions, but only part of the command may be executed when Redis is killed, so it is safer and cleaner to use the command above.
But there are new problems in the following scenarios:
- Client 1 successfully obtains the lock.
- Client 1 blocks an operation for a long time (GC, etc.) or has a long network delay.
- When the expiration date is up, the lock is released automatically.
- Client 2 has obtained the lock corresponding to the same resource.
- Client 1 recovers from the block and releases the lock held by client 2.
To avoid this, we usually set the VALUE of the lock KEY to a random VALUE, as long as the VALUE is not repeated for a continuous period of time. When releasing a lock, check whether the VALUE of the current lock is consistent with the VALUE set by yourself. The lock will be released only when the VALUE is consistent.
The redis command set becomes: get lock:
> SET TestLock RandomValue EX 5 NX
Copy the code
Release the lock:
> GET TestLock // determine whether the program is consistent > DEL TestLockCopy the code
This can also be problematic in the following scenarios:
- Client 1 successfully obtains the lock.
- Client 1 accesses shared resources.
- To release the lock, client 1 performs a ‘GET’ operation to GET a random string value.
- Client 1 determines the value of the random string to be equal to the expected value.
- Client 1 is blocked for a long time for some reason.
- When the expiration date is up, the lock is released automatically.
- Client 2 has obtained the lock corresponding to the same resource.
- Client 1 recovers from the block and performs the DEL manipulation to release the lock held by client 2.
Therefore, lock release must be placed in a transaction, via lua script. That is:
If the Lua script parameter TestLock is passed in, the random value in the current program cache determines whether the TestLock value is the same as the passed value. If the value is the same, the system returns whether the lock is unlocked successfullyCopy the code
In this way, distributed pessimistic locking is implemented under the condition that Redis single process is always running normally.