Home > Article > Backend Development > Correct way to unlock redis lock
Redis is a good friend of PHP. When writing business in PHP, the concept of lock is sometimes used. Only one person can operate a certain behavior at the same time. At this time we need to use locks. There are several locking methods. PHP cannot use locks in memory, nor can it use ZooKeeper to lock. Using a database to lock will consume a lot of money. At this time, we generally choose redis as the locking mechanism. This article mainly shares with you the correct method of unlocking redis, hoping to help everyone.
setnx
The simplest data structure locked in redis is string. In the earliest days, setnx was generally used for locking operations. This command is to set a val when :lock does not exist. Maybe you will also remember to use expire to increase the expiration of the lock. To unlock the operation, use the del command. The pseudo code is as follows:
if (Redis::setnx("my:lock", 1)) { Redis::expire("my:lock", 10); // ... do something Redis::del("my:lock") }
There is actually a problem here. The problem is that if crash and other behaviors are encountered between setnx and expire, the lock may not be released. So a further optimization solution may be to store the timestamp in the lock. Determine the length of timestamp.
set
Now it is officially recommended to use set directly to implement locking. We can use the set command to replace setnx, which looks like the following
if (Redis::set("my:lock", 1, "nx", "ex", 10)) { ... do something Redis::del("my:lock") }
The above code sets my:lock to 1 if and only if the lock is not When it exists, set the expiration time to 10 after the setting is completed.
The mechanism for acquiring locks is correct, but it is wrong to use del directly for deleting locks. Because it may lead to accidentally deleting other people's locks.
For example, I locked this lock for 10 seconds, but the processing time was longer than 10 seconds. At 10 seconds, the lock automatically expired, was taken away by others, and was re-locked. Then at this time, when I call Redis::del again, it will delete the lock created by others.
The official also has suggestions for unlocking commands. It is recommended to use lua script, first perform get, and then perform del
The program becomes:
$token = rand(1, 100000); function lock() { return Redis::set("my:lock", $token, "nx", "ex", 10); } function unlock() { $script = ` if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end ` return Redis::eval($script, "my:lock", $token) } if (lock()) { // do something unlock(); }
The token here is a random number. When locking, this token is stored in my:lock of redis. When unlocking, first get the token in the lock. If it matches the token I want to delete If they are consistent, it means that the lock was set by me before. Otherwise, it means that the lock has expired and was set by someone else, and I should not perform any operations on it.
So: Don’t use setnx anymore, use set directly for lock implementation.
Related recommendations:
php Use redis lock to limit concurrent access class
php Use redis lock to limit concurrent access class example
Summary of common methods for operating redis in php
The above is the detailed content of Correct way to unlock redis lock. For more information, please follow other related articles on the PHP Chinese website!