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才正确
 

 

posted @ 2018-08-24 12:29  以德为先  阅读(1853)  评论(0编辑  收藏  举报