上文问题处理
上文写了.Net Reids 入门到熟练,有道友说,不如起个名字叫 入门到删库,我说,删库不得行,最后,改成 入门到雪崩,哈哈。还是可以的
上文 .Net Reids 入门到熟练,文章中的 Redis Desktop Manager 软件收费,我是没得办法,用的老版本,有道友介绍说可以用 Another Redis Desktop Manager ,我自己也下载了,用着也是不错的说.
Another Redis Desktop Manager 下载地址 : https://github.com/qishibo/AnotherRedisDesktopManager/releases
也有道友说 StackExchange.Redis 这个.Net 的组件在特殊情况下会有 TimeOut的异常(通过增加线程池上限可以解决?可验证),建议使用 CSRedisCoe 或者 使用 FreeRedis 听说用这个更舒服。
#分布式锁 分布式环境中,最重要的三个技术点分别是,分布式锁、分布式事务、分布式选举,这三个技术点。
今天先对分布式锁进行简单的介绍和实现。
场景:当前服务非单体服务,在并发的业务的情况下,需要对独占的资源进行占用式分配使用,就需要用到分布式锁,简单来讲就是锁库存,锁单个的操作(比如,要更新某个数据,可能有点耗时,但是,又不能让N个服务同时都更新某个数据,就需要先锁住,更新完,对方再根据具体的情况执行其他业务。)
实现的技术,可以通过
-
1. Mysql(唯一主键索引)(通过插入业务唯一ID来实现,如果有插入的,说明抢锁失败)
-
2. Redis,Memcache (缓存)
-
3. Zookeeper (文件io)
这几个技术类型来看,速度最快的就是缓存了。
我们接下来就通过缓存来实现redis的分布式锁
锁的原理
其实就是假设有N个服务在运行,它们都需要做一件事情,但是,这个事情要排队来做,那就需要抢一个标志,证明谁可以做这个事情,这个标志,定义为锁,当其中一个服务抢到后,其他服务就抢不到了。只有抢到的服务释放了锁之后,其他服务才能抢这个锁,抢到了继续执行它自己的业务。
实际上,锁的速度是很快的,就像单体里的lock一样方便。
Redis 分布式锁 方案1
采用简单的方案实现
IDatabase.StringSet(key, value, TimeSpan, When.NotExists);
主要就是 When.NotExists ,当不存在的时候,插入成功,会有返回值,来判断。
/// <summary>
/// 实现一个redis锁,实现对特定资源的占用
/// </summary>
public class RedisLock
{
private IDatabase IDatabase;
private string key;
private string value;
private TimeSpan TimeSpan;
private TimeSpan TimeOut;
public RedisLock(IDatabase IDatabase, string key, string value, TimeSpan timeSpan, TimeSpan? timeout = null)
{
this.key = key;
this.value = value;
this.TimeSpan = timeSpan;
this.TimeOut = timeout.HasValue ? timeout.Value : timeSpan.Add(new TimeSpan(0, 0, 2));
this.IDatabase = IDatabase;
}
/// <summary>
/// 处理动作
/// </summary>
public bool Process(Action action)
{
bool state = false;
try
{
state = Lock();
if (state)
{
action?.Invoke();
}
}
finally
{
UnLock(state);
}
return state;
}
/// <summary>
/// 申请锁
/// </summary>
/// <returns></returns>
private bool Lock()
{
DateTime dateTime = DateTime.Now;
var state = false;
//申请标志位
while (!state && (DateTime.Now - dateTime) < TimeOut)
{
state = IDatabase.StringSet(key, value, TimeSpan, When.NotExists);
if (state)
{
break;
}
SpinWait.SpinUntil(() => false, 100);
}
return state;
}
/// <summary>
/// 释放锁
/// </summary>
/// <returns></returns>
private bool UnLock(bool lockState)
{
if (lockState)
{
IDatabase.KeyDelete(key);
}
else
{
var data = IDatabase.StringGet(key);
if (data == value)
{
IDatabase.KeyDelete(key);
}
}
return true;
}
}
结果也很不错

Redis 分布式锁 方案2
采用标准方式实现
redis 内置了lock的实现,主要是 LockTake LockQuery 和 LockRelease
主要是基于这几个方法进行的扩展
/// <summary>
/// 实现一个redis锁,实现对特定资源的占用
/// </summary>
public class RedisLock
{
private IDatabase IDatabase;
private string key;
private string value;
private TimeSpan TimeSpan;
private TimeSpan TimeOut;
public RedisLock(IDatabase IDatabase, string key, string value, TimeSpan timeSpan, TimeSpan? timeout = null)
{
this.key = key;
this.value = value;
this.TimeSpan = timeSpan;
this.TimeOut = timeout.HasValue ? timeout.Value : timeSpan.Add(new TimeSpan(0, 0, 2));
this.IDatabase = IDatabase;
}
/// <summary>
/// 处理动作
/// </summary>
public bool Process(Action action)
{
bool state = false;
try
{
state = Lock();
if (state)
{
action?.Invoke();
}
}
finally
{
UnLock(state);
}
return state;
}
/// <summary>
/// 申请锁
/// </summary>
/// <returns></returns>
private bool Lock()
{
DateTime dateTime = DateTime.Now;
var state = false;
//申请标志位
while (!state && (DateTime.Now - dateTime) < TimeOut)
{
state = IDatabase.LockTake(key, value, TimeSpan);
if (state)
{
break;
}
SpinWait.SpinUntil(() => false, 100);
}
return state;
}
/// <summary>
/// 释放锁
/// </summary>
/// <returns></returns>
private bool UnLock(bool lockState)
{
var data = IDatabase.LockQuery(key);
if (data == value)
{
IDatabase.LockRelease(key, value);
}
return true;
}
}
效果也是一样的
测试方法
class Program
{
static void Main(string[] args)
{
Console.Title = "redis lock Demo1 by 蓝创精英团队";
var connMultiplexer = ConnectionMultiplexer.Connect("127.0.0.1");
Console.WriteLine($"redis连接状态:{connMultiplexer.IsConnected}");
var db = connMultiplexer.GetDatabase(1);//可以选择指定的db,0-15
Test(db);
Console.WriteLine("redis lock 1 案例!");
Console.ReadLine();
}
public static void Test(IDatabase database)
{
var tasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
tasks.Add(Task.Run(() =>
{
var ID = Guid.NewGuid().ToString("N");
var redislock = new RedisLock(database, "key", ID, new TimeSpan(0, 0, 15), new TimeSpan(0, 0, 15 * 10));
redislock.Process(() => {
Console.WriteLine($"{DateTime.Now} - {ID}:申请到标志位!");
Console.WriteLine($"{DateTime.Now} - {ID}:处理自己的 事情!");
Thread.Sleep(5 * 1000);
Console.WriteLine($"{DateTime.Now} - {ID}:处理完毕!");
});
}));
}
Task.WaitAll(tasks.ToArray());
}
}
Redis分布式锁功能完结
完结撒花先。
Redis支持 Gzip压缩数据的支持
class Program
{
static void Main(string[] args)
{
Console.Title = "redis Gzip Demo by 蓝创精英团队";
var connMultiplexer = ConnectionMultiplexer.Connect("127.0.0.1");
Console.WriteLine($"redis连接状态:{connMultiplexer.IsConnected}");
var db = connMultiplexer.GetDatabase(1);//可以选择指定的db,0-15
//String
db.StringSet("str1", GzipCompress("123"));
var stringValue = db.StringGet("str1");
var data = GzipDecompress(stringValue);
Console.WriteLine($"获取到string 类型的值:{data}");
Console.WriteLine("redis gzip 案例!");
Console.ReadLine();
}
/// <summary>
/// gzip压缩
/// </summary>
static byte[] GzipCompress(string data)
{
using var gzipdata = new MemoryStream();
using var ms = new MemoryStream(Encoding.UTF8.GetBytes(data));
using var gs = new GZipStream(gzipdata, CompressionMode.Compress, true);
ms.CopyTo(gs);
var bytes = gzipdata.GetBuffer();
return bytes;
}
/// <summary>
/// gzip解压
/// </summary>
static string GzipDecompress(byte[] data)
{
if (data == null || data.Length == 0)
{
return null;
}
using MemoryStream ms = new(data);
using GZipStream compressedzipStream = new(ms, CompressionMode.Decompress);
using MemoryStream outBuffer = new();
byte[] block = new byte[1024];
while (true)
{
int bytesRead = compressedzipStream.Read(block, 0, block.Length);
if (bytesRead <= 0)
{
break;
}
else
{
outBuffer.Write(block, 0, bytesRead);
}
}
var bytes = outBuffer.ToArray();
return Encoding.UTF8.GetString(bytes);
}
}
程序运行的效果

以及 Another Redis Desktop Manager 看到的效果 :

总结
搞完了。这个gzip压缩功能用上了。性能提升也是看得见的。
代码地址
https://github.com/kesshei/RedisLockDemo.git
https://gitee.com/kesshei/RedisLockDemo.git