The Tail at Scale
The Tail at Scale[1],是 Google 2013 年發(fā)布的一篇論文,大規(guī)模在線服務(wù)的長(zhǎng)尾延遲問(wèn)題。
要知道怎么解決長(zhǎng)尾問(wèn)題,先要理解長(zhǎng)尾延遲是個(gè)什么問(wèn)題,在開(kāi)發(fā)在線服務(wù)的時(shí)候,我們都知道要關(guān)注服務(wù)的 p99/p999 延遲,要讓大部分用戶(hù)都能夠在預(yù)期的時(shí)間范圍內(nèi)獲得響應(yīng)。
下面是一個(gè)不同時(shí)間的請(qǐng)求數(shù)分布圖:
tail_latency大部分系統(tǒng)也都遵循這種分布規(guī)律,現(xiàn)在互聯(lián)網(wǎng)的系統(tǒng)規(guī)模比較大,一個(gè)服務(wù)依賴(lài)幾十上百個(gè)服務(wù)的情況都是有可能的。單一模塊的長(zhǎng)尾延遲會(huì)在有大量依賴(lài)的情況下,在服務(wù)粒度被放大,《The Tail at Scale》論文里給出了這樣的例子。
考慮一個(gè)系統(tǒng),大部分服務(wù)調(diào)用在 10ms 內(nèi)響應(yīng),但 99 分位數(shù)的延遲為 1 秒。如果一個(gè)用戶(hù)請(qǐng)求只在一個(gè)這樣的服務(wù)上處理,那么 100 個(gè)用戶(hù)請(qǐng)求中只有一個(gè)會(huì)很慢(一秒鐘)。這里的圖表概述了在這種假設(shè)的情況下,服務(wù)級(jí)別的延遲是如何被非常小概率的大延遲值影響的。
tail如果一個(gè)用戶(hù)請(qǐng)求必須從100個(gè)這樣的服務(wù)并行收集響應(yīng),那么 63% 的用戶(hù)請(qǐng)求將需要超過(guò)一秒鐘(圖中標(biāo)記為 "x")。即使對(duì)于只有萬(wàn)分之一概率在單臺(tái)服務(wù)器上遇到超過(guò)一秒的響應(yīng)延遲的服務(wù),如果服務(wù)的規(guī)模到達(dá) 2000 實(shí)例的話,也會(huì)觀察到幾乎五分之一的用戶(hù)請(qǐng)求需要超過(guò)一秒(圖中標(biāo)記為 "o")。
Xargin 注:
因?yàn)檎?qǐng)求是并行的,所以只受最慢的那個(gè)影響,100 個(gè)請(qǐng)求都落在 99 分位內(nèi)延遲才會(huì)小于 1s,所以延遲小于 1s 的概率是 pow(0.99, 100) = 0.3660323412732292,也就是說(shuō)一定有 63% 的概率會(huì)超過(guò) 1s。
第二個(gè),我們落在 99 分位的概率是 pow(0.9999, 2000) = 0.8187225652655495,也就是將近 20% 的用戶(hù)響應(yīng)會(huì)超過(guò) 1s。
上面的表格列出了一個(gè)真實(shí)的谷歌服務(wù)的測(cè)量結(jié)果,該服務(wù)在邏輯上與前文簡(jiǎn)化過(guò)的場(chǎng)景相似;根服務(wù)通過(guò)中間服務(wù)將一個(gè)請(qǐng)求分發(fā)到非常多的葉子服務(wù)。表展示了大量扇出(fan-out)調(diào)用時(shí),對(duì)延遲分布的影響。
在根服務(wù)器上測(cè)量的單個(gè)隨機(jī)請(qǐng)求完成的 99 分位延遲是 10ms。然而,所有請(qǐng)求完成的 99 分位數(shù)延遲是 140ms,95% 的請(qǐng)求 99 分位數(shù)延遲是 70ms,這意味著等待最慢的 5% 的慢請(qǐng)求要對(duì)總的 99 百分位數(shù)延遲的一半負(fù)責(zé)。對(duì)這些慢請(qǐng)求場(chǎng)景進(jìn)行優(yōu)化,會(huì)對(duì)服務(wù)的整體延遲產(chǎn)生巨大影響。
為什么會(huì)有長(zhǎng)尾延遲?
單個(gè)服務(wù)組件的長(zhǎng)尾高延遲可能由于許多原因產(chǎn)生,包括:
共享資源(Xargin: 混部現(xiàn)在越來(lái)越多了)。機(jī)器可能被爭(zhēng)奪共享資源(如 CPU 核心、處理器緩存、內(nèi)存帶寬和網(wǎng)絡(luò)帶寬)的不同應(yīng)用所共享,而在同一應(yīng)用中,不同的請(qǐng)求可能爭(zhēng)奪資源。
守護(hù)程序。后臺(tái)守護(hù)程序可能平均只使用有限的資源,但在運(yùn)行時(shí)可能會(huì)產(chǎn)生幾毫秒的峰值。
全局資源共享。在不同機(jī)器上運(yùn)行的應(yīng)用程序可能會(huì)爭(zhēng)搶全局資源(如網(wǎng)絡(luò)交換機(jī)和共享文件系統(tǒng))。
后臺(tái)任務(wù)。后臺(tái)活動(dòng)(如分布式文件系統(tǒng)中的數(shù)據(jù)重建,BigTable等存儲(chǔ)系統(tǒng)中的定期日志壓縮,以及垃圾收集語(yǔ)言中的定期垃圾收集)會(huì)導(dǎo)致周期性的延遲高峰。
排隊(duì)。中間服務(wù)器和網(wǎng)絡(luò)交換機(jī)中的多層隊(duì)列放大了這種可能性。
同時(shí)也是因?yàn)楫?dāng)前硬件的趨勢(shì):
功率限制。現(xiàn)代 CPU 被設(shè)計(jì)成可以暫時(shí)運(yùn)行在其平均功率之上(英特爾睿頻加速技術(shù)),如果這種活動(dòng)持續(xù)很長(zhǎng)時(shí)間,可以通過(guò)降頻降低發(fā)熱;
垃圾收集。固態(tài)存儲(chǔ)設(shè)備提供了非常快的隨機(jī)讀取訪問(wèn),但是需要定期對(duì)大量的數(shù)據(jù)塊進(jìn)行垃圾收集,即使是適度的寫(xiě)入活動(dòng),也會(huì)使讀取延遲增加100倍;
能源管理。許多類(lèi)型的設(shè)備的省電模式可以節(jié)省相當(dāng)多的能量,但在從非活動(dòng)模式轉(zhuǎn)為活動(dòng)模式時(shí),會(huì)增加額外的延遲。
解決方案
模塊內(nèi)盡量降低長(zhǎng)尾延遲
服務(wù)分級(jí) && 優(yōu)先級(jí)隊(duì)列。差異化服務(wù)級(jí)別可以用來(lái)優(yōu)先調(diào)度用戶(hù)正在等待的請(qǐng)求,而不是非交互式請(qǐng)求。保持低級(jí)隊(duì)列較短,以便更高級(jí)別的策略更快生效。
減少隊(duì)頭阻塞。將需要長(zhǎng)時(shí)間運(yùn)行的請(qǐng)求打散成一連串小請(qǐng)求,使其可以與其它短時(shí)間任務(wù)交錯(cuò)執(zhí)行;例如,谷歌的網(wǎng)絡(luò)搜索系統(tǒng)使用這種時(shí)間分割,以防止大請(qǐng)求影響到大量其它計(jì)算成本較低的大量查詢(xún)延遲。(隊(duì)頭阻塞還有協(xié)議和連接層面的問(wèn)題,需要通過(guò)使用更新的協(xié)議來(lái)解決,比如 h1 -> h2 -> h3 的升級(jí)思路)
管理后臺(tái)活動(dòng)和同步中斷。后臺(tái)任務(wù)可能產(chǎn)生巨大的 CPU、磁盤(pán)或網(wǎng)絡(luò)負(fù)載;例子是面向日志的存儲(chǔ)系統(tǒng)的日志壓縮和垃圾收集語(yǔ)言的垃圾收集器活動(dòng)。可以結(jié)合限流功能,把重量級(jí)操作分解成成本較低的操作,并在整體負(fù)載較低的時(shí)候觸發(fā)這些操作(比如半夜),以減少后臺(tái)活動(dòng)對(duì)交互式請(qǐng)求延遲的影響。
請(qǐng)求期間內(nèi)的一些自適應(yīng)手段
對(duì)沖請(qǐng)求。抑制延遲變化的一個(gè)簡(jiǎn)單方法是向多個(gè)副本發(fā)出相同的請(qǐng)求(Go 并發(fā)模式中的 or channel),并使用首先響應(yīng)的結(jié)果。一旦收到第一個(gè)結(jié)果,客戶(hù)端就會(huì)取消剩余的未處理請(qǐng)求。不過(guò)直接這么實(shí)現(xiàn)會(huì)造成額外的多倍負(fù)載。所以需要考慮優(yōu)化。
一個(gè)方法是推遲發(fā)送第二個(gè)請(qǐng)求,直到第一個(gè)請(qǐng)求到達(dá) 95 分位數(shù)還沒(méi)有返回。這種方法將額外的負(fù)載限制在 5% 左右,同時(shí)大大縮短了長(zhǎng)尾時(shí)間。
捆綁式請(qǐng)求。不像對(duì)沖一樣等待一段時(shí)間發(fā)送,而是同時(shí)發(fā)給多個(gè)副本,但告訴副本還有其它的服務(wù)也在執(zhí)行這個(gè)請(qǐng)求,副本任務(wù)處理完之后,會(huì)主動(dòng)請(qǐng)求其它副本取消其正在處理的同一個(gè)請(qǐng)求。需要額外的網(wǎng)絡(luò)同步。
跨請(qǐng)求的自適應(yīng)手段
微 分區(qū)。劃分單個(gè)機(jī)器為多個(gè) 分區(qū),以解決負(fù)載不平衡問(wèn)題。例如,每臺(tái)機(jī)器平均有 20 個(gè)分區(qū),系統(tǒng)可以以大約 5% 的增量來(lái)調(diào)輕負(fù)載,時(shí)間是系統(tǒng)簡(jiǎn)單地將分區(qū)與機(jī)器進(jìn)行一對(duì)一映射的 1/20。( sh )
選擇性的復(fù)制。為你檢測(cè)到的或預(yù)測(cè)到的會(huì)很熱的分區(qū)增加復(fù)制因子。然后,負(fù)載均衡器可以幫助分散負(fù)載。谷歌的主要網(wǎng)絡(luò)搜索系統(tǒng)采用了這種方法,在多個(gè)微分區(qū)中對(duì)流行和重要的文件進(jìn)行額外的復(fù)制。(就是熱點(diǎn)分區(qū)多準(zhǔn)備些實(shí)例啦,感覺(jué)應(yīng)該需要按具體業(yè)務(wù)去做一些預(yù)測(cè))
將慢速機(jī)器置于考察期。當(dāng)檢測(cè)到一臺(tái)慢速機(jī)器時(shí),暫時(shí)將其排除在操作之外(circuit breaker)。由于緩慢往往是暫時(shí)的,監(jiān)測(cè)何時(shí)使受影響的系統(tǒng)重新上線。繼續(xù)向這些被排除的服務(wù)器發(fā)出影子請(qǐng)求,收集它們的延遲統(tǒng)計(jì)數(shù)據(jù),以便在問(wèn)題緩解時(shí)將它們重新納入服務(wù)中。(這里就是簡(jiǎn)單的熔斷的實(shí)現(xiàn))
一些其它的權(quán)衡
考慮“足夠好”的響應(yīng)。一旦所有的服務(wù)器中有足夠的一部分做出了響應(yīng),用戶(hù)可能會(huì)得到最好的服務(wù),即得到輕微的不完整的結(jié)果,以換取更好的端到端延遲。(這里應(yīng)該是大家常說(shuō)的降級(jí))
使用金絲雀請(qǐng)求。在具有非常高扇出的系統(tǒng)中可能發(fā)生的另一個(gè)問(wèn)題是,一個(gè)特定的請(qǐng)求觸發(fā)了未經(jīng)測(cè)試的代碼路徑,導(dǎo)致崩潰或同時(shí)在成千上萬(wàn)的服務(wù)器上出現(xiàn)極長(zhǎng)的延遲。為了防止這種相關(guān)的崩潰情況,谷歌的一些 IR 系統(tǒng)采用了一種叫做“金絲雀請(qǐng)求”的技術(shù);根服務(wù)器并不是一開(kāi)始就把一個(gè)請(qǐng)求發(fā)送給成千上萬(wàn)的葉子服務(wù)器,而是先把它發(fā)送給一個(gè)或兩個(gè)葉子服務(wù)器。其余的服務(wù)器只有在根服務(wù)器在合理的時(shí)間內(nèi)從金絲雀那里得到成功的響應(yīng)時(shí)才會(huì)被查詢(xún)。
[1]
Tail at Scale:?https://research.google/pubs/pub40801/
總結(jié)
以上是生活随笔為你收集整理的The Tail at Scale的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 我就改了一行代码,为什么就全超时了?
- 下一篇: Fail at Scale