基礎用法
StackExchange.Redis
最核心的對象是 StackExchange.Redis.ConnectionMultiplexer
。ConnectionMultiplexer
被設計成可在多個調用之間共享使用。不需要為每個操作創建一個 ConnectionMultiplexer
,它是完全線程安全的。可以通過使用 ConnectionMultiplexer.Connect
或 ConnectionMultiplexer.ConnectAsync
來完成,並傳入配置字符串或 ConfigurationOptions
對象。 配置字符串可以采用一系列逗號分隔的節點的形式:
using StackExchange.Redis;
...
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
// ^^^ store and re-use this!!!
ConnectionMultiplexer
實現 IDisposable
,不再使用時可釋放,但短暫使用的情況很少見。
更復雜的情況可能涉及主/副本設置。對於此用法,只需指定所有節點(它將自動識別主節點):
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。 請注意,所有方法都具有同步和異步實現。
最簡單的操作是存儲和檢索值:
string value = "abcdefg";
db.StringSet("mykey", value);
...
string value = db.StringGet("mykey");
Console.WriteLine(value); // writes: "abcdefg"
請注意,這里的前綴 String...
表示 redis 的 String 類型,與 .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
返回的對象是一個不需要存儲的低成本的通道對象。
發布/訂閱 API 沒有數據庫的概念,但和之前一樣,我們可以選擇的提供一個異步狀態。
注意,所有訂閱都是全局的:它們不限於 ISubscriber
實例的生命周期。
redis 中的發布/訂閱功能使用命名的 “channels” ;channels 不需要事先在服務器上定義(這里有一個有趣的用法是利用每個用戶的通知渠道類驅動部分的實時更新)
如在.NET中常見的,訂閱采用回調委托的形式,它接受通道名稱和消息:
sub.Subscribe("messages", (channel, message) => {
Console.WriteLine((string)message);
});
注意:這里 StackExchange.Redis 捕獲並丟棄異常,以防止級聯失敗。要處理失敗,請在處理程序中使用
try/catch
來執行您所希望的操作(有任何例外情況)。
在 v2 中,你可以訂閱沒有回調的 Subscribe()
方法,而使用 ChannelMessageQueue
(表示有序發布/訂閱通知的消息隊列)作為替代。
可以使用 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
返回的對象是成本很低的通道對象,不需要存儲,並且可以選擇指定異步狀態。請注意,可用 endpoints
也可用:
EndPoint[] endpoints = redis.GetEndPoints();
在 IServer
實例中,可以使用 Server
命令。 例如:
DateTime lastSave = server.LastSave();
ClientInfo[] clients = server.ClientList();
同步 vs 異步 vs 執行且忽略
StackExchange.Redis 有3種主要使用機制:
- 同步 - 適用於操作在方法返回到調用者之前完成(雖然這會阻塞進程,但不會影響其他線程。StackExchange.Redis中的關鍵思想是它積極共享並發調用者之間的連接)
- 異步 - 該操作將在將來的某個時間完成,並立即返回
Task
或Task<T>
,稍后可以執行以下操作:- 執行
.Wait()
方法(阻塞當前進程,直到得到返回值) - 增加后續回調(
ContinueWith
in TPL) - 調用
await Task
(這是一種語言級別的功能,得到響應后立即繼續后續代碼)
- 執行
- 執行且忽略 - 忽略方法的返回值,交給后台執行。
同步用法在上面的示例中展示過了。是最簡單的用法,並且不涉及TPL。
對於異步用法,主要區別在於方法帶有 Async
后綴,以及使用 await
。 例如:
string value = "abcdefg";
await db.StringSetAsync("mykey", value);
...
string value = await db.StringGetAsync("mykey");
Console.WriteLine(value); // writes: "abcdefg"
執行且忽略用法,通過方法的可選參數 CommandFlags
進行設置(默認為無)。 在這種用法中,方法立即返回默認值(返回 String
的方法將返回 null
,返回 Int64
的方法將返回 0
),且方法將在后台執行,例如用於統計頁面訪問量:
db.StringIncrement(pageKey, flags: CommandFlags.FireAndForget);