wenfengsun

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

linux随机启动原理分析。

首先,linux随机启动有七个级别,分别是0-6,它们代表的意义是:

#0:停机

#1:单用户模式

#2:多用户模式,没有NFS

#3:完全多用户模式(标准模式)

#4:not used

#5:X11(xWindow)

#6: 重新启动

备注:千万不能设置initdefault为0和6.

这些级别的配置在/etc/inittab文件中配置,可以查看当前机器配置的是哪个级别。

那么Linux究竟是如何启动那些服务的呢?答案是通过脚本启动。

在/etc/rc(n) 文件夹下指明那些脚本是随机启动的【注意,这里的n的取值是0-6】。

这些脚本会统一配置到:/etc/init.d,而rc(n)目录下只是到这些脚本的软连接。

建立一个软连接的命令是:ln -s /etc/rc.d/init.d/apached /etc/rc3.d/S90apache

这里为软连接命名是有规范的:凡是以K开头的,表示随机不启动;凡是以S开头的,表示随机启动;

启动脚本:

你可能需要去网上搜罗有用的启动脚本了,因为脚本至少要提供 start命令才能够在启动的时候顺利启动。

当然,start|stop|restart 作为最常用的三个命令是必要的。

特别说明,如果你打算随机启动一个resin的web服务,那么你要做的事情会不少:

1. 去你的$RESIN_HOME/contrib下,拷贝init.resin到/etc/init.d下并重命名为resin,cp $RESIN_HOME/contrib/init.resin /etc/init.d/resin【备注:如果你的resin下没有contrib目录,说明你是拷贝过来的,并非以configure/make/make install的方式完成安装的。你需要重新编译安装resin即可得到这个目录】

2. 增加resin文件的权限:chmod 755 resin

3. 修改文件中的JAVA_HOME, RESIN_HOME为真实的目录地址。修改你的启动脚本,如果你使用了其他的配置文件,请在$EXE -p $PID -conf $RESIN_HOME/conf/xxx.conf -server xxx start $JARGS, 同时也要修改stop的设置。

4. 配置到启动目录,在/etc/rc3目录下增加软连接 ln -s /etc/init.d/resin S20resin

reboot后就会发现,这个服务随机启动了。

而且,你可以通过service resin start|stop|restart来操作这个服务。