Redis之利用锁机制来防止缓存过期产生的惊群现象
来源:互联网 发布:网络大电影的发展趋势 编辑:程序博客网 时间:2024/06/05 19:33
首先,所谓的缓存过期引起的“惊群”现象是指,在大并发情况下,我们通常会用缓存来给数据库分压,但是会有这么一种情况发生,那就是当一个缓存数据失效之后会导致同时有多个并发线程去向后端数据库发起请求去获取同一个数据,这样如果在一段时间内同时生成了大量的缓存,然后在另外一段时间内又有大量的缓存失效,这样就会导致后端数据库的压力突然增大,这种现象就可以称为“缓存过期产生的惊群现象”!
以下代码的思路,就是利用“锁机制”来防止惊群现象。先看代码:
class
KomaRedis{
private
$redis
;
//redis对象
private
static
$_instance
= null;
private
function
__construct(
$config
=
array
())
{
if
(
empty
(
$config
)) {
return
false;
}
$this
->redis =
new
Redis();
$this
->redis->connect(
$config
[
'server'
],
$config
[
'port'
]);
return
$this
->redis;
}
/**
* @param array $config
* @return redis操作类对象
*/
public
static
function
getInstance(
$config
=
array
())
{
if
(!(self::
$_instance
instanceof
self)) {
self::
$_instance
=
new
self (
$config
);
}
return
self::
$_instance
;
}
/**
* 获取缓存
* @param $key string $name
* @return array,object,number,string,boolean
* @desc 此方法使用了锁机制来防止防止缓存过期时所产生的惊群现象,保证只有一个进程不获取数据,可以更新,其他进程仍然获取过期数据
*/
public
function
getByLock(
$key
)
{
$sth
=
$this
->redis->get(
$key
);
if
(
$sth
=== false) {
return
$sth
;
}
else
{
$sth
= json_decode(
$sth
, TRUE);
if
(
intval
(
$sth
[
'expire'
]) <= time()) {
$lock
=
$this
->redis->incr(
$key
.
".lock"
);
if
(
$lock
=== 1) {
return
false;
}
else
{
return
$sth
[
'data'
];
}
}
else
{
return
$sth
[
'data'
];
}
}
}
/**
* 设置缓存
* @param $key string $name 缓存键
* @param $value $string ,array,object,number,boolean $value 缓存值
* @param null $ttl $string ,number $ttl 过期时间,如果不设置,则使用默认时间,如果为 infinity 则为永久保存
* @return bool
* @desc 此方法存储的数据会自动加入一些其他数据来避免惊群现象,如需保存原始数据,请使用 set
*/
public
function
setByLock(
$key
,
$value
,
$ttl
= null)
{
if
(
is_numeric
(
$ttl
) &&
intval
(
$ttl
) > 0) {
$ttl
=
intval
(
$ttl
);
$exp
= time() +
$ttl
;
$arg
=
array
(
"data"
=>
$value
,
"expire"
=>
$exp
);
}
else
{
$ttl
= 300;
$exp
= time() +
$ttl
;
}
empty
(
$ttl
) OR
$ttl
+= 300;
//增加redis缓存时间,使程序有足够的时间生成缓存
$arg
=
array
(
"data"
=>
$value
,
"expire"
=>
$exp
);
$rs
=
$this
->redis->setex(
$key
,
$ttl
, json_encode(
$arg
, TRUE));
$this
->redis->del(
$key
.
".lock"
);
return
$rs
;
}
/**
* 返回redis对象
* redis有非常多的操作方法,我们只封装了一部分
* 拿着这个对象就可以直接调用redis自身方法
*/
public
function
redis()
{
return
$this
->redis;
}
}
原理就是:
首先,在存储数据的时候,设置数据的过期时间比实际设置的过期时间多300秒,然后存储的数据中,通过一个数组来存储数据,数组中一个键用来存放真实的数据,另外一个键用来存放数据的真实过期时间,这个留到后期获取数据的时候做校验,然后把对应这个数据的“锁”删除掉。
这里这么做的原因和读取数据的做法相关!
然后,在读取数据的时候,依然像平时一样直接读取,如果数据已经超过了有效期(注意:这里的有效期并非设置的有效期,而是更该之后的有效期),那么就只能去读后端数据库。如果数据依然有效,则需要去判断,判断数据“在真正的有效期内是否失效”,如果没有失效,则直接返回数据!
重点是,假如数据“在伪造的有效期内没有失效,而在真正的有效期内已经失效”,那么这时就需要去判断“数据的锁”!
通过代码“$lock = $this->redis->incr($key . ".lock");”可以获取数据的锁,“$lock === 1”表示数据没有锁,那么这一次请求需要发送到后端数据库去读取最新的数据,否则的话表示该数据已经加了锁,也就是已经有一个线程去后端读取数据了,那么后来的线程也就没有权限再去后端取数据,需要等到前面的那个线程执行结束,但是这次读取就只能读取“旧的数据”了!
通过上面的解释也就明白,为什么在存储数据的时候需要“删除数据的锁”!因为一旦数据被重新存储,那么说明已经有一个线程去后端得到了最新的数据,那么该数据的锁就可以释放,然后下一个线程在获取数据的时候如果有需要就可以得到这个锁,然后才有权限进入到后端去读取新数据!
- Redis之利用锁机制来防止缓存过期产生的惊群现象
- Redis之利用锁机制来防止缓存过期产生的惊群现象
- Redis之利用锁机制来防止缓存过期产生的惊群现象
- 利用AOI来防止PCB缺陷的产生
- redis key的过期机制
- 防止点击后退的时候,出现网页过期的现象
- Redis之缓存机制
- 浅谈php的缓存机制之redis
- 利用缓存机制来实现对页面的优化
- 利用 filter 机制 给 静态资源 url 加上时间戳,来防止js和css文件的缓存,利于开发调试
- redis的key的过期机制
- Redis过期机制介绍
- redis过期处理机制
- Redis过期机制介绍
- Redis过期机制介绍
- 关于Memcached缓存设置过期时间时产生的异常
- php防止页面缓存,实现网页过期的方法
- redis setNX 锁来实现防止重复提交的
- 网络分析与图简介
- 第十九周OJ—Roken Necklace
- Leetcode刷题日记<Binary Tree Postorder Traversal>
- STM32中的main函数入口
- 最优化:拟牛顿法、最速下降法、共轭梯度法、信赖域法、协同优
- Redis之利用锁机制来防止缓存过期产生的惊群现象
- [UVA11605] Lights inside a 3d Grid && 数学期望
- jQuery实现异步上传图片(二)
- 231 金山笔试题
- 通过经纬度获取城市名/地址(不需要三方包)
- 数据结构第一章框图
- 实习日记4
- hadoop2.4.1格式化文件系统
- 网易游戏面试--两次股票买入卖出的最大收益