用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/

相關文章
相關標籤/搜索