分布式快取系統 Memcached CAS協議

2021-09-07 05:11:57 字數 2525 閱讀 2036

memcached在1.2.4版本後新增了cas(check and set)協議,主要用於併發控制:memcached中同乙個item同時被多個執行緒(多個客戶端)更改的併發問題。cas協議最本質的東西——版本號,即將每個item都關聯乙個全域性唯一的編號,從而利用該唯一的編號來判斷item資料在某個執行緒操作期間有無被其他的執行緒所更改(每次更改版本號都會改變,因此可作為判斷的標識)。

如果不採用cas,則有如下的情景:

第一步,a取出資料物件x; 

第二步,b取出資料物件x; 

第三步,b修改資料物件x,並將其放入快取; 

第四步,a修改資料物件x,並將其放入快取。 

我們可以發現,第四步中會產生資料寫入衝突。

如果採用cas協議,則是如下的情景。 

第一步,a取出資料物件x,並獲取到cas-id1; 

第二步,b取出資料物件x,並獲取到cas-id2; 

第三步,b修改資料物件x,在寫入快取前,檢查cas-id與快取空間中該資料的cas-id是否一致。結果是「一致」,就將修改後的帶有cas-id2的x寫入到快取。 

第四步,a修改資料物件y,在寫入快取前,檢查cas-id與快取空間中該資料的cas-id是否一致。結果是「不一致」,則拒絕寫入,返回儲存失敗。

可以通過重試,或者其他業務邏輯解決第四步設定失敗的問題。

具體的,在memcached中,每個key關聯都乙個64-bit長度的long型惟一數值,表示該key對應value的版本號。這個數值由memcached server產生,從1開始,且同一memcached server中不會重複。在兩種情況下這個版本數值會加1:新增乙個key-value對 和 對某已有key對應的value值更新成功。刪除item,而版本值不會減小。

可由如下例子看出:

memcachedclient client = new memcachedclient();  

client.set("fkey", "fvalue");  

//第一次set, 在memcached server中會維護fkey對應的value的版本號,假設是548;  

client.set("fkey", "svalue");  

//再次set,則這個fkey對應的value的版本號變為549;  

casvalue casvalue = client.gets("fkey");  

//這樣就可以得到對應key的cas版本號和實際value(各個memcached client都有類似的物件表示,名字可能不一樣,但效果類同),如 casvalue.getvalue = "svalue",casvalue.getcas=549; 

注:get命令返回給定key的value值。 而gets則會返回給定key的value和cas版本號值。如下圖:

其中,先set 一次name,再gets name的返回值為:「value  name 0 3 2", 然後再進行一次set name,  這時gets name的返回值為」value  name 0 3 3「,最後乙個欄位由2變為了3,即版本號因為set更改了value值而被增加了一,而get name的返回值為」value name 0 3「,與gets的返回值相比,少最後的版本號的字段。

cas協議在併發控制中的具體應用:

乙個memcached server在有多個額客戶端時,分析下多個client併發set同乙個key的場景。如clienta想把當前key的value set為"x",且操作成功;clientb卻把當前key的value值由"x"覆蓋set為"y",這時clienta再根據key去取value時得到"y"而不是期望的"x",它使用這個值,但不知道這個值已經被其它執行緒修改過,就可能會出現問題。

而cas協議正是用於解決這種併發修改問題。有執行緒試圖修改當前key-value對的value時,先由gets方法得到item的版本號,操作完成提交資料時,則先比較獲取的版本號與當前item key中的版本號是否一致,如果是相同的,則提交資料,完整set等更改操作。反之,如果不一致,則說明在該執行緒對item操作過程中,這個key-value對被其它執行緒更改過(當然也就更改了版本號),於是放棄此次修改(樂觀鎖概念)。

memcached預設是開啟cas屬性的,每次執行更改操作後,儲存資料時,都會生成其cas值並和item一起嘗試這儲存(是否儲存成功,需要有版本號cas值是否一致來決定)如果操作成功則更改原版本號為該cas值,否則放棄本次操作。在進行gets操作會返回系統生成的cas值。

//為新的item生成cas值  

uint64_t get_cas_id(void)  

//執行cas儲存時執行的判斷邏輯,  

else if (item_get_cas(it) == item_get_cas(old_it))//版本號cas值一致  

else //版本號cas值不一致,不進行實際的儲存  

stored = exists;  

}當因為cas值衝突,而不能完成對item的更改操作時,可以通過比如重試等方式,待沒有其他執行緒同時來更改該item時,則能順利完成更改操作。

分布式快取 memcache學習

1.使用分布式快取是為了解決多台機器共享資訊的問題,通過訪問乙個ip和埠來可以訪問不同的iis伺服器 2.memcache基礎原理 在socket伺服器端儲存資料是以鍵值對的形式儲存 記憶體處理的演算法 本質就是乙個大的雜湊表。key最大長度是255個字元,value最大為1mb 記憶體模型 mem...

memcache的分布式快取問題

有關使用memcache做分布式快取的方案,簡單寫下來,僅供參考。memcache是優異的快取解決方案,很多專案都有使用。memcache服務本身並不具備分布式快取的能力,它提供的就是對對的訪問能力,分布式的能力則完全來自於客戶端。現在有不少memcache的客戶端lib採用consistent h...

分布式快取Memcache和Redis

針對於現在計算機的cpu和網路設施,對應用程式來說,執行效率的瓶頸,已經不是 的長度 實現同乙個功能 和頻寬了,而是,訪問資源的過程,即 讓我們的程式慢下來的罪魁禍首就是io操作。程式從硬碟上讀取資料是乙個非常花費時間的操作,因為我們現在所使用的硬碟是機械式的,你想機械的執行速度和電的速度,那是乙個...