Memcache分布式鎖


在分布式緩存的應用中,會遇到多個客戶端同時爭用的問題。這個時候,需要用到分布式鎖,得到鎖的客戶端才有操作權限

下面通過一個簡單例子介紹:
這里引用的是 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);
        }
    }
}
View Code

控制台程序:

//引用
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"));          
        }
    }
}
View Code

運行結果效果圖說明:

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM