.Net 开源项目 FreeRedis 实现思路之 - Redis 6.0 客户端缓存技术
1|0写在开头
FreeRedis 是一款继 CSRedisCore 之后重写的 .NET redis 客户端开源组件,以 MIT 协议开源托管于 github,目前支持 .NET 5、.NETCore 2.1+、.NETFramework 4.0+、Xamarin,有可能已经支持 AOT 编译(目前未测试,但会往这个方向走)。
- 🌈 所有方法名与 redis-cli 保持一致
- 🌌 支持 Redis 集群(服务端要求 3.2 及以上版本)
- ⛳ 支持 Redis 哨兵模式
- 🎣 支持主从分离(Master-Slave)
- 📡 支持发布订阅(Pub-Sub)
- 📃 支持 Redis Lua 脚本
- 💻 支持管道(Pipeline)
- 📰 支持事务
- 🌴 支持 GEO 命令(服务端要求 3.2 及以上版本)
- 🌲 支持 STREAM 类型命令(服务端要求 5.0 及以上版本)
- ⚡ 支持本地缓存(Client-side-cahing,服务端要求 6.0 及以上版本)
- 🌳 支持 Redis 6 的 RESP3 协议
github: https://github.com/2881099/FreeRedis
2|0了解 Redis
Redis是一个开源的使用C语言编写、开源、支持网络、可基于内存亦可持久化的日志型、高性能的Key-Value数据库,并提供多种语言的API。它通常被称为 数据结构服务器 ,因为值(value)可以是 字符串(string)、哈希(map)、 列表(list)、集合(sets)、有序集合(sorted sets)、地理位置(Geo)、消息列队(Streams)等类型。
与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
优势:
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets, Ordered Sets, Geo, Streams 数据类型操作。
- 原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
3|0本文看点
Redis 6.0 是一个可期的版本,增加了 RESP3.0 协议,ACL 权限控制,从原有的单线程改为多线程(性能提升2-3倍)等诸多更新。今天向大家介绍他的另一个重要特性:客户端缓存技术,讲解如何落设计在 .NET 中。
为什么需要客户端缓存?
我们都知道,使用 Redis 进行数据的缓存的主要目的是减少对 MySQL 等数据库的访问,提供更快的访问速度,毕竟 《Redis in Action》中提到的, Redis 的性能大致是普通关系型数据库的 10 ~ 100 倍。
所以,如下图所示,Redis 用来存储热点数据,Redis 未命中,再去访问数据库,这样可以应付大多数情况下的性能要求。
但是,Redis 也有其性能上限,并且访问 Redis 必然有一定的网络 I/O 以及序列化反序列化损耗。所以,往往会引入进程缓存,将最热的数据存储在本地,进一步加快访问速度。
如上图所示,Guava Cache 等进程缓存作为一级缓存,Redis 作为二级缓存:
- 先去 Guava Cache 中查询数据,如果命中则直接返回。
- Guava Cache 中未命中,则再去 Redis 中查询,如果命中则返回数据,并在 Guava Cache 中设置此数据。
- Redis 也未命中的话,只有去 MySQL 中查询,然后依次将数据设置到 Redis 和 Guava Cache 中。
只使用 Redis 分布式缓存时,遇到数据更新时,应用程序更新完 MySQL 中的数据,可以直接将 Redis 中对应缓存失效掉,保持数据的一致性。
而进程内缓存的数据一致性比分布式的缓存面临更大的挑战。数据更新的时候,如何通知其他进程也更新自己的缓存呢?
如果按照分布式缓存的思路,我们可以设置极短的缓存失效时间,这样不必实现复杂的通知机制。
但是不同进程内的数据依然会面临不一致的问题,并且不同进程缓存失效时间不统一,同一个请求到了不同的进程,可能出现反复幻读的情况。
4|0落地分析
如上当 key 失效的时候,Redis 6.0 提供了三种模式通知客户端,普通模式、广播模式、转发模式。
1、普通模式
普通模式依赖 RESP3.0 协议,需要在连接成功时使用 hello 命令开启 RESP3.0 模式。
hello 3
client tracking on
落地在 .NET 之中时,我们必然是使用连接池技术,那么每个连接都必须使用以上的两个命令,此时每个连接是一个循环读的操作,如下:
本来我们可以比较简单的这样执行命令:
可以看出来,两段代码同时读,会导致读取的结果错乱。如何解决还需要三思,而我们 PASS 了这种模式。
2、广播模式
广播模式和普通模式差不多,都需要依赖 RESP3.0 协议。这种方式下 Redis 服务端不再消耗过多内存存储信息,而是发送更多的失效消息给客户端。
与普通模式必须获取一次键的规则不同,广播模式下,只要键被修改或删除,符合规则的客户端都会收到失效消息,而且是可以多次获取的
与普通模式相比,虽然少存储了一些数据,但是由于需要对前缀规则进行匹配,会消耗一定的 CPU 资源,所以注意别使用过长的前缀。
广播模式和普通模式一样,需要解决命令同时读取的问题(请见上面的两段代码)。
3、转发模式
Redis 为了兼容 RESP2 协议提供了转发(Redirect)模式,不再使用 RESP3 原生支持 PUSH 消息,而是将消息通过 Pub/Sub 通知给另外一个客户端,具体流程如下图所示。
MemoryCacheAop 是 FreeRedis 已经实现好的拦截器,主要实现拦截命令执行,获取本地内存。完整代码:https://github.com/2881099/FreeRedis/blob/master/src/FreeRedis/ClientSideCaching.cs
5|0测试功能
cli.Notice 事件在控制台输出内容:
Not connected 代表没有经过 redis-server
6|0写在最后
FreeRedis 是一款继 CSRedisCore 之后重写的 .NET redis 客户端开源组件,以 MIT 协议开源托管于 github,目前支持 .NET 5、.NETCore 2.1+、.NETFramework 4.0+、Xamarin,有可能已经支持 AOT 编译(目前未测试,但会往这个方向走)。
github: https://github.com/2881099/FreeRedis
谢谢支持!!
__EOF__

本文链接:https://www.cnblogs.com/kellynic/p/14009158.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?