引子
为什么写这篇文章呢? 因为. NET Core 的生态越来越好了! 之前玩转. net 的时候操作 Redis 相信大伙都使用过一些组件, 但都有一些缺点, 如 ServiceStack.Redis 是商业版, 免费版有限制; StackExchange.Redis 是免费版, 但是内核在 .NETCore 运行时经常有 Timeout 的问题, 暂无法解决; csredis 作者在 2014 年以后就没有更新了, 它不支持 .net core, 但是它的源码可读性很强非常干净, 几乎无任何依赖. 但是随着. NET Core 生态的越来越好, 又涌现了一批我们国人开发的支持. Net Core 的 Redis 组件, 供我们选择.
http://git.newlifex.com/NewLife/NewLife.Redis 他是 NewLife 团队开发的, 已经在 ZTO 大数据实时计算中广泛应用, 200 多个 Redis 实例稳定工作一年多, 每天处理近 1 亿包裹数据, 日均调用量 80 亿次.
CSRedis https://github.com/2881099/csredis (这里我更喜欢把它叫做 CSRedisCore)这是另一个国内大牛 nicye 开发的, 为人很低调, 所以了解他的人很少! 目前我项目中广泛使用的也是这个. 作者前不久刚做了一个几大 Redis 组件的性能测试. net core 2.0 Redis 驱动性能比拼 有兴趣的可以打开链接看一下.
注: 此 CSRedis(今天本文的主角 CSRedisCore) 非彼 CSRedis(.net 时代的组件, 很久没更新了, 不支持. net core)
NewLife.Redis 的使用方法在前两天的 Redis 基本使用及百亿数据量中的使用技巧分享 (附视频地址及观看指南) 文章中已经分享了! 文章也有视频教程. 所以今天的文章将介绍另一个玩转 Redis 的神器 - CSRedis 了!
基本使用
CSRedisCore 的使用很简单, 就需要实例化一个 CSRedisClient(集群连接池)对象然后初始化一下 RedisHelper 就可以了, 他的方法名与 Redis-cli 基本保持一致. 所以说你可以像使用 Redis-cli 命令一样来使用它. 作者最近也支持了 Pipeline 功能以及 MGet,MSet 等提高效率的功能! 话不多少下面我们将通过一个个实例来看下他的操作吧.
简单使用
获取 Nuget 包(目前版本 3.0.18)! 哈, 没错, 使用前要通过 Nuget 来安装下引用, 什么? 你不知道怎么使用 Nuget 包? 对不起, 右上角点下 "X" 关掉网页就可以了.
nuget Install-Package CSRedisCore
几种启动模式介绍:
普通模式:
var csredis = new CSRedis.CSRedisClient("127.0.0.1:6379,password=123,defaultDatabase=13,poolsize=50,ssl=false,writeBuffer=10240,prefix=key 前辍");
官方集群模式: 假设你已经配置好 Redis-trib 集群, 定义一个[普通模式] 的 CSRedisClient 对象, 它会根据 Redis-server 返回的 MOVED | ASK 错误记录 slot, 自动增加节点 Nodes 属性.
127.0.0.1:6379,password=123,defaultDatabase=0,poolsize=50,ssl=false,writeBuffer=10240,prefix=
其他节点在运行过程中自动增加, 确保每个节点密码一致.
警告: 本模式与[分区模式] 同时使用时, 切记不可设置 "prefix=key 前辍"(或者全部设置成一样), 否则会导致 keySlot 计算结果与服务端不匹配, 无法记录 slotCache.
注意: 官方集群不支持多 keys 的命令,[管道] ,Eval(脚本)等众多杀手级功能.
分区模式: 本功能实现多个服务节点分担存储(作者自己实现的一种方式), 与官方的分区, 集群, 高可用方案不同.
例如: 缓存数据达到 500G, 如果使用一台 Redis-server 服务器光靠内存存储将非常吃力, 使用硬盘又影响性能.
可以使用此功能自动管理 N 台 Redis-server 服务器分担存储, 每台服务器只需约 (500/N)G 内存, 且每台服务器匀可以配置官方高可用架构.
- var csredis = new CSRedis.CSRedisClient(null,
- "127.0.0.1:6371,password=123,defaultDatabase=11,poolsize=10,ssl=false,writeBuffer=10240,prefix=key 前辍",
- "127.0.0.1:6372,password=123,defaultDatabase=12,poolsize=11,ssl=false,writeBuffer=10240,prefix=key 前辍",
- "127.0.0.1:6373,password=123,defaultDatabase=13,poolsize=12,ssl=false,writeBuffer=10240,prefix=key 前辍",
- "127.0.0.1:6374,password=123,defaultDatabase=14,poolsize=13,ssl=false,writeBuffer=10240,prefix=key 前辍");
- // 实现思路: 根据 key.GetHashCode() % 节点总数量, 确定连向的节点
- // 也可以自定义规则(第一个参数设置)
今天我只给大家演示怎么来进行使用, 所以采用了普通模式, 代码如下所示:
- static void Main(string[] args)
- {
- // 普通模式
- var csredis = new CSRedis.CSRedisClient("127.0.0.1:6379,password=123,defaultDatabase=1,poolsize=50,ssl=false,writeBuffer=10240");
- // 初始化 RedisHelper
- RedisHelper.Initialization(csredis);
- //Install-Package Caching.CSRedis (本篇不需要)
- // 注册 mvc 分布式缓存
- //services.AddSingleton<IDistributedCache>(new Microsoft.Extensions.Caching.Redis.CSRedisCache(RedisHelper.Instance));
- Test();
- Console.ReadKey();
- }
- static void Test()
- {
- RedisHelper.Set("name", "祝雷");// 设置值. 默认永不过期
- //RedisHelper.SetAsync("name", "祝雷");// 异步操作
- Console.WriteLine(RedisHelper.Get<String>("name"));
- RedisHelper.Set("time", DateTime.Now, 1);
- Console.WriteLine(RedisHelper.Get<DateTime>("time"));
- Thread.Sleep(1100);
- Console.WriteLine(RedisHelper.Get<DateTime>("time"));
- // 列表
- RedisHelper.RPush("list", "第一个元素");
- RedisHelper.RPush("list", "第二个元素");
- RedisHelper.LInsertBefore("list", "第二个元素", "我是新插入的第二个元素!");
- Console.WriteLine($"list 的长度为{RedisHelper.LLen("list")}");
- //Console.WriteLine($"list 的长度为{RedisHelper.LLenAsync("list")}");// 异步
- Console.WriteLine($"list 的第二个元素为{RedisHelper.LIndex("list",1)}");
- //Console.WriteLine($"list 的第二个元素为{RedisHelper.LIndexAsync("list",1)}");// 异步
- // 哈希
- RedisHelper.HSet("person","name", "zhulei");
- RedisHelper.HSet("person", "sex", "男");
- RedisHelper.HSet("person", "age", "28");
- RedisHelper.HSet("person", "adress", "hefei");
- Console.WriteLine($"person 这个哈希中的 age 为{RedisHelper.HGet<int>("person","age")}");
- //Console.WriteLine($"person 这个哈希中的 age 为{RedisHelper.HGetAsync<int>("person","age")}");// 异步
- // 集合
- RedisHelper.SAdd("students","zhangsan", "lisi");
- RedisHelper.SAdd("students", "wangwu");
- RedisHelper.SAdd("students", "zhaoliu");
- Console.WriteLine($"students 这个集合的大小为{RedisHelper.SCard("students")}");
- Console.WriteLine($"students 这个集合是否包含 wagnwu:{RedisHelper.SIsMember("students","wangwu")}");
- }
通过上面的代码大家可以看到对于 Redis 的操作都是使用 RedisHelper 这个类来实现的. 而且, 对 Redis 的所有操作名称都跟 Redis-Cli 命令高度一致! 这样就会方便很多! 同时对所有的方法在实现上都有同步异步的操作! 这里建议进行 Redis 操作的话都尽量使用同步操作. 原因在上篇也进行了介绍! 这里就不再次进行介绍了!.
执行的结果如下所示:
大 #家可以摘录代码然后拷贝到一个新的控制台程序中运行即可!
高级使用
上面给大家介绍了一些通用的使用方法, 接下来呢我们进行一些高级方法的使用. 包括订阅 / 发布, PipeLine, 缓存壳等等.
订阅与发布
- // 普通订阅
- RedisHelper.Subscribe(
- ("chan1", msg => Console.WriteLine(msg.Body)),
- ("chan2", msg => Console.WriteLine(msg.Body)));
- // 模式订阅(通配符)
- RedisHelper.PSubscribe(new[] { "test*", "*test001", "test*002" }, msg => {
- Console.WriteLine($"PSUB {msg.MessageId}:{msg.Body} {msg.Pattern}: chan:{msg.Channel}");
- });
- // 模式订阅已经解决的难题:
- //1, 分区的节点匹配规则, 导致通配符最大可能匹配全部节点, 所以全部节点都要订阅
- //2, 本组 "test*", "*test001", "test*002" 订阅全部节点时, 需要解决同一条消息不可执行多次
- // 发布
- RedisHelper.Publish("chan1", "123123123");
- // 无论是分区或普通模式, RedisHelper.Publish 都可以正常通信
- // 不加缓存的时候, 要从数据库查询
- var t1 = Test.Select.WhereId(1).ToOne();
- // 一般的缓存代码, 如不封装还挺繁琐的
- var cacheValue = RedisHelper.Get("test1");
- if (!string.IsNullOrEmpty(cacheValue)) {
- try {
- return JsonConvert.DeserializeObject(cacheValue);
- } catch {
- // 出错时删除 key
- RedisHelper.Remove("test1");
- throw;
- }
- }
- var t1 = Test.Select.WhereId(1).ToOne();
- RedisHelper.Set("test1", JsonConvert.SerializeObject(t1), 10); // 缓存 10 秒
- // 使用缓存壳效果同上, 以下示例使用 string 和 hash 缓存数据
- var t1 = RedisHelper.CacheShell("test1", 10, () => Test.Select.WhereId(1).ToOne());
- var t2 = RedisHelper.CacheShell("test", "1", 10, () => Test.Select.WhereId(1).ToOne());
- var t3 = RedisHelper.CacheShell("test", new [] { "1", "2" }, 10, notCacheFields => new [] {
- ("1", Test.Select.WhereId(1).ToOne()),
- ("2", Test.Select.WhereId(2).ToOne())
- });
Pipeline 及 MGet,MSet
使用管道模式, 打包多条命令一起执行, 从而提高性能.
- var ret1 = RedisHelper.StartPipe().Set("a", "1").Get("a").EndPipe();
- var ret2 = RedisHelper.StartPipe(p => p.Set("a", "1").Get("a"));
- var ret3 = RedisHelper.StartPipe().Get("b").Get("a").Get("a").EndPipe();
- // 与 RedisHelper.MGet("b", "a", "a") 性能相比, 经测试差之毫厘
压力测试对比
到这里你可能要问了, CSRedisCore 性能如何呢? 跟其他的 Redis 组件相比又如何呢, 这里给出一个链接. net core 2.0 Redis 驱动性能比拼?.net core 2.0 Redis 驱动性能比拼, 上面有作者做的测试, 大伙可以看下, 我也做个截图分享
来源: https://www.cnblogs.com/yilezhu/p/9947905.html