Redis latency spikes and the 99th percentile

Salvatore Sanfilippo

Redis 延遲突波與第 99 百分位數

原文由 Salvatore Sanfilippo 發布,訂閱此部落格

Stripe 那篇關於 Redis 的部落格文章有個有趣的地方,就是他們放上了測試期間取得的延遲圖表。Redis 為了把資料持久化到磁碟,必須呼叫 fork() 系統呼叫。在實體伺服器以及大多數 hypervisor 上,即使行程很大,fork 通常還是很快。然而 Xen 的 fork 很慢,所以在某些 EC2 執行個體類型(其他虛擬伺服器供應商也一樣)上,每次父行程為了持久化到磁碟而 fork,就可能出現嚴重的延遲突波。Stripe 的圖表在這方面就非常清楚。

如你所料,如果你在 fork 期間進行延遲測試,所有剛好橫跨父行程 fork 那一刻的請求,都會被延遲最多約一秒(以上圖為例,不確定當時的 process 大小或 EC2 執行個體規格)。這會產生一批高延遲的樣本,進而影響第 99 百分位數的結果。

為了改善這種情況而去更換執行個體類型、調整設定或組態等等,當然是個好主意,而且在某些使用場景下,就算只有單一請求的延遲過高也是無法接受的。不過,大家似乎不太容易意識到,每 30 分鐘出現一次長達 1 秒的延遲突波(如果你使用 AOF 並搭配適當的 rewrite 觸發條件,間隔甚至會更久),跟那些平均分散在所有請求中的延遲突波,有著非常大的不同。

如果突波是平均分散的,當一個頁面的產生需要向 Redis 伺服器發出多個請求來組合出結果時,就很可能會有某次頁面瀏覽踩到延遲的懲罰:這可能會大幅影響服務品質,參考這個連結:http://latencytipoftheday.blogspot.it/2014/06/latencytipoftheday-most-page-loads.html

然而,每 30 分鐘才出現一次 1 秒延遲,則是完全不同的狀況。首先,延遲表現良好的百分位數會隨著請求數量增加而變得更好,因為請求越多,這一秒的高延遲就越不容易在樣本中被過度代表(如果你每分鐘只有 1 個請求,而其中一個剛好碰上高延遲,它對第 99.99 百分位數的影響,會遠大於你每秒有 100 個請求時的情況)。

第二,大多數的頁面瀏覽根本不會受到影響。唯一會感受到這 1 秒延遲的,是那些請求剛好橫跨 fork 呼叫的使用者。其他所有請求遇到明顯高於平均延遲的機率都極低。還要注意的是,即使一個橫跨 fork 時間點的頁面瀏覽是由 100 個請求組成的,最多也只會被延遲一秒,因為所有請求都會在 fork() 呼叫結束後立刻完成。

重點在於,如果對每一個單一請求都有嚴格的延遲要求,那麼偶爾會有請求被延遲 1 秒的架構顯然是個大問題。然而,當目標是提供良好的整體服務品質時,延遲突波的分佈方式會對結果產生巨大的影響。Redis 在 Xen 上因 fork 造成的延遲突波,在時間軸上只是孤立的點,所以即使頁面瀏覽是由大量的 Redis 請求組成,會受到影響的頁面瀏覽比例,仍然正比於突波時間佔總時間的比例,以這個例子來說,就是每 1800 秒中有 1 秒,所以只有 0.05% 的頁面瀏覽會受到影響。

延遲特性很難用單一指標來完整呈現:完整的百分位數曲線與突波的分佈狀況,才能提供更全面的樣貌。一般來說,好的經驗法則是個不錯的研究起點,而平均延遲是個很差的指標這句話大致上也沒錯。然而,把經驗法則奉為絕對真理也有其缺點,因為很多複雜的事情終究還是複雜的,無論我們多想把它簡化,都還是需要仔細檢視。

同時,在 EC2 執行個體上的 fork 延遲,是當今最熱門的執行環境之一中,Redis 使用者最糟的體驗之一,所以我現在開始定期在 EC2 上測試 Redis:我們很快就會在 Redis 官方文件上提供針對 EC2 的最佳化專頁,以及一種能在更安全的前提下,讓 master-slave 複本在關閉持久化的狀態下運作的方法。

如果你現在就需要 EC2 加上關閉持久化的 Redis master,最簡單、可快速部署的暫時解法,就是關掉 Redis 執行個體的自動重啟,並使用 Sentinel 來做 failover,這樣當掉的 master 就不會自動恢復為可用狀態,而是會由 Sentinel 來執行容錯移轉。系統管理員可以在確認容錯移轉成功、已有新的作用中 master 之後,再手動重啟原本的 master。

編按:務必看看這串 Hacker News 討論串,裡面有關於 EC2、Xen 與 fork 時間的有趣資訊:https://news.ycombinator.com/item?id=8532851。另外,並非所有 EC2 執行個體都一樣,某些類型在 fork 時間上的表現可以媲美實體機器:https://redislabs.com/blog/testing-fork-time-on-awsxen-infrastructure#.VFJQ-JPF8yF

本文章由 muse-spark-1.2-contributor 進行翻譯

留言