在Laravel中使用Redis鎖解決快取擊穿問題

FishTail發表於2020-09-13

快取擊穿是開發中可能會遇到的問題:

快取擊穿是指快取中沒有但資料庫中有的資料(一般是快取時間到期),這時由於併發使用者特別多,同時讀快取沒讀到資料,又同時去資料庫去取資料,引起資料庫壓力瞬間增大,造成過大壓力

Redis鎖是解決快取擊穿問題的一個很好的辦法。

Laravel 7 中自帶有 \Illuminate\Cache\RedisLock Redis鎖類,直接使用就行,用起來也很方便。

RedisLock 的建構函式如下:

/**
 * @param \Illuminate\Redis\Connections\Connection $redis redis例項
 * @param string $name redis鎖的鍵名
 * @param int $seconds redis鎖的失效時間
 * @param string|null $owner redis鎖的值,如果不設定或者為null,基類會將其設定為隨機字串
 */
public function __construct($redis, $name, $seconds, $owner = null)
{
    parent::__construct($name, $seconds, $owner);
    $this->redis = $redis;
}

在這個類中,使用 acquire() 方法獲得互斥的Redis鎖,使用 release() 方法釋放鎖。

使用示例:

use Illuminate\Cache\RedisLock;
function RedisLockTest()
{
    //獲取redis例項
    $redis = Redis::connection();
    $key = 'redis_test_key';
    //獲取redis鎖例項
    $redisLock = new RedisLock($redis, $key . '_lock', 30);
    $res = $redis->get($key);
    if (empty($res)) {
        //拿到互斥鎖
        if ($redisLock->acquire()) {
            //模擬從資料庫中獲取資料的過程
            sleep(5);
            $value = date('Y-m-d H:i:s');
            //更新快取,過期時間可以根據實際情況調整
            $redis->setex($key, 60, $value);
            //釋放鎖
            $redisLock->release();
            return $value;
            //未拿到互斥鎖
        } else {
            //等待2秒,然後重新獲取快取值,讓其他獲取到鎖的程式取得資料並設定快取,等待時間可以根據實際情況調整
            sleep(2);
            return $this->getArticleInCache();
        }
    } else {
        return $res;
    }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章