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

在用memcache , 不可否认,memcache 在实际应用中的表现非常出色。不过也许正是因为其对速度和性能的要求过于严格,导致 memcache 的可操作性不是那么强。PHP 在使用的时候,也只能有限的使用 add、delete、replace、flush 等几个简单的方法。

memcache 官方是不建议我们手动去删除缓冲内容的, 因为官方的 api 中有关删除的方法只有 delete 和flush,前者是在知道 key 的情况下删除一个对象的值,后面是清除服务器上所有对象。

不过很多情况下,我们需要从服务器上删除一部分对象,又不希望把整个服务器上的对象都清空,官方的 FAQ 上提供了一个“伪命名空间(Simulating Namespaces )” 的作法。

Java代码  

  1. <?php  
  2. //生成一个用来保存 namespace 的 key  
  3. $ns_key = $memcache->get("product_namespace_key");  
  4.   
  5. //如果 key 不存在,则创建  
  6. if ($ns_key === false) $memcache->set("product_namespace_key", time());  
  7.   
  8. //根据 namespace_key 生成真正的 key  
  9. $my_key = $ns_key . md5($sql);  
  10. // 获取当前key下的缓存  
  11. $val = $memcache->get($my_key);  
  12. if (!$val) {  
  13.     $memcache->set($my_key, $dbValue, 600);  
  14. }  
  15. //需要删除整个namespace里的对象的时候,这样处理即可:  
  16. $memcache->increment("product_namespace_key");  
  17. ?>  

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

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

Java代码  

  1. if (memcache.get(key) == null) {  
  2.     // 3 min timeout to avoid mutex holder crash  
  3.     if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {  
  4.         value = db.get(key);  
  5.         memcache.set(key, value);  
  6.         memcache.delete(key_mutex);  
  7.     } else {  
  8.         sleep(50);  
  9.         retry();  
  10.     }  
  11. }  

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

Java代码  

  1. v = memcache.get(key);  
  2. if (v == null) { //不存在  
  3.     if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {  
  4.         value = db.get(key);  
  5.         memcache.set(key, value);  
  6.         memcache.delete(key_mutex);  
  7.     } else {  
  8.         sleep(50);  
  9.         retry();  
  10.     }  
  11. } else {  
  12.     if (v.timeout <= now()) {  //过期  
  13.         if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {  
  14.             // extend the timeout for other threads  
  15.             v.timeout += 3 * 60 * 1000;  
  16.             memcache.set(key, v, KEY_TIMEOUT * 2);  
  17.   
  18.             // load the latest value from db  
  19.             v = db.get(key);  
  20.             v.timeout = KEY_TIMEOUT;  
  21.             memcache.set(key, value, KEY_TIMEOUT * 2);  
  22.             memcache.delete(key_mutex);  
  23.         } else {  
  24.             sleep(50);  
  25.             retry();  
  26.         }  
  27.     }  
  28. }  
时间: 2024-09-12 10:32:34

Memcache时模拟命名空间及缓存失效问题的解决的相关文章

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

缓存命名空间 memcache本身不支持命名空间,但是我们可以利用 memcache本身的机制,来模拟命名空间.比如:你要清除一组数据,就需要用到命名空间,来看这样一个例子,说明写在了注释里: class Action { public function index() { global $mc_wr; // 获取命名空间 $ns_key = $mc_wr->get("foo_namespace_key"); // 如果命名空间不存在,则设置一个 if($ns_key===fal

缓存失效竟然可以这么解?

传统缓存失效策略 为了提高业务访问速度,提升业务读并发,很多用户都会在业务架构中引入缓存层.业务所有读请求全部路由到缓存层,通过缓存的内存读取机制大大提升业务读取性能.缓存中的数据不能持久化 ,一旦缓存异常退出,那么内存中的数据就会丢失,所以为了保证数据完整,业务的更新数据会落地到持久化存储中,例如DB.目前云用户的业务架构一般如下图: 在上图中,大家可以看到,用户的更新数据直接持久化到DB, 业务读请求直接请求缓存数据,所以业务需要解决缓存失效问题,即解决因为数据变更导致缓存中的数据失效的问题

缓存失效竟然可以这么解决?

数据传输提供的数据订阅功能,可以在不影响业务的情况下,实现简单.可靠的缓存失效逻辑.这种缓存失效机制为阿里巴巴多年架构优化沉淀下来的经验,下面我们一起来看数据订阅究竟怎么实现这种机制. 传统缓存失效策略 为了提高业务访问速度,提升业务读并发,很多用户都会在业务架构中引入缓存层.业务所有读请求全部路由到缓存层,通过缓存的内存读取机制大大提升业务读取性能.缓存中的数据不能持久化 ,一旦缓存异常退出,那么内存中的数据就会丢失,所以为了保证数据完整,业务的更新数据会落地到持久化存储中,例如DB.目前云用

缓存穿透和缓存失效的预防和解决

缓存穿透: 缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存, 这将导致这个不存在的数据每次请求都要到存储层去查询,如果有人恶意破坏,很可能直接对DB造成影响,这就失去了缓存的意义. 解决办法: 对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃.还有最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一 定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统

应对Memcached缓存失效,导致高并发查询DB的几种思路

最近看到nginx的合并回源,这个和下面的思路有点像.不过nginx的思路还是在控制缓存失效时的并发请求,而不是当缓存快要失效时,及时地更新缓存. nginx合并回源,参考:http://blog.csdn.net/brainkick/article/details/8570698 update: 2015-04-23 ====================== 当Memcached缓存失效时,容易出现高并发的查询DB,导致DB压力骤然上升. 这篇blog主要是探讨如何在缓存将要失效时,及时地

缓存穿透、缓存并发、缓存失效之思路变迁缓存穿透、缓存并发、缓存失效之思路变迁

我们在用缓存的时候,不管是Redis或者Memcached,基本上会通用遇到以下三个问题: 缓存穿透 缓存并发 缓存失效 一.缓存穿透     注: 上面三个图会有什么问题呢? 我们在项目中使用缓存通常都是先检查缓存中是否存在,如果存在直接返回缓存内容,如果不存在就直接查询数据库然后再缓存查询结果返回.这个时候如果我们查询的某一个数据在缓存中一直不存在,就会造成每一次请求都查询DB,这样缓存就失去了意义,在流量大时,可能DB就挂掉了. 那这种问题有什么好办法解决呢? 要是有人利用不存在的key频

缓存穿透、缓存并发、缓存失效之思路变迁

我们在用缓存的时候,不管是Redis或者Memcached,基本上会通用遇到以下三个问题: 缓存穿透 缓存并发 缓存失效 一.缓存穿透     注: 上面三个图会有什么问题呢? 我们在项目中使用缓存通常都是先检查缓存中是否存在,如果存在直接返回缓存内容,如果不存在就直接查询数据库然后再缓存查询结果返回.这个时候如果我们查询的某一个数据在缓存中一直不存在,就会造成每一次请求都查询DB,这样缓存就失去了意义,在流量大时,可能DB就挂掉了. 那这种问题有什么好办法解决呢? 要是有人利用不存在的key频

应对Memcached缓存失效,导致高并发查询DB的四种思路(l转)

当Memcached缓存失效时,容易出现高并发的查询DB,导致DB压力骤然上升. 这篇blog主要是探讨如何在缓存将要失效时,及时地更新缓存,而不是如何在缓存失效之后,如何防止高并发的DB查询. 解决这个问题有四种思路: 比如一个key是aaa,失效时间是30s.   1.定期从DB里查询数据,再刷到memcached里 这种方法有个缺点是,有些业务的key可能是变化的,不确定的. 而且不好界定哪些数据是应该查询出来放到缓存中的,难以区分冷热数据.   2.当缓存取到为null时,加锁去查询DB

ios-使用SDWebImage时想要更改缓存

问题描述 使用SDWebImage时想要更改缓存 在开发过程中遇到的一个问题,SDWebImage的缓存机制是根据URL来的,所以当后台在URL不变的情况下更改了图片,客户端使用的仍然是未更改前的图片,只有用户清除了缓存后再进入应用才能看到这张新图片,那么问题来了,如果是诸如显示头像这种有可能会经常更换的图片,不得不进行缓存更改了,SDWebImage的sd_setImageWithURL方法中可以携带一个option参数,这个参数默认是0,如果使用SDWebImageRefreshCached