怎么實現redis的讀鎖?
避免掉入 SETNX(SET if Not eXists) 陷阱的最好方法就是永遠不要使用它:
setnx lock "lock"
expire lock 100
del lock
場景:某個查詢數據庫的接口,因為調用量比較大,所以加了緩存,并設定緩存過期后刷新.
問題是當并發量比較大的時候,如果沒有鎖機制,那么緩存過期的瞬間,大量并發請求會穿透緩存直接查詢數據庫,造成雪崩效應. 如果有鎖機制,那么就可以控制只有一個請求去更新緩存,其它的請求視情況要么等待,要么使用過期的緩存.
$key = 'cache_update_lock'; //鎖
$random = md5( uniqid(getmypid().'_'.mt_rand().'_', true) ); //隨機值
$ttl = 10; //nx表示not exists,ex表示expire,ttl表示time to live,單位是秒.
if( $redis->set($key, $random, ['nx', 'ex' => $ttl]) ) {
$cache->update(); //加鎖后執行業務邏輯,這里是更新緩存
//加入隨機值判斷是為了避免刪除到其他操作的鎖
if($redis->get($key) == $random) {
$redis->del($key);
}
}