用KV系统实现并发锁

在key-value系统中缓存了网络服务器上一个重要的ticket,这个ticket用来受权。在必定的时间周期7200s里更新。现须要实现一个CGI提供给前端获取这个ticket,CGI访问量为天天百万pv左右。html

假设某一时刻ticket要过时时有A,B两个请求。A请求过来发现ticket过时,开始从网络服务器上获取最新的ticket并写入KV,同时服务器更新本身存储的ticket。而B刚好在A写入前读出了ticket,此时服务器上的ticket和A同步了。但B的ticket是过时的,这会致使用B获取的ticket去请求资源时失败。前端

于是须要读写分离。其实读写分离也意味着把并发锁转移,从可能几K个并发争锁减小到几个并发争锁。同时在CGI中下降了加锁成本。缓存

思路以下:服务器

  • CGI只进行读KV操做
  • 实现一个daemon程序,只负责每隔固定周期往KV更新ticket。用一个并发锁去控制写入时的资源竞争。

KV实现并发锁

往KV里添加一个字段daemon_mutex,对应的value为pid + timestamp网络

daemon可能会挂掉。挂掉会致使两方面问题并发

  • daemon进程占有写锁,挂掉后死锁
  • daemon进程挂掉后KV不会更新

所以能够启动三个daemon进程,相互监督。.net

步骤以下:code

  1. 3个进程争写锁,争到的进程为主进程,每隔1s刷新KV中daemon_mutex的timestamp字段,至关于心跳数据。每隔15分钟更新KV中的ticket。(ticket更新不用太频繁)
  2. 2个从进程每隔1s读KV中daemon_mutex的timestamp字段,若time(NULL) - kv.update_time() > 15说明主进程挂掉了,2个从进程开始争锁,抢到的进程升级为主进程。重复以上。

Memcache实现并发锁

memcache也能够利用add去实现并发锁,主要是经过add的原子性来判断是否要执行关键代码。htm

if (memcache.get(key) == null) {
    // 设置过时时间防止持有写锁的进程死锁
    if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {
        //主进程执行流,当能够增长key_mutex字段,说明得到锁
        //业务逻辑操做
        value = db.get(key);
        memcache.set(key, value);
        //删除key_mutex
        memcache.delete(key_mutex);
    } else {
        //从进程执行流
        sleep(50);
        retry();
    }
}

参考

http://www.cnblogs.com/dluf/p/3849075.htmlblog

http://timyang.net/programming/memcache-mutex/

相关文章
相关标签/搜索