.NET redis 客户端开源组件 FreeRedis (继 CSRedisCore 之后重写)

nicye 2020-11-08 19:06:03
redis 开源 组件 客户端 客户


什么是 FreeRedis

FreeRedis 是一款 .NET redis 客户端开源组件,以 MIT 协议开源托管于 github,目前支持 .NET 5、.NETCore 2.1+、.NETFramework 4.0+、Xamarin,有可能已经支持 AOT 编译(目前未测试,但会往这个方向走)。

FreeRedis 会严格按照 FreeSql 的开源方式,做好单元测试,兼容平台,简单易用,有问必答,有求必应的态度,为中国 .NET 开源事业做一点点贡献。

感谢大家的支持,项目还未公开就已经获得 66 星。目前项目仍在起步阶段,欢迎小伙伴参与进来,贡献测试、或代码、或建议都可以。

项目当前的状态:

  • 版本 0.0.8(目前不建议使用在生产环境)
  • 单元测试 268 个
  • 支持 集群、哨兵、主从(已通过测试)
  • 支持 连接池
  • 支持 .NET5/.NETCore 2.1+/.NET4.0+
  • 支持 Redis6.0 所有类型
  • 支持 Redis6.0 RESP3 协议
  • API 仍然与 redis-cli 命令保持一致
  • 采用最宽松的开源协议 MIT https://github.com/2881099/FreeRedis

项目由来

说来话长,2016 年之前本人写了一年多 nodejs 服务端应用,使用过 node-redis 组件,真心好用。在此期间有同事不停安利 .NET 可以跨平台了,劝我快回来搞 .NET,开始我是抗拒做螃蟹第一人的,不知道是哪天下午闲着蛋疼去体验了一把 .NETCore 1.0-previewXX(不记得哪个版本了)。试了一把被吸引住了,体验感受和 expressjs 像极了,再也看不见以往 webform/mvc 的缺点。

于是我准备入坑了,入坑第一件事除了 hello world,还需要做相关调研:

  • 性能OK
  • 设计OK
  • 发展OK(暂时的定级)
  • 相关组件OK(HttpClient、Redis、Ado.NET、等等基础组件)

初始调研完成之后,接下下就要抽时间选型框架了,最终从众多框架中选择了合适团队的一款:https://github.com/simplcommerce/SimplCommerce ,在这个项目原有基础之上,结合企业规范要求定制改造,大约两个月时间完成了可生产的状态。(框架不求开始尽善尽美,只求使用中不断打磨,最终走向完美)

理想丰满现实骨干,接下来的故事就是遇到生产故障了,StackExchange.Redis、HttpClient 关于这两个组件的问题,以前讲过现在就不说了(万万没想到这么大的组件使用都能出现问题)。吃螃蟹就会掉坑,掉了坑就要想办法解决,最终与 csredis 组件结缘。

以当时的情形纵观 .NET 所有 redis 客户端组件,只有 csredis 源码最易改造支持 .NETCore(水平有限见谅),csredis 2014 年停止更新,本人于 2016 年将其改造支持 .NETCore 为主,以及增加连接池管理、集群、哨兵、redis2.8 以上的命令,在公司项目生产环境使用一年半载之后开源。

CSRedisCore 开源这到久,nuget 下载量达到 60W,收集需求若干,bug 若干(有解决了的、也有未能重现的),基于我已经对 redis 这块很熟悉,然后 redis 5.0/6.0 又新增了蛮多特性,重新写一款 bug 更少、可维护性更好的想法产生了。

经过几个月的墨迹终于走通可用了,项目最终命名:FreeRedis


如何使用

Single machine redis (单机)

public static RedisClient cli = new RedisClient("127.0.0.1:6379,password=123,defaultDatabase=13");
//cli.Serialize = obj => JsonConvert.SerializeObject(obj);
//cli.Deserialize = (json, type) => JsonConvert.DeserializeObject(json, type);
cli.Notice += (s, e) => Console.WriteLine(e.Log); //print command log
cli.Set("key1", "value1");
cli.MSet("key1", "value1", "key2", "value2");
string value1 = cli.Get("key1");
string[] vals = cli.MGet("key1", "key2");

API 仍然与 redis-cli 命令保持一致,所以如果想了解 FreeRedis 每个方法怎么使用,去百度搜索 “redis 命令”,有很多很多很多资料。don't say so much!!!

支持 Redis6.0 支持的所有数据类型:strings, hashes, lists, sets, sorted sets, bitmaps, hyperloglogs, geo, streams And BloomFilter.

Parameter Default Explain
protocol RESP2 If you use RESP3, you need redis 6.0 environment
user <empty> Redis server username, requires redis-server 6.0
password <empty> Redis server password
defaultDatabase 0 Redis server database
max poolsize 100 Connection max pool size
min poolsize 5 Connection min pool size
idleTimeout 20000 Idle time of elements in the connection pool (MS)
connectTimeout 10000 Connection timeout (MS)
receiveTimeout 10000 Receive timeout (MS)
sendTimeout 10000 Send timeout (MS)
encoding utf-8 string charset
ssl false Enable encrypted transmission
name <empty> Connection name, use client list command to view

如果需要连接 IPv6,连接串请使用: [fe80::b164:55b3:4b4f:7ce6%15]:6379


Master-Slave (读写分离)

public static RedisClient cli = new RedisClient(
"127.0.0.1:6379,password=123,defaultDatabase=13",
"127.0.0.1:6380,password=123,defaultDatabase=13",
"127.0.0.1:6381,password=123,defaultDatabase=13"
);
var value = cli.Get("key1");

这样创建的 cli,所有写入命令都会连接 127.0.0.1:6379 执行,所有读取命令只会随机连接 127.0.0.1:6380 或 127.0.0.1:6381 执行。(内部已经为每个命令做好了读写标记)

Redis Sentinel (哨兵高可用)

public static RedisClient cli = new RedisClient(
"mymaster,password=123",
new [] { "192.169.1.10:26379", "192.169.1.11:26379", "192.169.1.12:26379" },
true //是否读写分离
);

哨兵是一个分布式系统,为 Redis 提供高可用性解决方案,当主机 master 宕机之后,会马上出现一个新的 master 可使用,确保服务的正常运作。

哨兵模式还可以设置读写分离,缓解 master 频繁读取数据的压力,缺点:有可能读到的数据不是最新,因为 redis 从 master 同步到 slave 有延时。

Redis Cluster (集群)

假如你有一个 Redis Cluster 集群,其中有三个主节点(7001-7003)、三个从节点(7004-7006),则连接此集群的代码:

public static RedisClient cli = new RedisClient(
new ConnectionStringBuilder[] { "192.168.0.2:7001", "192.168.0.2:7001", "192.168.0.2:7003" }
);

Subscribe (订阅)

using (cli.Subscribe("abc", ondata)) //wait .Dispose()
{
Console.ReadKey();
}
void ondata(string channel, string data) =>
Console.WriteLine($"{channel} -> {data}");

Scripting (脚本)

var r1 = cli.Eval("return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}",
new[] { "key1", "key2" }, "first", "second") as object[];
var r2 = cli.Eval("return {1,2,{3,'Hello World!'}}") as object[];
cli.Eval("return redis.call('set',KEYS[1],'bar')",
new[] { Guid.NewGuid().ToString() })

Pipeline (管道)

using (var pipe = cli.StartPipe())
{
pipe.IncrBy("key1", 10);
pipe.Set("key2", Null);
pipe.Get("key1");
object[] ret = pipe.EndPipe();
Console.WriteLine(ret[0] + ", " + ret[2]);
}
// or Async Callback
using (var pipe = cli.StartPipe())
{
var tasks = new List<Task>();
long t0 = 0;
task.Add(pipe.IncrByAsync("key1", 10).ContinueWith(t => t0 = t.Result)); //callback
pipe.SetAsync("key2", Null);
string t2 = null;
task.Add(pipe.GetAsync("key1").ContinueWith(t => t2 = t.Result)); //callback
pipe.EndPipe();
Task.WaitAll(tasks.ToArray()); //wait all callback
Console.WriteLine(t0 + ", " + t2);
}

Transaction (事务)

using (var tran = cli.Multi())
{
tran.IncrBy("key1", 10);
tran.Set("key2", Null);
tran.Get("key1");
object[] ret = tran.Exec();
Console.WriteLine(ret[0] + ", " + ret[2]);
}
// or Async Callback
using (var tran = cli.Multi())
{
var tasks = new List<Task>();
long t0 = 0;
task.Add(tran.IncrByAsync("key1", 10).ContinueWith(t => t0 = t.Result)); //callback
tran.SetAsync("key2", Null);
string t2 = null;
task.Add(tran.GetAsync("key1").ContinueWith(t => t2 = t.Result)); //callback
tran.Exec();
Task.WaitAll(tasks.ToArray()); //wait all callback
Console.WriteLine(t0 + ", " + t2);
}

GetDatabase (切库)

using (var db = cli.GetDatabase(10))
{
db.Set("key1", 10);
var val1 = db.Get("key1");
}

结束语

目前项目仍在起步阶段,欢迎小伙伴参与进来,贡献测试、或代码、或建议都可以。

FreeRedis 使用最宽松的开源协议 MIT https://github.com/2881099/FreeRedis

如果你有好的 redis 实现想法,欢迎给作者留言讨论,谢谢观看!

版权声明
本文为[nicye]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/kellynic/p/13943313.html

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云