Memcache mutex设计模式

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

场景

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

  • 首页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
缺点:代码复杂性增大,所以通常场合用方案一也已经足够。app

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

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