环境:之前一直是使用serverStack.Redis的客服端,
今天来使用一下StackExchange.Redis(个人感觉更加的人性化一些,也是免费的,性能也不会差太多),
版本为StackExchange.Redis V2.1.58 ,Core3.1

简单的说明(专业的术语参考资料网络和官网):官网地址:https://www.redis.net.cn/

Redis是一个开源的 ,由C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

Redis 是一个高性能的key-value数据库。Redis的出现,很大程度补偿了memcached这类key/value存储的不足,

提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。

优点:

1 Redis读写性能优异,从内存当中进行IO读写速度快,支持超过100K+每秒的读写频率。

2 Redis支持Strings,

Lists, Hashes, Sets,Ordered Sets等数据类型操作。

3 Redis支持数据持久化,支持AOF和RDB两种持久化方式

4 Redis支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。

5 Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。

6 Redis是单线程多CPU,不需要考虑加锁释放锁,也就没有死锁的问题,效率高。

1:redis队列值入队出队,截图效果:

优化之前将近50秒了,这实在太慢了

优化后的效果:为5.55s的样子

2:redis发布与订阅截图效果:(一个发布者,四个订阅者)

3:redis秒杀,截图如下:单个进程秒杀ok

开多个进程时,会有超卖的现象:

4:redis值分布式锁,截图:

但是这样会比较耗资源

分布式锁ok库存为零就不在请求直接抛异常即可

上面通过测试的截图,简单的介绍了,Redis的队列(入队和出队),Redis发布与订阅,Redis分布式锁的使用,现在直接上代码 :

出队入队的WebApi Core3.1

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; namespace WebApp.Controllers
{
using Microsoft.AspNetCore.Mvc;
using RedisPublishAndSubHelper;
[Route("api/[Controller]")]
[ApiController]
public class RedisTestController
{
[HttpGet("EnqueueMsg")]
public async Task<ApiResultObject> EnqueueMsgAsync(string rediskey, string redisValue)
{
ApiResultObject obj = new ApiResultObject();
try
{
long enqueueLong = default;
for (int i = ; i < ; i++)
{
enqueueLong = await MyRedisSubPublishHelper.EnqueueListLeftPushAsync(rediskey, redisValue + i);
}
obj.Code = ResultCode.Success;
obj.Data = "入队的数据长度:" + enqueueLong;
obj.Msg = "入队成功!";
}
catch (Exception ex)
{ obj.Msg = $"入队异常,原因:{ex.Message}";
}
return obj;
}
[HttpGet("DequeueMsg")]
public async Task<ApiResultObject> DequeueMsgAsync(string rediskey)
{
ApiResultObject obj = new ApiResultObject();
try
{
string dequeueMsg = await MyRedisSubPublishHelper.DequeueListPopRightAsync(rediskey);
obj.Code = ResultCode.Success;
obj.Data = $"出队的数据是:{dequeueMsg}";
obj.Msg = "入队成功!";
}
catch (Exception ex)
{
obj.Msg = $"入队异常,原因:{ex.Message}";
}
return obj;
}
}
}

出队入队的后端code WebApi:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; namespace WebApp.Controllers
{
using Microsoft.AspNetCore.Mvc;
using RedisPublishAndSubHelper;
[Route("api/[Controller]")]
[ApiController]
public class RedisTestController
{
[HttpGet("EnqueueMsg")]
public async Task<ApiResultObject> EnqueueMsgAsync(string rediskey, string redisValue)
{
ApiResultObject obj = new ApiResultObject();
try
{
long enqueueLong = default;
for (int i = ; i < ; i++)
{
enqueueLong = await MyRedisSubPublishHelper.EnqueueListLeftPushAsync(rediskey, redisValue + i);
}
obj.Code = ResultCode.Success;
obj.Data = "入队的数据长度:" + enqueueLong;
obj.Msg = "入队成功!";
}
catch (Exception ex)
{ obj.Msg = $"入队异常,原因:{ex.Message}";
}
return obj;
}
[HttpGet("DequeueMsg")]
public async Task<ApiResultObject> DequeueMsgAsync(string rediskey)
{
ApiResultObject obj = new ApiResultObject();
try
{
string dequeueMsg = await MyRedisSubPublishHelper.DequeueListPopRightAsync(rediskey);
obj.Code = ResultCode.Success;
obj.Data = $"出队的数据是:{dequeueMsg}";
obj.Msg = "入队成功!";
}
catch (Exception ex)
{
obj.Msg = $"入队异常,原因:{ex.Message}";
}
return obj;
}
}
}

入队以及秒杀分布式锁的客服端的Code:

 using System;
using System.Threading;
using System.Threading.Tasks; namespace RedisPublishService
{
using RedisPublishAndSubHelper;
class Program
{
static void Main(string[] args)
{
#region 入队的code
{
int Index = ;
while (Index > )
{
//string msg = Console.ReadLine();
new MyRedisSubPublishHelper().PublishMessage("nihaofengge", $"你好风哥:Guid值是:{DateTime.Now}{Guid.NewGuid().ToString()}");
Console.WriteLine("发布成功!");
Index -= ;
}
Console.ReadKey();
}
#endregion #region 秒杀的code
{
try
{
Console.WriteLine("秒杀开始。。。。。");
for (int i = ; i < ; i++)
{
Task.Run(() =>
{
MyRedisSubPublishHelper.LockByRedis("mstest");
string productCount = MyRedisHelper.StringGet("productcount");
int pcount = int.Parse(productCount);
if (pcount > )
{
long dlong = MyRedisHelper.StringDec("productcount");
Console.WriteLine($"秒杀成功,商品库存:{dlong}");
pcount -= ;
System.Threading.Thread.Sleep();
}
else
{
Console.WriteLine($"秒杀失败,商品库存为零了!");
throw new Exception("产品秒杀数量为零!");//加载这里会比较保险
}
MyRedisSubPublishHelper.UnLockByRedis("mstest");
}).Wait();
}
}
catch (Exception ex)
{
Console.WriteLine($"产品已经秒杀完毕,原因:{ex.Message}");
}
Console.ReadKey();
}
#endregion
}
}
}

完整的code RedisHelper帮助类(测试并使用了部分方法的封装),

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; namespace RedisPublishAndSubHelper
{
using StackExchange.Redis;
using StackExchange;
using System.Threading; public class MyRedisHelper
{
private static readonly string connectionRedisStr = string.Empty;// "47.107.87.32:6379,connectTimeout=1000,connectRetry=3,syncTimeout=10000";
static MyRedisHelper()
{
//在这里来初始化一些配置信息
connectionRedisStr = "12.23.45.12:6379,connectTimeout=1000,connectRetry=3,syncTimeout=10000";
} #region Redis string简单的常见同步方法操作
public static bool StringSet(string key, string stringValue, double senconds = )
{
using (var conn = ConnectionMultiplexer.Connect(connectionRedisStr))
{
IDatabase db = conn.GetDatabase();
return db.StringSet(key, stringValue, TimeSpan.FromSeconds(senconds));
}
}
public static string StringGet(string key)
{
using (var conn = ConnectionMultiplexer.Connect(connectionRedisStr))
{
IDatabase db = conn.GetDatabase();
return db.StringGet(key);
}
} public static long StringInc(string key)
{
using (var conn = ConnectionMultiplexer.Connect(connectionRedisStr))
{
IDatabase db = conn.GetDatabase();
return db.StringIncrement(key);
}
} public static long StringDec(string key)
{
using (var conn = ConnectionMultiplexer.Connect(connectionRedisStr))
{
IDatabase db = conn.GetDatabase();
return db.StringDecrement(key);
}
}
public static bool KeyExists(string key)
{
using (var conn = ConnectionMultiplexer.Connect(connectionRedisStr))
{
IDatabase db = conn.GetDatabase();
return db.KeyExists(key);
}
}
#endregion #region List Hash, Set,Zset 大同小异的使用,比较简单,后续有时间再补上 #endregion #region 入队出队 #region 入队
/// <summary>
/// 入队right
/// </summary>
/// <param name="queueName"></param>
/// <param name="redisValue"></param>
/// <returns></returns>
public static long EnqueueListRightPush(RedisKey queueName, RedisValue redisValue)
{
using (var conn = ConnectionMultiplexer.Connect(connectionRedisStr))
{
return conn.GetDatabase().ListRightPush(queueName, redisValue);
}
}
/// <summary>
/// 入队left
/// </summary>
/// <param name="queueName"></param>
/// <param name="redisvalue"></param>
/// <returns></returns>
public static long EnqueueListLeftPush(RedisKey queueName, RedisValue redisvalue)
{
using (var conn = ConnectionMultiplexer.Connect(connectionRedisStr))
{
return conn.GetDatabase().ListLeftPush(queueName, redisvalue);
}
}
/// <summary>
/// 入队left异步
/// </summary>
/// <param name="queueName"></param>
/// <param name="redisvalue"></param>
/// <returns></returns>
public static async Task<long> EnqueueListLeftPushAsync(RedisKey queueName, RedisValue redisvalue)
{
using (var conn = await ConnectionMultiplexer.ConnectAsync(connectionRedisStr))
{
return await conn.GetDatabase().ListLeftPushAsync(queueName, redisvalue);
}
}
/// <summary>
/// 获取队列的长度
/// </summary>
/// <param name="queueName"></param>
/// <returns></returns>
public static long EnqueueListLength(RedisKey queueName)
{
using (var conn = ConnectionMultiplexer.Connect(connectionRedisStr))
{
return conn.GetDatabase().ListLength(queueName);
}
} #endregion #region 出队
public static string DequeueListPopLeft(RedisKey queueName)
{
using (var conn = ConnectionMultiplexer.Connect(connectionRedisStr))
{
IDatabase database = conn.GetDatabase();
int count = database.ListRange(queueName).Length;
if (count <= )
{
throw new Exception($"队列{queueName}数据为零");
}
string redisValue = database.ListLeftPop(queueName);
if (!string.IsNullOrEmpty(redisValue))
return redisValue;
else
return string.Empty;
}
}
public static string DequeueListPopRight(RedisKey queueName)
{
using (var conn = ConnectionMultiplexer.Connect(connectionRedisStr))
{
IDatabase database = conn.GetDatabase();
int count = database.ListRange(queueName).Length;
if (count <= )
{
throw new Exception($"队列{queueName}数据为零");
}
string redisValue = conn.GetDatabase().ListRightPop(queueName);
if (!string.IsNullOrEmpty(redisValue))
return redisValue;
else
return string.Empty;
}
}
public static async Task<string> DequeueListPopRightAsync(RedisKey queueName)
{
using (var conn = await ConnectionMultiplexer.ConnectAsync(connectionRedisStr))
{
IDatabase database = conn.GetDatabase();
int count = (await database.ListRangeAsync(queueName)).Length;
if (count <= )
{
throw new Exception($"队列{queueName}数据为零");
}
string redisValue = await conn.GetDatabase().ListRightPopAsync(queueName);
if (!string.IsNullOrEmpty(redisValue))
return redisValue;
else
return string.Empty;
}
}
#endregion #endregion #region 分布式锁
public static void LockByRedis(string key, int expireTimeSeconds = )
{
try
{
IDatabase database1 = ConnectionMultiplexer.Connect(connectionRedisStr).GetDatabase();
while (true)
{
expireTimeSeconds = expireTimeSeconds > ? : expireTimeSeconds;
bool lockflag = database1.LockTake(key, Thread.CurrentThread.ManagedThreadId, TimeSpan.FromSeconds(expireTimeSeconds));
if (lockflag)
{
break;
}
}
}
catch (Exception ex)
{
throw new Exception($"Redis加锁异常:原因{ex.Message}");
}
} public static bool UnLockByRedis(string key)
{
ConnectionMultiplexer conn = ConnectionMultiplexer.Connect(connectionRedisStr);
try
{
IDatabase database1 = conn.GetDatabase();
return database1.LockRelease(key, Thread.CurrentThread.ManagedThreadId);
}
catch (Exception ex)
{
throw new Exception($"Redis加锁异常:原因{ex.Message}");
}
finally
{
if (conn != null)
{
conn.Close();
conn.Dispose();
}
}
}
#endregion }
}

 using System;
using System.Collections.Generic;
using System.Text; namespace RedisPublishAndSubHelper
{
using StackExchange.Redis;
using System.Net.Http;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks; public class MyRedisSubPublishHelper
{
private static readonly string redisConnectionStr = "12.32.12.54:6379,connectTimeout=10000,connectRetry=3,syncTimeout=10000";
private static readonly ConnectionMultiplexer connectionMultiplexer = null;
static MyRedisSubPublishHelper()
{
connectionMultiplexer = ConnectionMultiplexer.Connect(redisConnectionStr);
} #region 发布订阅
public void SubScriper(string topticName, Action<RedisChannel, RedisValue> handler = null)
{
ISubscriber subscriber = connectionMultiplexer.GetSubscriber();
ChannelMessageQueue channelMessageQueue = subscriber.Subscribe(topticName);
channelMessageQueue.OnMessage(channelMessage =>
{
if (handler != null)
{
string redisChannel = channelMessage.Channel;
string msg = channelMessage.Message;
handler.Invoke(redisChannel, msg);
}
else
{
string msg = channelMessage.Message;
Console.WriteLine($"订阅到消息: { msg},Channel={channelMessage.Channel}");
}
});
}
public void PublishMessage(string topticName, string message)
{
ISubscriber subscriber = connectionMultiplexer.GetSubscriber();
long publishLong = subscriber.Publish(topticName, message);
Console.WriteLine($"发布消息成功:{publishLong}");
}
#endregion #region 入队出队
public static async Task<long> EnqueueListLeftPushAsync(RedisKey queueName, RedisValue redisvalue)
{
return await connectionMultiplexer.GetDatabase().ListLeftPushAsync(queueName, redisvalue);
} public static async Task<string> DequeueListPopRightAsync(RedisKey queueName)
{
IDatabase database = connectionMultiplexer.GetDatabase();
int count = (await database.ListRangeAsync(queueName)).Length;
if (count <= )
{
throw new Exception($"队列{queueName}数据为零");
}
string redisValue = await database.ListRightPopAsync(queueName);
if (!string.IsNullOrEmpty(redisValue))
return redisValue;
else
return string.Empty;
}
#endregion #region 分布式锁
public static void LockByRedis(string key, int expireTimeSeconds = )
{
try
{
IDatabase database = connectionMultiplexer.GetDatabase();
while (true)
{
expireTimeSeconds = expireTimeSeconds > ? : expireTimeSeconds;
bool lockflag = database.LockTake(key, Thread.CurrentThread.ManagedThreadId, TimeSpan.FromSeconds(expireTimeSeconds));
if (lockflag)
{
break;
}
}
}
catch (Exception ex)
{
throw new Exception($"Redis加锁异常:原因{ex.Message}");
}
} public static bool UnLockByRedis(string key)
{
try
{
IDatabase database = connectionMultiplexer.GetDatabase();
return database.LockRelease(key, Thread.CurrentThread.ManagedThreadId);
}
catch (Exception ex)
{
throw new Exception($"Redis加锁异常:原因{ex.Message}");
}
}
#endregion
}
}

.NetCore使用Redis,StackExchange.Redis队列,发布与订阅,分布式锁的简单使用的更多相关文章

  1. redis集群+JedisCluster+lua脚本实现分布式锁(转)

    https://blog.csdn.net/qq_20597727/article/details/85235602 在这片文章中,使用Jedis clien进行lua脚本的相关操作,同时也使用一部分 ...

  2. StackExchange.Redis学习笔记(五) 发布和订阅

    Redis命令中的Pub/Sub Redis在 2.0之后的版本中 实现了 事件推送的  发布订阅命令 以下是Redis关于发布和订阅提供的相关命令 SUBSCRIBE channel [channe ...

  3. redis实现消息队列&发布/订阅模式使用

    在项目中用到了redis作为缓存,再学习了ActiveMq之后想着用redis实现简单的消息队列,下面做记录.   Redis的列表类型键可以用来实现队列,并且支持阻塞式读取,可以很容易的实现一个高性 ...

  4. .netcore里使用StackExchange.Redis TimeOut 情况解决方法

    在用StackExchange.Redis这个组件时候,时不时会出现异常TimeOut解决方法如下, 解决方法: 在Program的Main入口方法里添加一句话: System.Threading.T ...

  5. EF+Redis(StackExchange.Redis)实现分布式锁,自测可行

    电商平台 都会有抢购的情况,比如 1元抢购. 而抢购 最重要的 就是库存,很多情况下  库存处理不好,就会出现超卖现象. 本文将用redis为缓存,StackExchange 框架,消息队列方式 实现 ...

  6. Redis系列(八):发布与订阅

    Redis的发布与订阅,有点类似于消息队列,发送者往频道发送消息,频道的订阅者接收消息. 1. 发布与订阅示例 首先,在本机开启第1个Redis客户端,执行如下命令订阅blog.redis频道: SU ...

  7. Redis的n种妙用,分布式锁,分布式唯一id,消息队列,抽奖……

    介绍 redis是键值对的数据库,常用的五种数据类型为字符串类型(string),散列类型(hash),列表类型(list),集合类型(set),有序集合类型(zset) Redis用作缓存,主要两个 ...

  8. NodeJS操作Redis实现消息的发布与订阅

    首先先说一下流程: 1.保存数据到Redis,然后将member值publish到 chat频道(publish.js功能) 2.readRedis.js文件此前一直在监听chat频道,readRed ...

  9. 八十五:redis之redis的事物、发布和订阅操作 (2019-11-18 22:54)

    redis事物可以一次执行多个命令,事物具有以下特征1.隔离操作:事物中的所有命令都会序列化.按顺序执行,不会被其他命令打扰2.原子操作:事物中的命令要么全部被执行,要么全部都不执行 开启一个事物,以 ...

随机推荐

  1. shell动态向sql传参

    一直在想有什么好方法可以实现,用shell动态给sql传参,自己写了一个简单,有什么好方法,欢迎留言补充,下面代码纯手打,可能有疏忽之处,请大佬批评指正指正. 实现方法如下: 1.新建一个文件02.t ...

  2. Python time gmtime()方法

    描述 Python time gmtime() 函数将一个时间戳转换为UTC时区(0时区)的struct_time,高佣联盟 www.cgewang.com 可选的参数sec表示从1970-1-1以来 ...

  3. PHP fscanf() 函数

    定义和用法 fscanf() 函数根据指定的格式对来自打开的文件的输入进行解析. 语法 fscanf(file,format,mixed) 参数 描述 file 必需.规定要检查的文件. format ...

  4. PHP fread() 函数

    定义和用法 fread() 函数读取打开的文件. 函数会在到达指定长度或读到文件末尾(EOF)时(以先到者为准),停止运行. 该函数返回读取的字符串,如果失败则返回 FALSE. 语法 string ...

  5. PHP preg_filter() 函数

    preg_filter 函数用于执行一个正则表达式搜索和替换.高佣联盟 www.cgewang.com 语法 mixed preg_filter ( mixed $pattern , mixed $r ...

  6. x86架构:分页机制和原理

    分页是现在CPU核心的管理内存方式,网上介绍材料很多,这里不赘述,简单介绍一下分页的背景和原理 1.先说说为什么要分段 实模式下程序之间不隔离,互相能直接读写对方内存,或跳转到其他进程的代码运行,导致 ...

  7. 区块链钱包开发 - USDT - 一、Omni本地钱包安装

    背景 Tether(USDT)中文又叫泰达币,是一种加密货币,是Tether公司推出的基于稳定价值货币美元(USD)的代币Tether USD,也是目前数字货币中最稳定的币,USDT目前发行了两种代币 ...

  8. C语言输出颜色

    命令后界面输出颜色 嵌入式终端界面输出日志时,为了区分输出的有用信息.错误信息,可以给不同级别的输出加上不同的颜色,以方便查看. 下面是颜色的定义: //颜色宏定义 #define NONE &quo ...

  9. gym102586 部分题解

    目录 Evacuation Sum Modulo Count Modulo 2 Robots Construct Points Amidakuji Yosupo's Algorithm link 出于 ...

  10. MySQL数据库——连接查询

    1.基本含义 连接就是指两个或2个以上的表(数据源)“连接起来成为一个数据源”. 实际上,两个表的完全的连接是这样的一个过程: 左边的表的每一行,跟右边的表的每一行,两两互相“横向对接”后所得到的所有 ...