鸿 网 互 联 www.68idc.cn

Redis之利用锁机制来防止缓存过期产生的惊群现象

来源:互联网 作者:佚名 时间:2014-12-30 20:41
Redis之利用锁机制来防止缓存过期产生的惊群现象:首先,所谓的缓存过期引起的“惊群”现象是指,在大并发情况下,我们通常会用缓存来给数据库分压,但是会...

首先,所谓的缓存过期引起的“惊群”现象是指,在大并发情况下,我们通常会用缓存来给数据库分压,但是会有这么一种情况发生,那就是当一个缓存数据失效之后会导致同时有多个并发线程去向后端数据库发起请求去获取同一个数据,这样如果在一段时间内同时生成了大量的缓存,然后在另外一段时间内又有大量的缓存失效,这样就会导致后端数据库的压力突然增大,这种现象就可以称为“缓存过期生的惊群现象”!

以下代码的思路,就是利用“锁机制”来防止惊群现象。先看代码:

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;     } }


原理就是:

网友评论
<