ホームページ >データベース >Redis >PHP+redis はロック操作とロック解除操作を実装します

PHP+redis はロック操作とロック解除操作を実装します

尚
転載
2020-06-20 16:55:064017ブラウズ

PHP+redis はロック操作とロック解除操作を実装します

ビジネスの背景: ルームのチェスやカード ゲームでは、同時操作による Redis データの不正な読み取りを防ぐためにロックが必要です (たとえば、ユーザーがルームに入るアクションを追加するなど)。

PHP+redis はロック操作とロック解除操作を実装します

##同時実行の場合、get RoomUsers はダーティ読み取りを行うことになります;

解決策: ルームをロックして、同時に 1 つのルーム内で 1 つのクライアントだけが操作できるようにします。時間、および他の同時クライアント 最後は待機中です; つまり ----- ロックをブロックしています;

Lock: Redis のロック方法はいくつかあります: incr、set、setnx、hSetnx。この記事を参照してください。 : いくつかの Redis ロック方法 一種の実装

推奨事項:

PHP ビデオ チュートリアル

ここではこの方法で設定します

$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); // ['李四', '王五', '张三']

ロック解除: もちろん、あなたは操作後にロックを解除する必要があります。いいえ、ロックを解除するには少なくとも 3 秒待つ必要があります。

ロックを解除するには、delete を使用してキーを削除します。ただし、ここには落とし穴があります。削除は直接使用できません。 client01 がロックを取得し、ユーザーをルームに追加するプロセス中に時間が 3 秒を超えたと仮定します。このとき、client02 もロックを取得して 3S を設定し、client01 が操作を完了してキーを削除すると、 client02 によって設定されたロックは削除されます;

lua の実行はアトミックなため、削除を実行するには lua コードを使用することをお勧めします。

// 将用户添加进房间
$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);

さらに関連する知識については、

redis 入門チュートリアル column を参照してください。

以上がPHP+redis はロック操作とロック解除操作を実装しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。