Home >Database >Redis >PHP+redis implements locking and unlocking operations

PHP+redis implements locking and unlocking operations

尚
forward
2020-06-20 16:55:064014browse

PHP+redis implements locking and unlocking operations

Business background: Locks are needed in room chess and card games to prevent dirty reading of redis data caused by concurrent operations; for example, adding the action of a user entering the room:

PHP+redis implements locking and unlocking operations

In the case of concurrency, get RoomUsers will have dirty reads;

Solution: lock the room to allow only one client to operate in a room at a time, and other concurrent clients The end is waiting; that is ----- blocking lock;

Lock: There are several redis locking methods: incr, set, setnx, hSetnx, you can refer to this article: Several redis locking methods A kind of implementation

Recommendation:PHP video tutorial

Here I use set this way

$roomId = $_GET['roomId'];
$user = $_GET['user'];             // '张三'
$key = "LockRoom:{$roomId}";
$value = $roomId.uniqid();
$ex = 3;
// 如果 $key 不存在的话,就设置 $key 的值为 $value,且有效期为 3s; 
// return TRUE / FALSE
while(true){
    $res  = $this->redis->set($key, $value, ['nx', 'ex' => $ex]);
    if($res) { break; }
    usleep(5000);
}

// 将用户添加进房间
$roomUsers = $this->redis->get("Room:{$roomId}:Users"); // ['李四', '王五']
$roomUsers[] = $user;
$this->redis->set("Room:{$roomId}:Users", $roomUsers); // ['李四', '王五', '张三']

Unlocking: Of course you have to unlock it after the operation, no You have to wait at least 3 seconds to unlock;

To unlock, use delete to delete the key; but there is a pitfall here. Delete cannot be used directly, because it is assumed that client01 obtains the lock and the time exceeds 3 seconds during the process of adding users to the room. , at this time client02 will also obtain the lock and set 3S, and then when client01 completes the operation and delete key, the lock set by client02 will be deleted;

It is recommended to use lua code to perform deletion, because lua execution is atomic sex.

// 将用户添加进房间
$roomUsers = $this->redis->get("Room:{$roomId}:Users"); // ['李四', '王五']
$roomUsers[] = $user;
$this->redis->set("Room:{$roomId}:Users", $roomUsers); // ['李四', '王五', '张三']

// lua 脚本解锁
// 先判断 key的值是否为 value, TRUE 才会删除, 所以 $value 的设计要有随机唯一性
$script = 'if redis.call("get",KEYS[1]) == ARGV[1]
then
    return redis.call("del",KEYS[1])
else
    return 0
end ';
$this->redis->eval($script, array($key , $value), 1);

For more related knowledge, please pay attention to redis introductory tutorialcolumn

The above is the detailed content of PHP+redis implements locking and unlocking operations. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:segmentfault.com. If there is any infringement, please contact admin@php.cn delete
Previous article:How to add redis commandNext article:How to add redis command