【譯】StackExchange.Redis中文使用文檔--管道與重用鏈接

管道和鏈接復(fù)用

延遲嚴(yán)重。現(xiàn)代計(jì)算機(jī)可以以驚人的速度攪動(dòng)數(shù)據(jù)并齐,并且高速網(wǎng)絡(luò)(通常具有在重要服務(wù)器之間的多個(gè)并行鏈路)提供巨大的帶寬独悴,但是... 該延遲意味著計(jì)算機(jī)花費(fèi)大量的時(shí)間等待數(shù)據(jù) 和 這是基于連續(xù)的編程越來(lái)越受歡迎的幾個(gè)原因之一耸袜。

讓我們考慮一些常規(guī)的程序代碼:

string a = db.StringGet("a");
string b = db.StringGet("b");

在涉及的步驟方面扇谣,這看起來(lái)大致是這樣:

[req1]                         # client: the client library constructs request 1
     [c=>s]                    # network: request one is sent to the server
          [server]             # server: the server processes request 1
                 [s=>c]        # network: response one is sent back to the client
                      [resp1]  # client: the client library parses response 1
                            [req2]
                                 [c=>s]
                                      [server]
                                             [s=>c]
                                                  [resp2]

現(xiàn)在讓我們突出客戶端正在做的一些事的時(shí)間點(diǎn)

[req1]
     [====waiting=====]
                      [resp1]
                            [req2]
                                 [====waiting=====]
                                                  [resp2]

請(qǐng)記住昧捷,這是不成比例的 - 如果這是按時(shí)間縮放,它將是完全由waiting 控制的罐寨。

管道線

因此靡挥,許多redis客戶端允許你使用 pipelining, 這是在管道上發(fā)送多個(gè)消息而不等待來(lái)自每個(gè)的答復(fù)的過(guò)程 - 并且(通常)稍后當(dāng)它們進(jìn)入時(shí)處理答復(fù)鸯绿。
在 .NET 中跋破,可以啟動(dòng)但尚未完成,并且可能以后完成或故障的由TPL封裝的操作可以由 TPL 通過(guò) Task / Task <T> API 來(lái)實(shí)現(xiàn)楞慈。
本質(zhì)上幔烛, Task<T> 表示 " T 類型未來(lái)可能的值"(非泛型的 Task 本質(zhì)尚是 Task<void> )啃擦。你可以使用任意一種用法:

  • 在稍后的代碼塊等待直到操作完成(.Wait()
  • 當(dāng)操作完成時(shí)囊蓝,調(diào)度一個(gè)后續(xù)操作(.ContinueWith(...)await

例如,要使用過(guò)程化(阻塞)代碼來(lái)借助管道傳遞這兩個(gè) get 操作令蛉,我們可以使用:

var aPending = db.StringGetAsync("a");
var bPending = db.StringGetAsync("b");
var a = db.Wait(aPending);
var b = db.Wait(bPending);

注意聚霜,我在這里使用db.Wait,因?yàn)樗鼤?huì)自動(dòng)應(yīng)用配置的同步超時(shí)珠叔,但如果你喜歡你也可以使用 aPending.Wait()Task.WaitAll(aPending,bPending);蝎宇。
使用管道技術(shù),我們可以立即將這兩個(gè)請(qǐng)求發(fā)送到網(wǎng)絡(luò)祷安,從而消除大部分延遲姥芥。
此外,它還有助于減少數(shù)據(jù)包碎片:?jiǎn)为?dú)發(fā)送(等待每個(gè)響應(yīng))的20個(gè)請(qǐng)求將需要至少20個(gè)數(shù)據(jù)包汇鞭,但是在管道中發(fā)送的20個(gè)請(qǐng)求可以通過(guò)少得多的數(shù)據(jù)包(也許只有一個(gè))凉唐。

執(zhí)行后不理

管道的一個(gè)特例是當(dāng)我們明確地不關(guān)心來(lái)自特定操作的響應(yīng)時(shí)庸追,這允許我們的代碼在排隊(duì)操作在后臺(tái)繼續(xù)時(shí)立即繼續(xù)。 通常台囱,這意味著我們可以在單個(gè)調(diào)用者的連接上并發(fā)工作淡溯。 這是使用 flags 參數(shù)來(lái)實(shí)現(xiàn)的:

// sliding expiration
db.KeyExpire(key, TimeSpan.FromMinutes(5), flags: CommandFlags.FireAndForget);
var value = (string)db.StringGet(key);

FireAndForget 標(biāo)志使客戶端庫(kù)正常地排隊(duì)工作,但立即返回一個(gè)默認(rèn)值(因?yàn)?KeyExpire 返回一個(gè) bool 簿训,這將返回 false 咱娶,因?yàn)?default(bool)false - 但是返回值是無(wú)意義的,應(yīng)該忽略)强品。
這也適用于 *Async 方法:一個(gè)已經(jīng)完成的 Task <T> 返回默認(rèn)值(或者為 void 方法返回一個(gè)已經(jīng)完成的 Task )膘侮。

復(fù)用鏈接

管道是很好的,但是通常任何單個(gè)代碼塊只需要一個(gè)值(或者可能想要執(zhí)行幾個(gè)操作择懂,但是依賴于彼此)喻喳。
這意味著我們?nèi)匀挥幸粋€(gè)問(wèn)題,我們花大部分時(shí)間等待數(shù)據(jù)在客戶端和服務(wù)器之間傳輸困曙。
現(xiàn)在考慮一個(gè)繁忙的應(yīng)用程序表伦,也許是一個(gè)Web服務(wù)器。
這樣的應(yīng)用程序通常是并發(fā)的慷丽,所以如果你有20個(gè)并行應(yīng)用程序請(qǐng)求都需要數(shù)據(jù)蹦哼,你可能會(huì)想到旋轉(zhuǎn)20個(gè)連接,或者你可以同步訪問(wèn)單個(gè)連接(這意味著最后一個(gè)調(diào)用者需要等待 延遲的所有其他19之前要糊,甚至開(kāi)始)纲熏。 或者折中一下,也許一個(gè)5個(gè)連接的租賃池 - 無(wú)論你怎么做锄俄,都會(huì)有很多的等待局劲。
StackExchange.Redis不做這個(gè); 相反,它做 很多 的工作奶赠,使你有效地利用所有這個(gè)空閑時(shí)間復(fù)用 一個(gè)連接鱼填。
當(dāng)不同的調(diào)用者同時(shí)使用它時(shí),它自動(dòng)把這些單獨(dú)的請(qǐng)求加入管道毅戈,所以不管請(qǐng)求使用阻塞還是異步訪問(wèn)苹丸,工作都是按進(jìn)入管道的順序處理的。
因此苇经,我們可能有10或20個(gè)的“get a 和 b”包括此前的(從不同的應(yīng)用程序請(qǐng)求)情景中赘理,并且他們都將盡快到達(dá)連接。
基本上扇单,它用完成其他調(diào)用者的工作的時(shí)間來(lái)填充 waiting 時(shí)間商模。

因此,StackExchange.Redis不提供的唯一redis特性(不會(huì)提供)是“阻塞彈出”(BLPOPBRPOPBRPOPLPUSH)施流,因?yàn)檫@將允許單個(gè)調(diào)用者停止整個(gè)多路復(fù)用器凉倚,阻止所有其他調(diào)用者 。
StackExchange.Redis 需要保持工作的唯一其他時(shí)間是在驗(yàn)證事務(wù)的前提條件時(shí)嫂沉,這就是為什么 StackExchange.Redis 將這些條件封裝到內(nèi)部管理的 condition 實(shí)例中稽寒。

在這里閱讀更多關(guān)于事務(wù)
如果你覺(jué)得你想“阻止出椞苏拢”杏糙,那么我強(qiáng)烈建議你考慮 發(fā)布 / 訂閱 代替:

sub.Subscribe(channel, delegate {
    string work = db.ListRightPop(key);
    if (work != null) Process(work);
});
//...
db.ListLeftPush(key, newWork, flags: CommandFlags.FireAndForget);
sub.Publish(channel, "");

這實(shí)現(xiàn)了相同的目的,而不需要阻塞操作蚓土。 注意:

  • 數(shù)據(jù) 不通過(guò) 發(fā)布 / 訂閱 發(fā)送; 發(fā)布 / 訂閱 API只用于通知處理器檢查更多的工作
  • 如果沒(méi)有處理器宏侍,則新項(xiàng)目保持緩存在列表中; 工作不會(huì)丟失
  • 只有一個(gè)處理器可以彈出單個(gè)值; 當(dāng)消費(fèi)者比生產(chǎn)者多時(shí),一些消費(fèi)者會(huì)被通知蜀漆,然后發(fā)現(xiàn)沒(méi)有什么可做的
  • 當(dāng)你重新啟動(dòng)一個(gè)處理器谅河,你應(yīng)該假設(shè) 有工作,以便你處理任何積壓的任務(wù)
  • 但除此之外确丢,語(yǔ)義與阻止出棧相同

StackExchange.Redis 的多路復(fù)用特性使得在使用常規(guī)的不復(fù)雜代碼的同時(shí)在單個(gè)連接上達(dá)到極高的吞吐量成為可能绷耍。

并發(fā)

應(yīng)當(dāng)注意,管道/鏈接復(fù)用器/未來(lái)值 方法對(duì)于基于連續(xù)的異步代碼也很好地起作用鲜侥;例如你可以寫(xiě):

string value = await db.StringGetAsync(key);
if (value == null) {
    value = await ComputeValueFromDatabase(...);
    db.StringSet(key, value, flags: CommandFlags.FireAndForget);
}
return value;

查看原文

More

作者水平有限褂始,若有疏漏或錯(cuò)誤還望提醒,十分感謝描函。

您可以在這里 提出問(wèn)題 崎苗。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市舀寓,隨后出現(xiàn)的幾起案子胆数,更是在濱河造成了極大的恐慌,老刑警劉巖互墓,帶你破解...
    沈念sama閱讀 212,686評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件必尼,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡轰豆,警方通過(guò)查閱死者的電腦和手機(jī)胰伍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,668評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)齿诞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)酸休,“玉大人,你說(shuō)我怎么就攤上這事祷杈“咚荆” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,160評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)宿刮。 經(jīng)常有香客問(wèn)我互站,道長(zhǎng),這世上最難降的妖魔是什么僵缺? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,736評(píng)論 1 284
  • 正文 為了忘掉前任胡桃,我火速辦了婚禮,結(jié)果婚禮上磕潮,老公的妹妹穿的比我還像新娘翠胰。我一直安慰自己,他們只是感情好自脯,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,847評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布之景。 她就那樣靜靜地躺著,像睡著了一般膏潮。 火紅的嫁衣襯著肌膚如雪锻狗。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 50,043評(píng)論 1 291
  • 那天焕参,我揣著相機(jī)與錄音轻纪,去河邊找鬼。 笑死叠纷,一個(gè)胖子當(dāng)著我的面吹牛桐磁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播讲岁,決...
    沈念sama閱讀 39,129評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼我擂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了缓艳?” 一聲冷哼從身側(cè)響起校摩,我...
    開(kāi)封第一講書(shū)人閱讀 37,872評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎阶淘,沒(méi)想到半個(gè)月后衙吩,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,318評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡溪窒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,645評(píng)論 2 327
  • 正文 我和宋清朗相戀三年坤塞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澈蚌。...
    茶點(diǎn)故事閱讀 38,777評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡摹芙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宛瞄,到底是詐尸還是另有隱情浮禾,我是刑警寧澤,帶...
    沈念sama閱讀 34,470評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站盈电,受9級(jí)特大地震影響蝴簇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜匆帚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,126評(píng)論 3 317
  • 文/蒙蒙 一熬词、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吸重,春花似錦荡澎、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,861評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至鞭铆,卻和暖如春或衡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背车遂。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,095評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工封断, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人舶担。 一個(gè)月前我還...
    沈念sama閱讀 46,589評(píng)論 2 362
  • 正文 我出身青樓坡疼,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親衣陶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子柄瑰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,687評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容