在分布式緩存的應用中,會遇到多個客戶端同時爭用的問題。這個時候,需要用到分布式鎖,得到鎖的客戶端才有操作權限
下面通過一個簡單例子介紹:
這里引用的是
Memcached.ClientLibrary.dll

//引用 using Memcached.ClientLibrary; namespace Memcache.AddLock { public class MemcacheHelper { //實例化Client public MemcachedClient MClient; public MemcacheHelper() { //參數設置 string SockIOPoolName = "demo"; string[] MemcacheServiceList = { "127.0.0.1:11211" }; //設置連接池 SockIOPool SPool = SockIOPool.GetInstance(SockIOPoolName); SPool.SetServers(MemcacheServiceList); SPool.Initialize(); MClient = new MemcachedClient(); MClient.PoolName = SockIOPoolName; //是否啟用壓縮數據:如果啟用了壓縮,數據壓縮長於門檻的數據將被儲存在壓縮的形式 MClient.EnableCompression = false; ////壓縮設置,超過指定大小的都壓縮 //MClient.CompressionThreshold = 1024 * 1024; } /// <summary> /// 根據key存儲對象 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public bool Set(string key, object value) { var result = MClient.Set(key, value); return result; } /// <summary> /// 根據key存儲對象,並且設置過期時間 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <param name="timeOut"></param> /// <returns></returns> public bool Set(string key, object value, DateTime timeOut) { var result = MClient.Set(key, value, timeOut); return result; } /// <summary> /// 根據key獲取對應的對象 /// </summary> /// <param name="key"></param> /// <returns></returns> public object Get(string key) { var result = MClient.Get(key); return result; } /// <summary> /// 替換對應key的value /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public bool Replace(string key, object value) { var result = MClient.Replace(key, value); return result; } /// <summary> /// 刪除對應key /// </summary> /// <param name="key"></param> /// <returns></returns> public bool Delete(string key) { return MClient.Delete(key); } /// <summary> /// 刪除對應key,並設置從內存中移除的時間點 /// </summary> /// <param name="key"></param> /// <param name="timeOut"></param> /// <returns></returns> public bool Delete(string key, DateTime timeOut) { return MClient.Delete(key, timeOut); } /// <summary> /// 判斷key是否存在,存在返回true,不存在返回false /// </summary> /// <param name="key"></param> /// <returns></returns> public bool KeyExists(string key) { return MClient.KeyExists(key); } /// <summary> /// Memcache分布式鎖 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <returns>當key存在返回false,當key不存在返回true</returns> public bool Add(string key, object value) { return MClient.Add(key, value); } /// <summary> /// Memcache分布式鎖,並且設置過期時間 /// Memcached分布式鎖可以使用 Add 命令,該命令只有KEY不存在時,才進行添加,否則不會處理。Memcached 所有命令都是原子性的,並發下add 同一個KEY,只會一個會成功。 /// 利用這個原理,可以先定義一個鎖 LockKEY,Add 成功的認為是得到鎖。並且設置[過期超時] 時間,保證宕機后,也不會死鎖。 /// 在完成具體操作后,判斷鎖 LockKEY 是否已超時。如果超時則不刪除鎖,如果不超時則 Delete 刪除鎖。 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <param name="timeOut"></param> /// <returns>當key存在返回false,當key不存在返回true</returns> public bool Add(string key, object value, DateTime timeOut) { return MClient.Add(key, value, timeOut); } } }
控制台程序:

//引用 using Memcached.ClientLibrary; namespace Memcache.AddLock { /// <summary> /// Memcache分布式鎖簡單實例 /// </summary> public class Program { //創建一個公共類 public static MemcacheHelper memcache; public static void Main(string[] args) { memcache = new MemcacheHelper(); Console.WriteLine("線程開始前,輸出" + memcache.Get("demoKey")); var result = memcache.Delete("demoKey"); Console.WriteLine("線程開始前,輸出" + memcache.Get("demoKey") + ",刪除對應key返回:" + result); Console.WriteLine("線程開始前,輸出" + memcache.Delete("LockKey")); memcache.Set("demoKey", "0"); //定義三個線程 Thread myThread1 = new Thread(new ParameterizedThreadStart(AddVal)); Thread myThread2 = new Thread(new ParameterizedThreadStart(AddVal)); Thread myThread3 = new Thread(AddVal); myThread1.Start("1"); myThread2.Start("2"); myThread3.Start(); Console.WriteLine("等待兩個線程結束"); Console.ReadKey(); } public static void AddVal(object num) { for (int i = 0; i < 500; i++) { //int result = int.Parse(memcache.Get("demoKey").ToString()); //memcache.Set("demoKey", (result + 1).ToString()); //如果0.5秒不釋放鎖 自動釋放,避免死鎖 if (memcache.Add("LockKey", "Hello World", DateTime.Now.AddSeconds(0.5))) { //得到鎖 try { int result = int.Parse(memcache.Get("demoKey").ToString()); memcache.Set("demoKey", (result + 1).ToString()); //注意:這里最好加上主動去刪除鎖 //檢查鎖是否超時(直接去刪除就可以) memcache.Delete("LockKey"); } catch (Exception ex) { //發生異常時也直接刪除鎖 memcache.Delete("LockKey"); } } else { i = i - 1; //沒有得到鎖時等待 } } Console.WriteLine("線程" + num + "結束,輸出" + memcache.Get("demoKey")); } } }
運行結果效果圖說明:
圖一是沒有加分布式鎖的情況下執行結果

圖二是加分布式鎖的情況下執行結果,三個線程各循環500次,最終緩存值應該為1500才正確
