wenfengsun

memcache的mutex模式

Posted on: July 26, 2011

memcache在高并发的情况下,可能会出现一个key多个线程去操作的情况;

典型的场景是:

1. API限制频率的场合,当某个用户的请求同时发过来的时候,如何更新缓存;

2. 当某缓存失效,要去数据库读取的时候,此时大量并发请求会造成数据库压力过大;

此时要考虑使用mutex模式,即为读取和设置增加一把锁。

方式1.增加锁,利用memcached的add操作的原子性保证同时只有一个进程获得锁。

例如:

String mutexKey = key+"_mutex";
MemcacheUtil client = MemcacheUtil.getInstance();
try{
if(client.getValue(mutexKey)==null){
if(client.add(mutexKey, "true", 10)){
int timer = (int)(rate.getReset_time_in_seconds()-(System.currentTimeMillis()/1000));
client.putObjValue(key, rate, timer);//set remain time.
client.removeValue(mutexKey);
}else{
Thread.sleep(10);
updateRateCache(rate, key);
}
}else{
Thread.sleep(10);
updateRateCache(rate, key);
}
}catch(Exception e){
log.error("Update ratelimit error-->"+e);
e.printStackTrace();
}

方式2.为了避免大量的请求阻塞,获取不到数据,而在value写入的时候加入timeout,在过期之后,用锁机制去db获取数据,而其他的未获取到db获取权限的,则还是从缓存读取数据。

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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: