業(yè)務背景:在房間棋牌游戲中需要用到鎖來防止并發(fā)操作引起的 redis 數(shù)據(jù)臟讀問題;例如添加用戶進入房間的動作:
并發(fā)的情況下,get RoomUsers 會有臟讀現(xiàn)象;
解決思路:加鎖房間來實現(xiàn) 一個房間每次只允許一個客戶端操作,其他并發(fā)客戶端則等待;也就是—–堵塞鎖;
加鎖:redis加鎖方式有幾種: incr、set、setnx、hSetnx,可以參考這篇文章:redis加鎖的幾種實現(xiàn)
立即學習“PHP免費學習筆記(深入)”;
推薦:PHP視頻教程
這里我用到 set 這種方式
$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 刪除 key; 但是這里有個坑,不能直接用 delete,因為假設 client01 獲得了鎖,在添加用戶進入房間的過程中 時間超過了 3秒 ,這個時候client02 就會同樣獲得鎖并且設置3S,然后當client01 操作完之后 delete key , 就把 client02 設置的鎖刪除了;
這里推薦用 lua 代碼執(zhí)行刪除,因為lua 執(zhí)行具有原子性。
//?將用戶添加進房間 $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);
更多相關知識請關注PHP視頻教程欄目
以上就是php+
? 版權聲明
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載。
THE END
喜歡就支持一下吧
相關推薦