PHP使用Memcache时模拟命名空间及缓存失效问题的解决

5年以前  |  阅读数:408 次  |  编程语言:PHP 

缓存命名空间

memcache本身不支持命名空间,但是我们可以利用 memcache本身的机制,来模拟命名空间。比如:你要清除一组数据,就需要用到命名空间,来看这样一个例子,说明写在了注释里:


    class Action
    {

     public function index()
     {
      global $mc_wr;

      // 获取命名空间
      $ns_key = $mc_wr->get("foo_namespace_key");
      // 如果命名空间不存在,则设置一个
      if($ns_key===false) $mc_wr->set("foo_namespace_key",time());

      $otherParms = 'select * from user LIMIT 1';
      // 根据命名空间生成唯一的key
      $my_key = "foo_".$ns_key.'_'.md5($otherParms);

      // 获取当前key下的缓存
      $val = $mc_wr->get($my_key);
      if (!$val) {
       $value = 'wangdekang_'.time();
       // 缓存不存在则设置缓存 600秒, 0为随机失效时间, 为失效时间添加随机秒数,防止瞬间所有缓存同时失效
       $mc_wr->set($my_key,$value,600, 0);
      }

      echo $val;
     }

     public function clear_ns()
     {
      global $mc_wr;
      // 更新命名空间值,让当前命名空间的所有值失效, memcache自身的缓存失效机制,当缓存不在被访问,会通过LRU失效机制
      $mc_wr->set('foo_namespace_key', time());
     }
    }

memcache缓存失效问题
在大并发的场合,当cache失效时,大量并发同时取不到cache,会同一瞬间去访问db并回设cache,可能会给系统带来潜在的超负荷风险。
解决方法:

方法一
在load db之前先add一个mutex key, mutex key add成功之后再去做加载db, 如果add失败则sleep之后重试读取原cache数据。为了防止死锁,mutex key也需要设置过期时间。伪代码如下


    if (memcache.get(key) == null) {
     // 3 min timeout to avoid mutex holder crash
     if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {
      value = db.get(key);
      memcache.set(key, value);
      memcache.delete(key_mutex);
     } else {
      sleep(50);
      retry();
     }
    } 

方法二
在value内部设置1个超时值(timeout1), timeout1比实际的memcache
timeout(timeout2)小。当从cache读取到timeout1发现它已经过期时候,马上延长timeout1并重新设置到cache。然
后再从数据库加载数据并设置到cache中。伪代码如下


    v = memcache.get(key);
    if (v == null) {
     if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {
      value = db.get(key);
      memcache.set(key, value);
      memcache.delete(key_mutex);
     } else {
      sleep(50);
      retry();
     }
    } else {
     if (v.timeout <= now()) {
      if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {
       // extend the timeout for other threads
       v.timeout += 3 * 60 * 1000;
       memcache.set(key, v, KEY_TIMEOUT * 2);

       // load the latest value from db
       v = db.get(key);
       v.timeout = KEY_TIMEOUT;
       memcache.set(key, value, KEY_TIMEOUT * 2);
       memcache.delete(key_mutex);
      } else {
       sleep(50);
       retry();
      }
     }
    }
 相关文章:
PHP分页显示制作详细讲解
SSH 登录失败:Host key verification failed
获取IMSI
将二进制数据转为16进制以便显示
获取IMEI
文件下载
贪吃蛇
双位运算符
PHP自定义函数获取搜索引擎来源关键字的方法
Java生成UUID
发送邮件
年的日历图
提取后缀名
在Zeus Web Server中安装PHP语言支持
让你成为最历害的git提交人
Yii2汉字转拼音类的实例代码
再谈PHP中单双引号的区别详解
指定应用ID以获取对应的应用名称
Python 2与Python 3版本和编码的对比
php封装的page分页类完整实例