基本使用
StackExchange.Redis 中核心對象是在 StackExchange.Redis
命名空間中的 ConnectionMultiplexer
類血公,這個對象隱藏了多個服務(wù)器的詳細(xì)信息昵仅。
因為ConnectionMultiplexer
要做很多事,它被設(shè)計為在調(diào)用者之間可以共享和重用累魔。
你不應(yīng)該在執(zhí)行每一個操作的時候就創(chuàng)建一個 ConnectionMultiplexer
. 它完全是線程安全的摔笤,并準(zhǔn)備好這種用法(多線程)。
在后續(xù)所有的例子中垦写,我們假設(shè)你有一個ConnectionMultiplexer
類的實例保存以重用吕世。
但現(xiàn)在,讓我們來先創(chuàng)建一個梯投。 這是使用 ConnectionMultiplexer.Connect
或 ConnectionMultiplexer.ConnectAsync
完成的命辖,傳遞配置字符串或ConfigurationOptions
對象。
配置字符串可以采用逗號分隔的一系列節(jié)點的形式分蓖,所以讓我們在默認(rèn)端口(6379)上連接到本地機(jī)器上的一個實例:
using StackExchange.Redis;
...
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
// ^^^ store and re-use this!!!
請注意尔艇,ConnectionMultiplexer
實現(xiàn)了 IDisposable
接口而且可以在不再需要的時候處理釋放掉。
這是故意不展示使用 using
語句用法么鹤,因為你想要只是簡單地使用一個ConnectionMultiplexer
的情況是極少見的 终娃,因為想法是重用這個對象。
更復(fù)雜的情況可能涉及主/從設(shè)置; 對于此用法蒸甜,只需簡單的指定組成邏輯redis層的所有所需節(jié)點(它將自動標(biāo)識主節(jié)點)
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("server1:6379,server2:6379");
如果它發(fā)現(xiàn)兩個節(jié)點都是主節(jié)點棠耕,則可以可選地指定可以用于解決問題的仲裁密鑰余佛,然而幸運地是這樣的條件是非常罕見的。
一旦你有一個 ConnectionMultiplexer
窍荧,你可能有3個主要想做的事:
- 訪問一個 redis 數(shù)據(jù)庫(注意辉巡,在集群的情況下,單個邏輯數(shù)據(jù)庫可以分布在多個節(jié)點上)
- 使用 redis 的的 發(fā)布/訂閱 功能
- 訪問單獨的服務(wù)器以進(jìn)行維護(hù)/監(jiān)視
使用 redis 數(shù)據(jù)庫
訪問redis數(shù)據(jù)庫非常簡單:
IDatabase db = redis.GetDatabase();
從 GetDatabase
返回的對象是一個成本很低的通道對象搅荞,不需要存儲红氯。
注意,redis支持多個數(shù)據(jù)庫(雖然“集群”不支持)咕痛,這可以可選地在調(diào)用 GetDatabase
中指定痢甘。
此外,如果您計劃使用異步API茉贡,您需要 Task.AsyncState
有一個值塞栅,也可以指定:
int databaseNumber = ...
object asyncState = ...
IDatabase db = redis.GetDatabase(databaseNumber, asyncState);
一旦你有了'IDatabase',它只是一個使用 redis API 的情況腔丧。
注意放椰,所有方法都具有同步和異步實現(xiàn)。
根據(jù)微軟的命名指導(dǎo)愉粤,異步方法都以 ...Async(...)
結(jié)尾砾医,并且完全是可以等待的 await
等。
最簡單的操作也許是存儲和檢索值:
string value = "abcdefg";
db.StringSet("mykey", value);
...
string value = db.StringGet("mykey");
Console.WriteLine(value); // writes: "abcdefg"
需要注意的是衣厘,這里的 String...
前綴表示 redis 的 String 類型如蚜,盡管它和 .NET 的字符串類型 都可以保存文本, 它們還是有較大差別的影暴。
然而错邦,redis 還允許鍵和值使用原始的二進(jìn)制數(shù)據(jù),用法和字符串是一樣的:
byte[] key = ..., value = ...;
db.StringSet(key, value);
...
byte[] value = db.StringGet(key);
覆蓋所有redis數(shù)據(jù)類型的所有 [redis數(shù)據(jù)庫命令](http://redis.io/commands)的都是可以使用的型宙。
使用 redis 發(fā)布/訂閱
redis的另一個常見用法是作為 發(fā)布/訂閱消息分發(fā)工具;
這也很簡單撬呢,并且在連接失敗的情況下, ConnectionMultiplexer
將處理重新訂閱所請求的信道的所有細(xì)節(jié)妆兑。
ISubscriber sub = redis.GetSubscriber();
同樣魂拦,從 GetSubscriber
返回的對象是一個不需要存儲的低成本的通道對象。
發(fā)布/訂閱 API沒有數(shù)據(jù)庫的概念箭跳,但和之前一樣晨另,我們可以選擇的提供一個異步狀態(tài)。
注意谱姓,所有訂閱都是全局的:它們不限于 ISubscriber
實例的生命周期。
redis中的 發(fā)布/訂閱 功能使用命名的“channels”; channels 不需要事先在服務(wù)器上定義(這里有一個有趣的用法是利用每個用戶的通知渠道類驅(qū)動部分的實時更新)
如在.NET中常見的刨晴,訂閱采用回調(diào)委托的形式屉来,它接受通道名稱和消息:
sub.Subscribe("messages", (channel, message) => {
Console.WriteLine((string)message);
});
另外(通常在一個單獨的機(jī)器上的一個單獨的進(jìn)程)路翻,你可以發(fā)布到該通道:
sub.Publish("messages", "hello");
這將(實際上瞬間)將“hello”寫到訂閱進(jìn)程的控制臺。 和之前一樣茄靠,通道名和消息都可以是二進(jìn)制的茂契。
有關(guān)順序和并發(fā)消息處理的使用文檔說明,請參見 發(fā)布/訂閱消息順序 慨绳。
訪問單獨的服務(wù)器
出于維護(hù)目的掉冶,有時需要發(fā)出服務(wù)器特定的命令:
IServer server = redis.GetServer("localhost", 6379);
GetServer
方法會接受一個 EndPoint
終結(jié)點或者是一個可以唯一標(biāo)識一個服務(wù)器的鍵/值對。
像之前介紹的那樣脐雪, GetServer
方法返回的是一個不需要被存儲的輕量級的通道對象厌小,并且可以可選的指定 async-state(異步狀態(tài))。
需要注意的是战秋,多個可用的節(jié)點也是可以的:
EndPoint[] endpoints = redis.GetEndPoints();
一個 IServer
實例是可以使用服務(wù)器命令的 Server commands璧亚,例如:
DateTime lastSave = server.LastSave();
ClientInfo[] clients = server.ClientList();
同步 vs 異步 vs 執(zhí)行后不理
StackExchange.Redis有3種主要使用機(jī)制:
同步 - 適用于操作在方法返回到調(diào)用者之前完成(注意,盡管這可能阻止調(diào)用者脂信,但它絕對不會阻止其他線程:StackExchange.Redis的關(guān)鍵思想是它積極地與并發(fā)調(diào)用者共享連接)
Asynchronous - where the operation completes some time in the future, and a
Task
orTask<T>
is returned immediately, which can later:異步 - 操作在將來完成一些時間癣蟋,并且立即返回一個
Task
或 'Task<T>' 對象,也可以稍后再返回:是可以等待的(阻塞當(dāng)前線程狰闪,直到響應(yīng)可用)
.Wait()
可以增加一個后續(xù)的回調(diào) (TPL 中的
ContinueWith
)awaited 可等待的(這是簡化后者的語言級特性疯搅,同時如果答復(fù)已經(jīng)知道也立即繼續(xù))
執(zhí)行后不理 - 適用于你真的對這個回復(fù)不感興趣,并且樂意繼續(xù)不管回應(yīng)
同步的用法已經(jīng)在上面的示例中展示了埋泵。這是最簡單的用法幔欧,并且不涉及 TPL。
對于異步使用秋泄,關(guān)鍵的區(qū)別是方法名稱上的 Async
后綴琐馆,以及(通常)使用“await”語言特性。例如:
string value = "abcdefg";
await db.StringSetAsync("mykey", value);
...
string value = await db.StringGetAsync("mykey");
Console.WriteLine(value); // writes: "abcdefg"
執(zhí)行后不理 的用法可以通過所有方法上的可選參數(shù) CommandFlags flags
(默認(rèn)值為 null
)來訪問使用恒序。
這種用法中瘦麸,方法會立即方法一個默認(rèn)值(所以通常返回一個 String
的方法總是返回 null
,而一個通常返回一個 Int64
的方法總是返回 0
)歧胁。
操作會在后臺繼續(xù)執(zhí)行滋饲。這種情況的典型用例可能是增加頁面瀏覽數(shù)量:
db.StringIncrement(pageKey, flags: CommandFlags.FireAndForget);
查看原文
More
作者水平有限,若有疏漏或錯誤還望提醒喊巍,十分感謝屠缭。
您可以在這里 提出問題 。