Redis-PHP實戰篇——常用的使用場景
redis-php實戰
public function getRedis()
{
$redis = new \Redis();
$redis->connect(env("REDIS_MASTER",'127.0.0.1'),6379);
$redis->auth(env('REDIS_AUTH','123456'));
return $redis;
}
$redis = $this->getRedis();
複製程式碼
String 簡單字串快取實戰
$key = 'str:name';
// 字串快取實戰
$redis->set($key ,'WXiangQian');
$name = $redis->get($key);
echo $name; // WXiangQian
$redis->expire($strCacheKey,30); # 設定30秒後過期
複製程式碼
HSET 簡單雜湊快取實戰
$key = 'hset:name'
$uid = 1;
$redis->hSet($key,$uid,'WXiangQian');
$data = $redis->hGet($key,1);
print_r($data); //輸出資料
複製程式碼
排行榜實戰
$strKey = 'zset:ranking_list' ;
//儲存資料
$redis->zadd($strKey,'50',json_encode(['name' => 'Tom']));
$redis->zadd($strKey,'70',json_encode(['name' => 'John']));
$redis->zadd($strKey,'90',json_encode(['name' => 'Jerry']));
$redis->zadd($strKey,'30',json_encode(['name' => 'Job']));
$redis->zadd($strKey,'100',json_encode(['name' => 'LiMing']));
$dataOne = $redis->ZREVRANGE($strKey,-1,true);
echo "---- {$strKey}由大到小的排序 ---- <br /><br />";
print_r($dataOne);
$dataTwo = $redis->ZRANGE($strKey,true);
echo "<br /><br />---- {$strKey}由小到大的排序 ---- <br /><br />";
print_r($dataTwo);
複製程式碼
list分頁實戰
$strKey = 'list:data';
$page = $request->input('page',1);
$pageSize = $request->input('limit',50);
$limit_s = ($page-1) * $pageSize;
$limit_e = ($limit_s + $pageSize) - 1;
$data = $tools->redis->lRange($strKey,$limit_s,$limit_e);
print_r($data);
複製程式碼
簡單字串悲觀鎖實戰
解釋:悲觀鎖(Pessimistic Lock),顧名思義,就是很悲觀。
每次去拿資料的時候都認為別人會修改,所以每次在拿資料的時候都會上鎖。
場景:如果專案中使用了快取且對快取設定了超時時間。
當併發量比較大的時候,如果沒有鎖機制,那麼快取過期的瞬間,
大量併發請求會穿透快取直接查詢資料庫,造成雪崩效應。
/**
* 獲取鎖
* @param String $key 鎖標識
* @param Int $expire 鎖過期時間
* @return Boolean
*/
public function lock($key = '',$expire = 5) {
$is_lock = $this->_redis->setnx($key,time()+$expire);
//不能獲取鎖
if(!$is_lock){
//判斷鎖是否過期
$lock_time = $this->_redis->get($key);
//鎖已過期,刪除鎖,重新獲取
if (time() > $lock_time) {
unlock($key);
$is_lock = $this->_redis->setnx($key,time() + $expire);
}
}
return $is_lock? true : false;
}
/**
* 釋放鎖
* @param String $key 鎖標識
* @return Boolean
*/
public function unlock($key = ''){
return $this->_redis->del($key);
}
// 定義鎖標識
$key = 'str:lock';
// 獲取鎖
$is_lock = lock($key,10);
if ($is_lock) {
echo 'get lock success<br>';
echo 'do sth..<br>';
sleep(5);
echo 'success<br>';
unlock($key);
} else { //獲取鎖失敗
echo 'request too frequently<br>';
}
複製程式碼
簡單事務的樂觀鎖實戰
解釋:樂觀鎖(Optimistic Lock),顧名思義,就是很樂觀。
每次去拿資料的時候都認為別人不會修改,所以不會上鎖。
watch命令會監視給定的key,當exec時候如果監視的key從呼叫watch後發生過變化,則整個事務會失敗。
也可以呼叫watch多次監視多個key。這樣就可以對指定的key加樂觀鎖了。
注意watch的key是對整個連線有效的,事務也一樣。
如果連線斷開,監視和事務都會被自動清除。
當然了exec,discard,unwatch命令都會清除連線中的所有監視。
$strKey = 'str:age';
$redis->set($strKey,10);
$age = $redis->get($strKey);
echo "---- Current Age:{$age} ---- <br/><br/>"; // 10
$redis->watch($strKey);
// 開啟事務
$redis->multi();
//-------------------------------
/**
* 在這個時候新開了一個新會話執行
*
* redis-cli 執行 $redis->set($strKey,30); //新會話 模擬其他終端
* 這時候$age=30; //30
*/
//-------------------------------
$redis->set($strKey,20);
$redis->exec();
$age = $redis->get($strKey);
echo "---- Current Age:{$age} ---- <br/><br/>"; //30
//當exec時候如果監視的key從呼叫watch後發生過變化,則整個事務會失敗
複製程式碼
悲觀鎖與樂觀鎖的適用場景:
悲觀鎖:比較適合寫入操作比較頻繁的場景,如果出現大量的讀取操作,每次讀取的時候都會進行加鎖,這樣會增加大量的鎖的開銷,降低了系統的吞吐量。
樂觀鎖:比較適合讀取操作比較頻繁的場景,如果出現大量的寫入操作,資料發生衝突的可能性就會增大,為了保證資料的一致性,應用層需要不斷的重新獲取資料,這樣會增加大量的查詢操作,降低了系統的吞吐量。
總結:兩種所各有優缺點,讀取頻繁使用樂觀鎖,寫入頻繁使用悲觀鎖。
像樂觀鎖適用於寫比較少的情況下,即衝突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。但如果經常產生衝突,上層應用會不斷的進行retry,這樣反倒是降低了效能,所以這種情況下用悲觀鎖就比較合適,之所以用悲觀鎖就是因為兩個使用者更新同一條資料的概率高,也就是衝突比較嚴重的情況下,所以才用悲觀鎖.
悲觀鎖比較適合強一致性的場景,但效率比較低,特別是讀的併發低。樂觀鎖則適用於讀多寫少,併發衝突少的場景