Memcache分布式锁

时间:2022-05-30 05:41:44

在分布式缓存的应用中,会遇到多个客户端同时争用的问题。这个时候,需要用到分布式锁,得到锁的客户端才有操作权限

下面通过一个简单例子介绍:
这里引用的是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", "");
//定义三个线程
Thread myThread1 = new Thread(new ParameterizedThreadStart(AddVal));
Thread myThread2 = new Thread(new ParameterizedThreadStart(AddVal));
Thread myThread3 = new Thread(AddVal);
myThread1.Start("");
myThread2.Start("");
myThread3.Start();
Console.WriteLine("等待两个线程结束");
Console.ReadKey();
} public static void AddVal(object num)
{
for (int i = ; i < ; 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 + ).ToString()); //注意:这里最好加上主动去删除锁
//检查锁是否超时(直接去删除就可以)
memcache.Delete("LockKey");
}
catch (Exception ex)
{
//发生异常时也直接删除锁
memcache.Delete("LockKey");
}
}
else
{
i = i - ; //没有得到锁时等待
}
}
Console.WriteLine("线程" + num + "结束,输出" + memcache.Get("demoKey"));
}
}
}

运行结果效果图说明:

图一是没有加分布式锁的情况下执行结果
 Memcache分布式锁
图二是加分布式锁的情况下执行结果,三个线程各循环500次,最终缓存值应该为1500才正确
Memcache分布式锁