Redis 防緩存雪崩鎖方法實現

緩存更新主要有如下幾種方案:php

1,檢測是否過時,是則加鎖去更新緩存(防緩存雪崩鎖主要在該場景下出現)redis

2,主動更新緩存(該方式理論如此,可是具體實現須要依據具體場景,不見得最優)緩存

3,緩存時間加隨機數,避免同一時間出現大量緩存過時現象(這裏的一個問題是須要去尋找最優的隨機範圍)測試

4,歡迎補充。。。this


這裏的鎖方法實現,是對基於 redis 的方案一而言的,不妥之處還請指正!code

鎖代碼以下:get

/**
 * @author koma<komazhang@foxmail.com>
 *
 * @param string $key
 * @param intger $locktime
 * 
 * @return boolean
**/
function lock($key, $locktime = 1)
{
	global $redis;

	$curtime  = time();
	$lockKey  = "{$key}.lock";
	$locktime = $curtime+$locktime+1;

	if ( $redis->setNx($lockKey, $locktime) ) {
		return true;
	}

	if ( ($redis->get($lockKey) < $curtime)
		&& ($redis->getSet($lockKey, $locktime) < $curtime) ) {
		return true;
	}

	return false;
}

/**
 * @author koma<komazhang@foxmail.com>
 *
 * @param string $key
 * 
 * @return null
**/
function release($key)
{
	global $redis;

	$redis->delete("{$key}.lock");
}


調用方式以下:string

$redis = new Redis();
$redis->connect('192.168.1.10');

$key    = "stream.01";
$data   = "this is the content";
$expire = 60;
$curtime = time();

if ( !$redis->hExists($key, 'data') ) {
	$redis->hSet($key, 'data', $data);
	$redis->hSet($key, 'expire', $curtime+$expire);
}

if ( (intval($redis->hGet($key, 'expire')) < $curtime) && lock($key) ) { //out of time
	//update the data
	file_put_contents(dirname(__FILE__).'/log.txt', "=========================\n", FILE_APPEND);
	file_put_contents(dirname(__FILE__).'/log.txt', "do update\n", FILE_APPEND);

	sleep(5);
	$redis->hSet($key, 'expire', $curtime+$expire);

	//release the lock
	release($key);
}

echo $redis->hGet($key, 'data');


本地經過 siege -c 500 -n 10 -bv http://www.localhost.me/redis/test.php  測試經過,歡迎交流!io

參考連接:http://redis.io/commands/setnx function

相關文章
相關標籤/搜索