CachingFramework.Redis
.NET REDIS客户库库基于stackexchange.redis添加了一些有趣的功能,例如可扩展的序列化策略,对组键,哈希字段和集合成员的标记机制,以及支持原子添加/获得操作的提取机制,所有这些机制都是集群兼容的。
特征
- .NET框架和.NET核心支持
- 键入缓存:任何可序列化对象都可以用作缓存值。
- 提取机制:用于原子添加/获取操作的快捷缓存方法(缓存模式)。
- 标记机制:可以标记缓存项目,允许通过标签检索或无效键或成员。
- 时间的时间机制:每个键都可以与定义其对生命时间的值相关联。
- 词典分类的集合:用于快速弦匹配和自动完整建议。
- Pub/sub Support :发布强烈键入消息的发布订阅实现。
- 地理空间索引:半径查询支持。
- HyperLoglog支持:计算独特的事物。
- 可配置的序列化:默认情况下的压缩二进制序列化器,或提供您自己的序列化。
- REDIS数据类型为.NET集合:列表,设置,排序集,哈希和位图支持作为托管集合。
- REDIS KEYPACE通知:订阅酒吧/子通道以接收影响REDIS数据集的事件。
- 与redis群集完全兼容:所有命令均为群集安全。
用法
nuget
要安装软件包在软件包管理器控制台上运行以下命令:
PM> Install-Package CachingFramework.Redis
语境
Rediscontext类提供的所有功能分为五个类别,每个功能都作为具有以下名称的属性公开:
- 缓存
- 收藏
- 地理空间
- Pubsub
- 关键因素
默认配置
连接到Local主机端口6379上的Redis:
var context = new RedisContext ( ) ; 自定义连接配置
var context = new RedisContext ( "10.0.0.1:7000, 10.0.0.2:7000, connectRetry=10, abortConnect=false, allowAdmin=true" ) ;构造函数参数必须是有效的stackexchange.redis连接字符串。检查此信息有关STACKEXCHANGE.REDIS配置选项的更多信息。
自定义数据库选项
var context = new RedisContext ( "localhost:6379" , new DatabaseOptions
{
KeyPrefix = "Cache:" ,
DbIndex = 2
} ) ;DatabaseOptions参数允许配置全局密钥前缀和数据库索引,以在上下文中使用
自定义多路复用器
您可以使用适当的构造函数过载来注入自己的多路复用器:
public class PooledConnectionMultiplexer : IConnectionMultiplexer
{
// ...
}
var myMultiplexer = new PooledConnectionMultiplexer ( Common . Config ) ;
var context = new RedisContext ( myMultiplexer ) ;重要说明:
重新介绍对象应在呼叫者之间共享和重复使用。不建议每次操作创建重质膜下文。请检查stackexchange.redis文档以获取更多信息。
序列化
提供了不同的序列化机制:
| 序列化器 | 数据 | 配置 |
|---|---|---|
| 二进制序列化器 | 所有类型均使用.NET二进制形式和GZIP压缩序列化。 | .NET框架的默认值 |
| jsonserializer | 使用System.Text.json将数据存储为JSON。可以使用jsonserialialoptions配置序列化。 | .NET Core的默认值 |
| RawSerializer | 简单类型被序列化为UTF-8字符串。任何其他类型都使用默认序列化器序列化。 | 可以使用setSerializerfor()每个类型进行序列化设置 |
| newtonsoftjsonserializer | 使用newtonsoft.json将数据存储为JSON。可以使用jsonserializersettings配置序列化。 | nuget软件包CachingFramework.Redis .newtonsoftjson |
| msgpackserializer | 数据通过msgpack.cli存储为MessagePack。 | nuget软件包CachingFramework.Redis .msgpack |
Rediscontext类具有构造函数过载以提供序列化机制,例如:
var context = new RedisContext ( "localhost:6379" , new JsonSerializer ( ) ) ; 默认序列化方法
您可以通过设置静态属性RedisContext.DefaultSerializer来更改默认序列化机制。在没有明确序列化器的情况下创建Rediscontext时,使用此默认值。
当然,您必须在创建任何上下文之前执行此操作,例如在您的应用程序启动中:
RedisContext . DefaultSerializer = new JsonSerializer ( ) ;注意:如果您没有明确设置序列化器,则将取决于框架:.NET Framework版本将默认为tinarySerializer和.NET Core至JsonSerialializer。
如果您计划从不同的框架版本中消费数据,请确保所有这些都使用相同的序列化方法。
自定义序列化
要提供自定义序列化机制,请实现Iserializer界面(或从SerializerBase类中继承)。
例如:
public class MySerializer : SerializerBase
{
public override RedisValue Serialize < T > ( T value )
{
return value . ToString ( ) ;
}
public override T Deserialize < T > ( RedisValue value )
{
return ( T ) Convert . ChangeType ( value . ToString ( ) , typeof ( T ) ) ;
}
} 原始序列化器
RawSerializer允许使用方法setSerializerfor
例如,允许将StringBuilder序列化为UTF-8编码字符串:
// On your startup logic:
RedisContext . DefaultSerializer = new RawSerializer ( )
. SetSerializerFor < StringBuilder >
(
sb => Encoding . UTF8 . GetBytes ( sb . ToString ( ) ) ,
b => new StringBuilder ( Encoding . UTF8 . GetString ( b ) )
) ;打字缓存
任何原始类型或可序列化类都可以用作缓存值。
例如:
[ Serializable ]
public class User
{
public int Id { get ; set ; }
public string UserName { get ; set ; } .. .
}注意:默认序列化方法二进制序列化器需要序列化属性。例如,如果使用JSON Serializer ,则此属性将不必要。有关更多信息,请参见序列化部分。
在缓存中添加一个对象:
string redisKey = "user:1" ;
User value = new User ( ) { Id = 1 } ; // any serializable object
context . Cache . SetObject ( redisKey , value ) ;用TTL添加一个对象
将一个对象添加到缓存中,并以1天的持续时间:
context . Cache . SetObject ( redisKey , value , TimeSpan . FromDays ( 1 ) ) ;获取一个对象
User user = context . Cache . GetObject < User > ( redisKey ) ;卸下钥匙
context . Cache . Remove ( redisKey ) ;提取机制
为原子添加/获取操作提供了快捷方式(请参阅缓存模式)。
获取对象
尝试从缓存中获取一个对象,如果不存在该对象,将其插入到缓存中:
var user = context . Cache . FetchObject < User > ( redisKey , ( ) => GetUserFromDatabase ( id ) ) ;仅当缓存上不存在该值时,方法getUserFromDatabase才会被调用,在这种情况下,将在返回该值之前将其添加到缓存中。
用时间延长的对象获取对象:
var user = context . Cache . FetchObject < User > ( redisKey , ( ) => GetUserFromDatabase ( id ) , TimeSpan . FromDays ( 1 ) ) ;仅当缓存上不存在该值时,才设置TTL值。
哈希
哈希是由与.NET词典这样的值相关的字段组成的图。
设置哈希对象
在用字段键(子键)索引的redis键上设置对象:
void InsertUser ( User user )
{
var redisKey = "users:hash" ;
var fieldKey = "user:id:" + user . Id ;
context . Cache . SetHashed ( redisKey , fieldKey , user ) ;
} 获取哈希对象
通过redis密钥和字段键获取对象:
User u = context . Cache . GetHashed < User > ( "users:hash" , "user:id:1" ) ; 在哈希中获取所有对象
IDictionary < string , User > users = context . Cache . GetHashedAll < User > ( "users:hash" ) ;哈希中的对象可能具有不同的类型。
按模式扫描字段
通过将球形模式与字段名称匹配,可以逐渐迭代哈希成员。
例如,要迭代字段名称以“用户:”开头的哈希的成员。
var scan = context . Cache . ScanHashed < User > ( "users:hash" , "user:*" ) ;
foreach ( var item in scan )
{
string key = item . Key ;
User value = item . Value ;
// ...
} 从哈希中删除对象
context . Cache . RemoveHashed ( "users:hash" , "user:id:1" ) ; 获取哈希对象
var user = context . Cache . FetchHashed < User > ( "users:hash" , "user:id:1" , ( ) => GetUser ( 1 ) ) ;只有在哈希上不存在该值时,方法getuser才会被调用,在这种情况下,将在返回之前将其添加到哈希。
哈希作为.NET词典
可以通过在rediscontext.collections上使用getredisdixtionary方法来将哈希作为.NET字典处理:例如:
var dict = context . Collections . GetRedisDictionary < string , User > ( "users:hash" ) ;
dict . Add ( "user:id:1" , user ) ;有关收集的更多信息,请参阅Collections.md。
标记机制
群集兼容标记机制,其中标签用于分组密钥,哈希字段,集合成员,排序的集合成员和地理空间成员,因此可以同时检索或无效。标签可以与任意数量的密钥,哈希字段或设置成员有关。
标记存储
每个标签都存储在一个redis集中,其值是标签引用的键。这些专门的REDIS组以自定义内部格式存储在钥匙中。默认情况下,名为红色的标签的密钥格式为:$ _ tag _ $:red
可以使用serializer中的属性tagprefix和tagpostfix自定义标签的内部密钥格式。
例如:
RedisContext . DefaultSerializer . TagPrefix = "{tag:" ;
RedisContext . DefaultSerializer . TagPostfix = "}" ;因此,标签红色的内部密钥将为{tag:red}
添加与标签有关的单个对象
将一个对象添加到缓存中,并将其与标签红色和蓝色相关联:
context . Cache . SetObject ( "user:1" , user , new [ ] { "red" , "blue" } ) ; 添加与标签有关的哈希对象
标签可以指向哈希的字段。
context . Cache . SetHashed ( "users:hash" , "user:id:1" , value , new [ ] { "red" } ) ; 将成员添加到与标签相关的REDIS集中:
将一个成员添加到REDIS集合中,并将成员与标签红色相关联:
context . Cache . AddToSet ( "users:set" , value , new [ ] { "red" } ) ; 将成员添加到与标签相关的redis排序集中:
将一个成员添加到Redis排序集中,并将成员与标签蓝色相关联:
context . Cache . AddToSortedSet ( "users:sortedset" , 100.00 , value , new [ ] { "blue" } ) ; 将现有键与标签联系起来
将钥匙与绿色标签相关联:
context . Cache . AddTagsToKey ( "user:1" , new [ ] { "green" } ) ; 将现有哈希字段与标签联系起来
将哈希字段与绿色标签相关联:
context . Cache . AddTagsToHashField ( "users:hash" , "user:id:1" , new [ ] { "green" } ) ; 将重新设置的现有成员与标签联系起来
将集合成员与蓝色标签相关联:
context . Cache . AddTagsToSetMember ( "users:set" , "user:id:1" , new [ ] { "blue" } ) ;可以使用相同的方法将标签与排序的集合成员和地理空间索引成员相关联。
从钥匙中删除标签
删除钥匙和标签绿色之间的关系:
context . Cache . RemoveTagsFromKey ( "user:1" , new [ ] { "green" } ) ; 从哈希字段中删除标签
删除哈希字段和标签绿色之间的关系:
context . Cache . RemoveTagsFromHashField ( "users:hash" , "user:id:1" , new [ ] { "green" } ) ; 从Redis组中删除标签
删除设置成员和标签绿色之间的关系:
context . Cache . RemoveTagsFromSetMember ( "users:set" , "user:id:1" , new [ ] { "green" } ) ;可以使用相同的方法从排序的集合成员和地理空间索引成员中删除标签。
通过标签获取对象
获取与红色和/或绿色有关的所有对象:
IEnumerable < User > users = context . Cache . GetObjectsByTag < User > ( "red" , "green" ) ;这假设与标签相关的所有键均为相同的类型。
确定成员是否被标记
确定在给定标签上是否包含redis字符串密钥:
bool x = context . Cache . IsStringKeyInTag ( "key" , "blue" ) ;确定在给定标签上是否包含redis哈希字段:
bool x = context . Cache . IsHashFieldInTag ( "users:hash" , "user:id:1" , "blue" ) ;确定在给定标签上是否包含REDIS集成员:
bool x = context . Cache . IsSetMemberInTag ( "users:set" , user , "red" ) ; 通过标签使钥匙无效
删除与蓝色和/或绿色标签相关的所有键,哈希字段,集合成员和排序的集合成员:
context . Cache . InvalidateKeysByTag ( "blue" , "green" ) ; 让成员进入标签
获取与特定标签有关的所有成员(密钥,哈希字段和集合成员):
IEnumerable < TagMember > members = context . Cache . GetMembersByTag ( "blue" ) ;
foreach ( TagMember member in members )
{
var key = member . Key ;
var type = member . MemberType ;
var user = member . GetMemberAs < User > ( ) ;
} TagMember在其密钥属性上包含REDIS密钥,成员类型上包含MemberType属性上的成员类型。如果成员类型不是redis字符串,则可以通过调用getMemberas
会员类型是StringKey,Hashfield,SetMember或SortedSetMember之一。
通过标签获取钥匙
获取与给定标签相关的所有键,哈希字段和集合成员:
ISet < string > keys = context . Cache . GetKeysByTag ( new [ ] { "green" } ) ;如果标签与哈希字段相关,则返回的字符串将为:
{hashkey}:$ _-> _ $:{field}
如果标签与集合,排序集或地理空间索引相关,则返回的字符串将为:
{setKey}:$ _- s> _ $:{成员}
例如:
用户:哈希:$ _-> _ $:user:id:1表示字段用户:ID:1个哈希用户:哈希。
用户:设置:$ _- S> _ $:用户:ID:2表示成员用户:ID:SET用户:SET。
酒吧/子API
提供了强大的发布/订阅机制。
订阅频道
在频道用户上聆听类型用户的消息:
context . PubSub . Subscribe < User > ( "users" , user => Console . WriteLine ( user . Id ) ) ; 发布到频道
向频道用户发布类型用户的消息:
context . PubSub . Publish < User > ( "users" , new User ( ) { Id = 1 } ) ; 退订频道
context . PubSub . Unsubscribe ( "users" ) ;图案匹配订阅
REDIS PUB/SUB支持模式匹配,客户可以在其中订阅Glob Style模式,以接收发送给频道名称的所有匹配给定模式的消息。
使用频道模式订阅
context . PubSub . Subscribe < User > ( "users.*" , user => Console . WriteLine ( user . Id ) ) ;这将收听任何名称以“用户”开头的频道。
使用频道模式取消订阅
context . PubSub . Unsubscribe ( "users.*" ) ; 示例 - 幼稚的4线聊天应用程序
static void Main ( )
{
var context = new RedisContext ( "10.0.0.1:7000" ) ;
context . PubSub . Subscribe < string > ( "chat" , m => Console . WriteLine ( m ) ) ;
while ( true )
{
context . PubSub . Publish ( "chat" , Console . ReadLine ( ) ) ;
}
}地理空间API
地理空间REDIS API由一组命令组成,这些命令增加了对存储和查询经度/纬度坐标的支持和查询成对重键的命令。
地理空间API可从Redis版本> = 3.2.0获得。
添加地理空间项目
通过其坐标将用户添加到地理空间索引中:
string redisKey = "users:geo" ;
context . GeoSpatial . GeoAdd < User > ( redisKey , new GeoCoordinate ( 20.637 , - 103.402 ) , user ) ;添加与标签有关的地理空间项目
将用户添加到地理空间索引中,并将其与标签相关联:
string redisKey = "users:geo" ;
context . GeoSpatial . GeoAdd < User > ( redisKey , new GeoCoordinate ( 20.637 , - 103.402 ) , user , new [
下载源码
通过命令行克隆项目:
git clone https://github.com/thepirat000/CachingFramework.Redis.git