1. 数据库乐观锁;数据库
2. 基于Redis的分布式锁;less
3. 基于ZooKeeper的分布式锁。本篇博客将介绍第二种方式,基于Redis实现分布式锁。虽然网上已经有各类介绍Redis分布式锁实现的博客,然而他们的实现却有着各类各样的问题,为了不误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁。分布式
首先,为了确保分布式锁可用,咱们至少要确保锁的实现同时知足如下四个条件:ui
互斥性。在任意时刻,只有一个客户端能持有锁。code
不会发生死锁。即便有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其余客户端能加锁。get
具备容错性。只要大部分的Redis节点正常运行,客户端就能够加锁和解锁。博客
解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端本身不能把别人加的锁给解了。string
使用StackExchange.Redis 实现起来简单得很io
/// <summary> /// 加锁,若是锁定成功,就去执行方法 /// </summary> public static bool LockTake(string key, string data, int seconds, int db = 0) { // key:用key来当锁,由于key是惟一的。 // value:不少童鞋可能不明白,有key做为锁不就够了吗,为何还要用到value?缘由就是咱们在上面讲到可靠性时, // 分布式锁要知足第四个条件解铃还须系铃人,经过给value赋值为Guid.NewGuid().ToString(),咱们就知道这把锁是哪一个请求加的了,在解锁的时候就能够有依据。 return GetDatabase(db).LockTake(key, data, (DateTime.Now.AddSeconds(seconds) - DateTime.Now)); } /// <summary> /// 解锁 /// </summary> public static bool LockRelease(string key, string data, int db = 0) { return GetDatabase(db).LockRelease(key, data); }
调用实现class
string guid = Guid.NewGuid().ToString(); if (RedisHelper.LockTake(wechatOpenId, guid, 90, 15)) { try { // 执行方法 } catch (Exception e) { // 异常 } finally { RedisHelper.LockRelease(wechatOpenId, guid, 15); } } else { // 已锁,没法执行 return null; }