IT技术博客大学习 共学习 共进步

Memcache mutex设计模式

Tim[后端技术] 2010-07-26 23:45:30 浏览 4,905 次

周六的S2 Web 2.0技术沙龙上介绍了memcache中使用mutex场景(文后要演讲稿),有网友对详情感兴趣,简单介绍如下。

场景

Mutex主要用于有大量并发访问并存在cache过期的场合,如

  • 首页top 10, 由数据库加载到memcache缓存n分钟
  • 微博中名人的content cache, 一旦不存在会大量请求不能命中并加载数据库
  • 需要执行多个IO操作生成的数据存在cache中, 比如查询db多次

问题

在大并发的场合,当cache失效时,大量并发同时取不到cache,会同一瞬间去访问db并回设cache,可能会给系统带来潜在的超负荷风险。我们曾经在线上系统出现过类似故障

解决方法

方法一
在load db之前先add一个mutex key, mutex key add成功之后再去做加载db, 如果add失败则sleep之后重试读取原cache数据。为了防止死锁,mutex key也需要设置过期时间。伪代码如下
(注:下文伪代码仅供了解思路,可能存在bug,欢迎随时指出。)

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

相对于方案一
优点:避免cache失效时刻大量请求获取不到mutex并进行sleep
缺点:代码复杂性增大,因此一般场合用方案一也已经足够。

方案二在Memcached FAQ中也有详细介绍 How to prevent clobbering updates, stampeding requests,并且Brad还介绍了用他另外一个得意的工具 Gearman 来实现单实例设置cache的方法,见 Cache miss stampedes,不过用Gearman来解决就感觉就有点奇技淫巧了。

附:本次Web2.0技术沙龙演讲主题:微博Cache设计谈,需下载请点击演讲稿下menu/download (需登录slideshare)。

建议继续学习

  1. 关于memcache分布式一致性hash (阅读 11,661)
  2. Memcache分布式部署方案 (阅读 6,667)
  3. 关于session和memcache的若干问题 (阅读 5,186)
  4. 设计模式原则总结 (阅读 5,086)
  5. Memcache源代码分析之数据存储 (阅读 4,863)
  6. 自己写的一个轻量级javascript框架的设计模式 (阅读 4,763)
  7. 解决memcache连接奇慢问题一例 (阅读 4,747)
  8. Memcache协议的学习 (阅读 4,704)
  9. 关于Memcache长连接自动重连的问题 (阅读 4,641)
  10. Memcache源代码分析之网络处理 (阅读 4,544)