Home  >  Article  >  Backend Development  >  Correct way to unlock redis lock

Correct way to unlock redis lock

小云云
小云云Original
2017-12-14 13:35:582799browse

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!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn