基本用法
StackExchange.Redis中的中心对象是名称空间中的ConnectionMultiplexer类StackExchange.Redis。这是隐藏多个服务器详细信息的对象。由于ConnectionMultiplexer功能很多,因此可以在调用方之间共享和重用它。您不应该创建ConnectionMultiplexer每个操作。它是完全线程安全的,并且可以用于此用途。在所有后续示例中,将假定您已ConnectionMultiplexer保存一个实例以供重用。但是现在,让我们创建一个。这可以使用ConnectionMultiplexer.Connect或ConnectionMultiplexer.ConnectAsync传入配置字符串或ConfigurationOptions对象来完成。配置字符串可以采用逗号分隔的一系列节点的形式,因此让我们仅通过默认端口(6379)连接到本地计算机上的实例:
using StackExchange.Redis;
...
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
// ^^^ store and re-use this!!!
需要注意的是ConnectionMultiplexer工具IDisposable,可以在不再需要处置。这是故意不显示using语句用法的原因,因为ConnectionMultiplexer要重用此对象非常少见,因此您希望简短地使用它。
更复杂的情况可能涉及主/副本设置。对于此用法,只需指定组成该逻辑Redis层的所有所需节点(它将自动识别主节点):
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("server1:6379,server2:6379");
如果发现两个节点都是主节点,则可以有选择地指定一个决胜键,该键可用于解决问题,但是幸运的是这种情况很少见。
有了之后ConnectionMultiplexer,您可能需要做以下三件事:
-
访问redis数据库(请注意,在集群的情况下,单个逻辑数据库可能分布在多个节点上)
-
利用redis的发布/订阅功能
-
访问单个服务器以进行维护/监视
使用redis数据库
-
访问redis数据库非常简单:
-
IDatabase db = redis.GetDatabase();
-
返回的对象
GetDatabase
是便宜的直通对象,不需要存储。请注意,redis支持多个数据库(尽管“群集”不支持此功能);您可以在调用中指定此选项GetDatabase
。此外,如果您打算使用异步API并要求Task.AsyncState
具有一个值,则也可以指定以下值: -
int databaseNumber = ... object asyncState = ... IDatabase db = redis.GetDatabase(databaseNumber, asyncState);
-
一旦有了
IDatabase
,只需使用redis API。请注意,所有方法都具有同步和异步实现。按照Microsoft的命名指南,所有异步方法都结束了...Async(...)
,并且是完全await
可用的,等等。 -
最简单的操作是存储和检索值:
-
string value = "abcdefg"; db.StringSet("mykey", value); ... string value = db.StringGet("mykey"); Console.WriteLine(value); // writes: "abcdefg"
-
请注意,
String...
此处的前缀表示String redis类型,尽管它们都可以存储文本数据,但它们在很大程度上与.NET String类型分开。但是,redis允许键和值都使用原始二进制数据-用法是相同的: -
byte[] key = ..., value = ...; db.StringSet(key, value); ... byte[] value = db.StringGet(key);
-
的整个范围内redis的数据库命令涵盖所有redis的数据类型是可供使用。
使用redis发布订阅
-
Redis的另一种常见用法是作为发布/订阅消息分发工具。这也很简单,并且在连接失败的情况下,
ConnectionMultiplexer
它将处理重新订阅所请求频道的所有细节。 -
ISubscriber sub = redis.GetSubscriber();
-
同样,从中返回的对象
GetSubscriber
是便宜的直通对象,无需存储。pub / sub API没有数据库的概念,但是像以前一样,我们可以选择提供异步状态。请注意,所有订阅都是全局的:它们的作用域不限于ISubscriber
实例的生存期。Redis中的发布/订阅功能使用命名为“ channels”的通道;不需要在服务器上预先定义通道(这里有趣的用法是每用户通知通道之类的东西,它是驱动Stack Overflow实时更新的一部分)。与.NET中常见的一样,订阅采用回调委托的形式,它们接受通道名称和消息: -
sub.Subscribe("messages", (channel, message) => { Console.WriteLine((string)message); });
-
注意:此处的异常由StackExchange.Redis捕获和丢弃,以防止级联失败。要处理失败,请在处理程序中使用
try
/catch
来执行您希望的操作(有任何例外情况)。 -
在v2中,您可以订阅而无需直接向该
Subscribe()
方法提供回调,而可以使用returnChannelMessageQueue
,它表示有序发布/订阅通知的消息队列。这允许使用ChannelMessageQueue.OnMessage()
方法,该方法为接收消息时要执行的同步(Action<ChannelMessage>
)和异步(Func<ChannelMessage, Task>
)处理程序提供重载。 -
// Synchronous handler sub.Subscribe("messages").OnMessage(channelMessage => { Console.WriteLine((string) channelMessage.Message); }); // Asynchronous handler sub.Subscribe("messages").OnMessage(async channelMessage => { await Task.Delay(1000); Console.WriteLine((string) channelMessage.Message); });
-
您可以单独(通常是在单独的计算机上的单独过程中)发布到此频道:
-
sub.Publish("messages", "hello");
-
这将(实际上是瞬时地)写入
"hello"
已订阅进程的控制台。和以前一样,通道名和消息都可以是二进制的。 -
另请参阅发布/子消息顺序,以获取有关顺序消息和并发消息处理的指南。
访问单个服务器
-
出于维护目的,有时有必要发出服务器特定的命令:
-
IServer server = redis.GetServer("localhost", 6379);
-
该
GetServer
方法将接受EndPoint
唯一标识服务器的或名称/值对。和以前一样,从其返回的对象GetServer
是便宜的直通对象,不需要存储,并且可以选择指定异步状态。请注意,可用端点集也可用: -
EndPoint[] endpoints = redis.GetEndPoints();
-
在
IServer
实例中,服务器命令可用;例如: -
DateTime lastSave = server.LastSave(); ClientInfo[] clients = server.ClientList();
同步和异步
-
StackExchange.Redis有3种主要使用机制:
-
同步-操作在方法返回调用者之前完成(请注意,尽管这可能会阻止调用者,但它绝对不会阻止其他线程:StackExchange.Redis中的关键思想是它积极共享并发调用者之间的连接)
-
异步-该操作将在以后的某个时间完成,并且立即返回
Task
或Task<T>
,以后可以:-
是
.Wait()
ED(阻塞当前线程,直到响应是可用的) -
ContinueWith
在TPL中添加了一个继续回调 -
被期待已久的(这是一个语言级的功能,简化了后者,同时也继续如果立即答复是已知的)
-
-
一劳永逸-您对回复真的不感兴趣,无论回复如何,乐于继续
-
同步用法已在上面的示例中显示。这是最简单的用法,并且不涉及TPL。
-
对于异步使用,主要区别在于
Async
方法的后缀,以及(通常)await
语言功能的使用。例如: -
string value = "abcdefg"; await db.StringSetAsync("mykey", value); ... string value = await db.StringGetAsync("mykey"); Console.WriteLine(value); // writes: "abcdefg"
-
即弃即用用法可通过
CommandFlags flags
所有方法上的可选参数访问(默认为无)。在这种用法中,该方法立即返回默认值(因此,通常返回a的方法String
将始终返回null
,而通常返回an的方法Int64
将始终返回0
)。该操作将在后台继续。一个典型的用例是增加页面浏览量: -
db.StringIncrement(pageKey, flags: CommandFlags.FireAndForget);