Pinterest大規模緩存集群的架構剖析,pinterest后臺分析Pinterest大規模緩存集群的架構剖析作者 Kevin Lin譯者 朱琪珊策劃 萬佳隨著越來越多的用戶到 Pinterest 尋求靈感,Pinterest 核心基礎設施系統的需求增長的比以往任何時候都快。我們的核心存儲系統之一是位于許多微服......
作者 Kevin Lin
譯者 朱琪珊
策劃 萬佳
隨著越來越多的用戶到 Pinterest 尋求靈感,Pinterest 核心基礎設施系統的需求增長的比以往任何時候都快。我們的核心存儲系統之一是位于許多微服務和數據庫前面的分布式緩存層。它處于 Pinterest 基礎架構技術棧的底部,負責吸收由用戶增長驅動的絕大多數后端流量。
Pinterest 的分布式緩存集群建立在 AWS 的 EC2 實例上,由數千臺機器組成,緩存了數百 TB 的數據,高峰時,每秒可處理 1.5 億個請求。該緩存層通過降低整個后端技術棧的延遲,來優化頂層性能,并通過減少昂貴的后端所需的容量來提供顯著的成本效率。
本文中,我們將對支持 Pinterest 的大規模緩存集群的架構進行深入的技術研究。
1應用數據緩存
每個對 Pinterest 的 API 請求都會在內部根據技術棧分發到復雜的 RPC 樹,并在完成其關鍵路徑前會涉及數十個服務。這可能包括查詢關鍵數據(例如 Pinterest 的圖片和收藏板)的服務,推快遞相關圖片的推薦系統和垃圾內容檢測系統。在這些服務中,只要其輸入數據可以被唯一鍵值表示,就可以將該離散的查詢單元的結果緩存在臨時存儲系統中,以便將來重用。
在 Pinterest,分布式緩存層的最常見用途是通過后備語義(lookaside semantics)來存儲這類中間計算的結果。這使得緩存層能吸收一大部分流量。如果沒有緩存層,這些流量會流向涉及復雜計算和昂貴存儲的服務和數據庫。憑借著毫秒級的尾延遲(tail latency),以及極低的單位請求基礎架構成本,這個分布式緩存層提供了一個高性能低成本的后端擴展機制,以滿足 Pinterest 不斷增長的需求。
簡化版的 Pinterest 的 API 請求生命周期:經過主要 API 服務,其依賴項后端以及分布式緩存層。
通過提供分布式緩存層即服務,應用開發人員可以專注于實現業務邏輯,而不必擔心分布式數據的一致性、高可用性或者內存容量。緩存層用戶使用通用的路由抽象層,以確保應用程序具有容錯性和一致的數據視圖。此外,緩存服務端集群可以獨立于應用層橫向擴展,從而透明地調整內存或吞吐量,以適應資源使用情況的變化。
2分布式緩存的骨干:Memcached 和 Mcrouter
Memcached 和 mcrouter 構成了 Pinterest 分布式緩存基礎架構的骨干,并且在 Pinterest 的存儲基礎架構中起著至關重要的作用。Memcached 是由純 C 語言編寫的開源且高效的內存鍵值存儲。Mcrouter 是應用層的 Memcached 協議代理,位于 Memcached 集群的前面,并提供強大的高可用性和路由功能。
Memcached 是緩存解決方案中非常有吸引力的選擇:
得益于其異步事件驅動的體系結構和多線程處理模型,memcached 非常高效且易于進行橫向擴展以滿足容量需求。
Extstore 通過實例的 NVMe 閃存磁盤上的二級溫存儲(secondary warm storage)層,幫助實現了驚人的存儲效率。
Memcached 精心設計的簡單體系結構提供了在其之上構建抽象層的靈活性,以及簡單易行的水平可擴展性以滿足日益增長的需求。一個 Memcached 進程本身只是一個簡單的鍵值存儲,根據設計,它對其它的 Memceched 進程的存在毫無了解,甚至沒有 Memcached 集群的概念。
Memcached 在數十年的開發過程中已經經過準確性和性能的嚴格測試,并擁有非常活躍的開源社區(該社區還將多個 Pinterest 提交的補丁合并至上游。)。
Memcached 自帶了對 TLS 終止功能的原生支持,從而使我們能通過 TLS 雙向身份驗證的流量(該過程還額外包括內部搭建的基于 SPIFFE 授權訪問控制)來保護整個集群。
Mcrouter 在 2014 年由 Facebook 開源,在擴展其 Memcached 部署方面發揮了關鍵作用。Mcrouter 也非常適合 Pinterest 的架構,原因如下:
通過為應用開發人員提供與整個緩存集群進行交互的單個終端節點,Mcrouter 充當了 Memcached 服務器集群的有效抽象。此外,將 mcrouter 用作整個系統的唯一接口可以確保 Pinterest 上所有服務和機器之間有通用及全局一致的流量行為。
Mcrouter 提供了解耦的控制平面和數據平面:Memcached 服務器集群的整個拓撲結構被劃分為多個“池”(邏輯集群),而管理客戶端和服務器池之間交互的請求路由策略和行為均被獨立管理。
Mcrouter 的配置 API 為復雜的路由提供了強大的基礎,包括區域親和性路由,用于實現數據冗余的復制,多層緩存層和影子流量。
作為使用 memcached 的 ASCII 協議的應用層代理,mcrouter 開放了針對智能協議的功能,例如請求處理(TTL 修改、運行中壓縮等)。
Mcrouter 原生地提供了豐富的可觀察性功能,并且對客戶端應用來說不需要任何成本。這為我們整個基礎架構中的 Memcached 流量提供了詳細的可見性。對我們而言,其中最重要的指標包括百分位請求延遲,按單個客戶端和服務器維度劃分的吞吐量,與鍵前綴和鍵模式有關的請求趨勢以及用于檢測服務器行為異常的錯誤率。
從 mcrouter 到 Memcached 的請求路由總覽。每個鍵前綴都與一個路由策略相關聯,圖中展示了兩個例子。
在實踐中,mcrouter 作為邊車代理(proxy sidecar)被部署在和服務同一機器的單獨進程。如圖 2 所示,應用程序(可以由任何語言編寫)在回快遞時將 Memcached 協議請求發快遞給 mcrouter,然后 mcrouter 作為代理將這些請求發國際快遞數千個上游 memcached 服務器。這種架構能使我們在完全托管的緩存服務器集群中構建強大功能的同時,對客戶端服務保持完全透明。
盡管從 Pinterest 早期開始,memcached 一直就是 Pinterest 基礎架構的一部分,我們對其客戶端的拓展策略在這些年來也在不斷進化。具體來說,路由和服務發現在最開始是通過客戶端庫完成的(這其實很脆弱,而且它還與二進制部署緊密耦合)。然后,該方法被內部構建的一個路由代理取代(該路由代理沒有提供用于高可用性的基礎功能),最終被 mcrouter 取代。
3計算和存儲效率
Memcached 的效率很高:單個 r5.2xlarge EC2 實例每秒能支持超過 10 萬個請求和數以萬計的并發 TCP 連接,同時不會顯著地增加客戶端的延遲。這使 Memcached 成為 Pinterest 吞吐效率最高的生產服務。這部分歸功于編寫良好的 C 語言代碼以及其體系結構。該體系結構利用了多個工作線程,每個工作線程獨立地運行由”libevent“驅動的事件循環,來支持傳入的連接。
在 Pinterest,Memcached 的 extstore 在存儲效率方面取得了巨大的成功,具體的用例包括可視搜索以及個性化搜索推薦引擎。extstore 擴展了緩存數據容量,在 DRAM 之外增加了掛載在本地的 NVMe 閃存盤,從而將每個實例的可用存儲容量從約 55 GB(r5.2xlarge)增加到將近 1.7 TB(i3.2xlarge),而實例成本只是略有增長。
在實踐中,extstore 大大優化了數據用量受限的用例,盡管 DRAM 和 SSD 響應時間之間有幾個數量級的差異,extstore 卻沒有犧牲端到端延遲。extstore 的內置調整工具使我們能找到一個平衡了磁盤 I/O、磁盤到內存的重新緩存速率、壓縮頻率和壓縮程度以及客戶端尾部響應時間的最佳平衡點。
4高可用性
Pinterest 的所有基礎架構系統都是高可用的,我們的緩存系統也不例外。通過利用 mcrouter 提供的豐富的路由功能,我們的 memcached 集群有著一系列的容錯功能:
針對部分失控或完全宕機的服務器的自動故障轉移。網絡本身就是不可靠且有損耗的。我們整個緩存架構假定這是不可改變的事實,在服務器不可用或速度緩慢時也可以保持可用性。幸運的是,緩存數據在本質上是瞬態的,這放寬了對數據持久性的要求,而持久性存儲(例如數據庫)對數據持久性的要求很高。在 Pinterest 中,mcrouter 會自動地在請求響應緩慢時,或者某個服務器宕機時故障轉移到全局共享集群,并且 mcrouter 還會通過主動的運行狀況檢查將服務器加入服務池中。通過自動故障轉移以及一系列的單個服務器故障的代理層檢測,運維人員可以在最短的生產停機時間內識別并更換行為異常的服務器。
通過透明的跨區域復制實現數據冗余。我們的關鍵用例是跨不同的 AWS 可用區(AZ)進行多集群復制的。這樣就可以在完全丟失可用區的情況下實現零停機時間:所有請求都將自動重定向到位于另一個可用區中的運行狀況良好的副本節點(replica),在該副本節點中有完整的數據冗余副本。
與實際生產流量隔離的影子測試。mcrouter 中的流量路由功能使我們可以進行各種彈性測試,包括集群到集群的暗流量以及在實際生產請求中人為加入的延遲和停機時間的測試,而不會影響生產。
5負載均衡和數據分片
分布式系統的關鍵功能之一是水平可伸縮性,這是一種可以橫向擴展而不是縱向擴展以適應額外的流量增長的能力。在 Pinterest,我們絕大多數的緩存工作量都是受吞吐量限制的,這需要集群中實例的數量與請求的數量大致呈線性比例關系。然而,memcached 本身是一個非常簡單的鍵值存儲,它本身并不會知道集群中的其他節點。那么每秒數億個請求是如果通過網絡發國際快遞正確的服務器上的呢
Mcrouter 通過對每個請求的緩存鍵運用哈希算法,來將請求確定性地發國際快遞池中的某一個主機。這對于在服務器之間平均分配流量非常有幫助,但是 memcached 有一個獨特的要求,即它的集群需要任意可伸縮性,也就是說運維人員要能夠自由地根據不斷變化的流量需求,來調整集群容量,同時最大程度地減少客戶端的影響。
一致性哈希確保了在合格分片的總數增加或減少時,大多數鍵空間分區也可以映射到同一服務器。高度集中和可預測的命中率影響,允許系統在擴展時對客戶端透明,從而防止容量的小范圍變化導致集群命中率出現災難性下降。
一致性哈希算法保證了當單一節點加入現有集群時,大多數鍵值空間所分配的服務器不變
客戶端路由層將單個鍵值前綴映射到一個或多個這樣的一致哈希池,這些一致哈希池位于某個路由策略之后,包括跨可用區復制集群的可用區親和性偏好路由,針對位于基于閃存的容量集群后方的基于內存集群的 L1L2 路由(具有穿透)等。這樣可以隔離流量,從而按客戶端的用例情況來分配容量,并且可以確保來自 Pinterest 集群中任何客戶端機器的一致緩存路由行為。
6優劣權衡和我們的考慮
所有足夠復雜的基礎架構系統都具有一個共同特點:充滿了(往往非常細微的)優劣權衡。在構建和擴展我們的緩存系統的過程中,我們權衡了許多方案的成本和收益。如下是最重要的幾點:
中間代理層會產生大量的計算和 I/O 開銷,特別是對于具有嚴格的延遲 SLO 并且注重性能的系統而言。但是,mcrouter 所提供的高可用性抽象,靈活的路由行為以及許多其他功能遠遠比性能損耗更重要。
全局共享的代理配置會給更改部署帶來風險,因為在部署時,所有控制平面更改都會應用到 Pinterest 的含有數萬臺機器的整個集群中。然而,這也確保了全局一致的 memcached 集群拓撲和與之相關的路由策略,無論客戶端通過何種方式在 Pinterest 內何處進行部署。
我們管理維護著約一百個不同的 Memcached 集群,其中,許多集群具有不同的租戶(tenancy)特征(專用與共享)、硬件實例類型和路由策略。雖然這給團隊帶來了相當大的運維負擔,但它也允許每個用例達到有效的性能和可用性隔離,同時還能通過選擇最適合某個特定工作負載使用情況的參數和實例類型來達到效率優化。
在大多數情況下,一致性哈希方案在上游服務器池之間進行負載分配的效果很好,即使在鍵空間由類似前綴的鍵簇組成的情況下也是如此。但是,這不能解決熱鍵問題——特定鍵集的請求量的異常增加仍然會產生因服務器集群中的熱分片所導致的負載不平衡的問題。
7展望
展望未來,我們希望繼續提高 Pinterest 緩存基礎架構的效率、可靠性和性能。我們的努力包括當前的一些實驗性項目,例如將 memcached 核心直接嵌入到主機應用程序進程中,以處理性能關鍵的用例(這能使 memcached 與服務流程共享內存空間,并消除網絡和 I/O 開銷)。此外還有可靠性項目,例如設計一個穩健的多區域冗余解決方案。
原文鏈接:
https://medium.com/pinterestengineering/scalingcacheinfrastructureatpinterest422d6d294ece
特別聲明:以上文章內容僅代表作者本人觀點,不代表ESG跨境電商觀點或立場。如有關于作品內容、版權或其它問題請于作品發表后的30日內與ESG跨境電商聯系。
二維碼加載中...
使用微信掃一掃登錄
使用賬號密碼登錄
平臺顧問
微信掃一掃
馬上聯系在線顧問
小程序
ESG跨境小程序
手機入駐更便捷
返回頂部