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


Posted in PHP onFebruary 27, 2016

缓存命名空间

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 相关文章推荐
利用PHP和AJAX创建RSS聚合器的代码
Mar 13 PHP
PHP程序员编程注意事项
Apr 10 PHP
php中将数组存到文件里的实现代码
Jan 19 PHP
zend framework配置操作数据库实例分析
Dec 06 PHP
PHP 自定义错误处理函数trigger_error()
Mar 26 PHP
浅谈PHP变量作用域以及地址引用问题
Dec 27 PHP
Thinkphp实现MySQL读写分离操作示例
Jun 25 PHP
PHP中读取文件的8种方法和代码实例
Aug 05 PHP
zend framework重定向方法小结
May 28 PHP
php自定义截取中文字符串-utf8版
Feb 27 PHP
PHP中ltrim()函数的用法与实例讲解
Mar 28 PHP
PhpStorm+xdebug+postman调试技巧分享
Sep 15 PHP
简单谈谈PHP中strlen 函数
Feb 27 #PHP
详解PHP的Laravel框架中Eloquent对象关系映射使用
Feb 26 #PHP
PHP文件缓存smarty模板应用实例分析
Feb 26 #PHP
PHP计算当前坐标3公里内4个角落的最大最小经纬度实例
Feb 26 #PHP
PHP实现根据时间戳获取周几的方法
Feb 26 #PHP
PHP将二维数组某一个字段相同的数组合并起来的方法
Feb 26 #PHP
关于PHP 如何用 curl 读取 HTTP chunked 数据
Feb 26 #PHP
You might like
php使用iconv中文截断问题的解决方法
2015/02/11 PHP
使用新浪微博API的OAuth认证发布微博实例
2015/03/27 PHP
深入理解PHP内核(二)之SAPI探究
2015/11/10 PHP
全面解读PHP的Yii框架中的日志功能
2016/03/17 PHP
PHP 网站修改默认访问文件的nginx配置
2017/05/27 PHP
Vagrant(WSL)+PHPStorm+Xdebu 断点调试环境搭建
2019/12/13 PHP
js 禁用浏览器的后退功能的简单方法
2008/12/10 Javascript
js focus不起作用的解决方法(主要是因为dom元素是否加载完成)
2010/11/05 Javascript
Javascript 闭包引起的IE内存泄露分析
2012/05/23 Javascript
javascript中强制执行toString()具体实现
2013/04/27 Javascript
基于JavaScript Array数组方法(新手必看篇)
2016/08/20 Javascript
微信小程序 登录的简单实现
2017/04/19 Javascript
jQuery实现的简单在线计算器功能
2017/05/11 jQuery
详解Angular 中 ngOnInit 和 constructor 使用场景
2017/06/22 Javascript
详解离线安装npm包的几种方法
2018/11/25 Javascript
微信小程序MUI导航栏透明渐变功能示例(通过改变opacity实现)
2019/01/24 Javascript
ZK中使用JS读取客户端txt文件内容问题
2019/11/07 Javascript
JavaScript检测浏览器是否支持CSS变量代码实例
2020/04/03 Javascript
详细解读tornado协程(coroutine)原理
2018/01/15 Python
python3+PyQt5使用数据库窗口视图
2018/04/24 Python
Python基于sklearn库的分类算法简单应用示例
2018/07/09 Python
python实现汉诺塔算法
2021/03/01 Python
python2和python3的输入和输出区别介绍
2018/11/20 Python
Python实现随机生成任意数量车牌号
2020/01/21 Python
python中with用法讲解
2020/02/07 Python
pytorch模型存储的2种实现方法
2020/02/14 Python
Selenium执行完毕未关闭chromedriver/geckodriver进程的解决办法(java版+python版)
2020/12/07 Python
澳大利亚宠物食品和用品商店:PETstock
2020/01/02 全球购物
"引用"与多态的关系
2013/02/01 面试题
一些Unix笔试题和面试题
2012/09/25 面试题
Ruby如何创建一个线程
2013/03/10 面试题
《宋庆龄故居的樟树》教学反思
2014/04/07 职场文书
政风行风自查自纠报告
2014/10/21 职场文书
2015年车间安全管理工作总结
2015/05/13 职场文书
百万英镑观后感
2015/06/09 职场文书
Javascript设计模式之原型模式详细
2021/10/05 Javascript