
redis 和 dragonfly 該有危機感了!
微軟開源全新緩存存儲系統 garnet
近日,微軟正式開源緩存存儲系統 garnet。據微軟研究院資料庫小組高級首席研究員 badrish chandramouli 居間,garnet 項目是從零開始構建而成,且以性能為核心考量(特別是吞吐量中的線程可擴展性與更高比例的低延遲水平)。
具體來說,garnet 具有以下幾大優勢:
- garnet 採用流行的 resp 線路協議作為起點,因此大多數用戶可以不作任何修改、就直接通過大多數程式語言編寫的 redis 客戶端直接接入 garnet。
- garnet 通過多條客戶端連接與小批量形式提供更好的可擴展性與吞吐量,幫助大型應用程式和服務節約運行成本。
- garnet 在第 99 及第 99.9 百分位上表現出更好的客戶端延遲水平,更高比例的穩定性表現對於現實場景而言至關重要。
- garnet 基於最新.net 技術,具有跨平台、可擴展和現代化等特點。它在設計上易於開發與調整,且不致犧牲常見場景下的性能水平。通過利用.net 豐富的庫生態來擴展其 api,並提供開放的優化機會。憑藉對.net 的充分發掘,garnet 在 linux 和 windows 平台上均表現出頂尖性能。
據了解,微軟研究院自 2016 年以來一直在研究現代鍵-值資料庫架構。2018 年,微軟將一套嵌入式鍵-值庫 faster 開源之後,其性能超出原有系統幾個數量級,同時專注於簡單的單節點進程內鍵-值模型。
從 2021 年開始,根據實際用例的需求,微軟開始構建一套新的遠程緩存存儲方案。其中包含一切必要功能,以作為現有緩存存儲的可行替代選項。當時微軟面臨的挑戰包括保持/增強其在早期工作中已經取得的性能優勢,同時考慮如何更好地適應更加現實的普遍網絡環境。這項工作的成果就是 garnet。
在被問及 garnet 適合部署在哪些場景下時,chandramouli 表示任何“使用 redis、keydb 或者 dragonfly 作為緩存存儲方案的現有應用程式都適合,garnet 能提供更高的吞吐量、更低延遲、通過減少需要託管的緩存存儲分片來降低成本,還可將數據溢出至本地磁碟或 ssd 以緩存超過內存大小的數據。此外,garnet 也適合各種希望借極高性能緩存層提高性能、降低後端存儲伺服器或資料庫成本的新型應用程式。”

api 功能方面,garnet 支持廣泛的 api,包括原始字符串、分析與對象操作。它還提供分片、複製及動態密鑰遷移等功能的集群模式。gartner 支持客戶端 resp 事務及用 c#編寫的伺服器端存儲過程,還允許用戶在原始字符串及新對象類型之上設置自定義操作。所有這些均可簡單使用 c#編寫,因此自定義擴展的開發門檻更低。
網絡、存儲、集群功能方面,garnet 使用快速且可插拔的網絡層,且支持後續擴展,例如配合內核旁路堆棧。它支持傳輸層安全(tls)通信協議和各種基本訪問控制。garnet 的存儲層被稱為 tsavorite,是從 oss faster 中分叉而成,可提供一系列強大的資料庫功能,例如線程可擴展性、分層存儲支持(內存、ssd 和雲存儲等)、快速非阻塞檢查點、恢復、持久操作日誌記錄、多鍵事務支持,以及更好的內在管理與重用功能等。此外,garnet 還支持集群操作模式。
除了單節點執行之外,garnet 還支持集群模式,允許用戶創建並管理分片和複製部署。garnet 還支持高效、動態的鍵遷移方案,藉此重新均衡各個分片。用戶可以使用標準的 redis 集群命令來創建並管理 garnet 集群,各節點則執行 gossip 以共享並演進集群狀態。總的來說,garnet 的集群模式是一項龐大且仍在發展的功能,微軟表示,更多細節將在後續文章中與大家分享。
chandramouli 在回復 the stack 的郵件中補充道,“我們也期待大家能將 garnet 在各類其他現實應用中的表現反饋回來。此外,我們還擁有一套基於 c#的強大存儲過程模型,用戶可以藉此對關注的事務進行自定義。最後,我們將 garnet 視為面向未來的重要創新工具,包括優化磁碟 io、內核旁路網絡以及向量資料庫等應用場景。”
garnet 有什麼亮點?
雲和邊緣計算的快速增長讓相關應用程式和服務在數據和覆蓋範圍上均有顯著提升。但與此同時,它們也在數據訪問、更新與轉換層面提出了效率更高、延遲更低、成本更廉的實際要求。這些應用程式與服務往往需要在存儲交互方面投入大量運營支出,這也使其成為當今最昂貴、最具挑戰性的平台領域之一。以單獨可擴展的遠程進程形式存在的緩存存儲軟體層,能夠有效降低這些成本並提高應用程式性能。這也推動了緩存存儲行業的發展,包括許多大家耳熟能詳的開源系統,例如 redis、memcached、keydb 以及 dragonfly。
與僅支持簡單獲取/設置接口的傳統遠程緩存存儲不同,現代緩存需要提供豐富的 api 與功能集。它們支持原始字符串、hyperloglog 等分析數據結構,以及排序集和哈希等複雜數據類型。它們還須允許用戶為緩存設置檢查點和恢復功能、創建數據分片、維護複製複本並支持事務與自定義擴展。
然而,現有系統在保持系統設計簡單性的同時,往往難以滿足如此豐富的功能需求,包括導致其無法充分利用最新硬體功能(例如多核心、分層存儲、快速網絡)。此外,其中許多系統在設計之初,也沒有考慮到可由應用程式開發者輕鬆擴展、或者在不同平台/作業系統上良好運行等現實需求。
根據居間,garnet 在設計上重新考量了整個緩存存儲堆棧--從網絡處獲取數據包、到解析和處理資料庫操作、再到執行存儲交互。
下圖為 garnet 的整體架構,可以看到,garnet 的網絡層繼承了微軟受 shadowfax 研究啟發所建立的共享內存設計。tls 處理與存儲交互在 io 完成線程上執行,這就避免了常見的線程切換開銷。這種方法能夠借 cpu 緩存一致性將數據傳輸至網絡,而非基於需要在伺服器上移動數據的傳統 shuffle 設計。

garnet 的存儲設計由兩套 tsavorite 鍵-值存儲組成,二者與統一的操作日誌進行綁定。前一套存儲被稱為“主存儲”,針對原始字符串操作進行了優化,負責管理內存以避免垃圾收集。第二套則為可選的“對象存儲”,主要針對複雜對象及自定義數據類型進行優化,具體涵蓋排序集、集、哈希、列表和地理空間等流行數據類型。它們被存儲在內存堆上(以保證更新更加高效),並以序列化形式存放在磁碟內。未來,微軟還將研究如何通過統一的索引與日誌簡化 garnet 的系統維護。
garnet 設計中的一大顯著特點,就是採用了 tsavorite 存儲 api。該 aip 用於提供更大、更豐富且可擴展的 resp api 表面,能夠執行讀取、更新插入、刪除以及原子讀取-修改-寫入等操作,且全部通過 garnet 的異步回調實現以便在每項操作期間的多個點上插入邏輯。存儲 api 模型還確保 garnet 能夠將對問題的解析與查詢處理,同並發、存儲分層和檢查點等其他存儲功能徹底分開。
此外,garnet 還進一步增加了對基於雙階段鎖定的多鍵事務的支持。用戶可以使用 resp 客戶端事務(multi-exec)或使用 c#中的伺服器端事務存儲過程。
性能表現
微軟研究團隊通過展示比較了 gartner 與其他領先開源緩存存儲方案間的關鍵性能指標。
首先,團隊預先配置了兩套運行 linux 系統(ubuntu 20.04)的 azure 標準 f72s v2 虛擬機(每虛擬機 72 上 vcpu 加 144 gib 內存),且啟用了加速 tcp。其中一套虛擬機運行各種緩存存儲伺服器,另一套則專門發布工作負載。這裡微軟使用自己的基準測試工具 resp.benchmark,統一由它給出性能測試結果。
微軟將 garnet 與最新開源版本的 redis(v7.2)、keydb(v6.3.4)以及 dragonfly(v6.2.11)進行了比較。在實驗中,微軟使用了均勻隨機分布的鍵(garnet 的共享內存設計對於非隨機分布的鍵具有更好的性能優化效果)。在這些實驗中,數據會被預先加載至每台伺服器上,再嵌入內存中。
實驗一:不同數量客戶端會話的吞吐量比較
從大指 get 操作(每批 4096 條請求)加低負載(8 字節鍵與值)起步,嘗試最大限度減少網絡開銷,並逐步增加客戶端會話數量以比較系統性能。從下圖中可以看到,garnet 表現出的可擴展性超越了 redis 與 keydb,同時實現了比所有三大基線系統更高的吞吐量(y 軸取對數坐標)。請注意,雖然 dragonfly 的擴展性能與 garnet 類似,但前者屬於純內存內系統。此外,當資料庫大小(即預加載的鍵數量)明顯超過處理器的緩存大小時(2.56 億個鍵),garnet 相較於其他系統仍擁有強勁的吞吐量表現。

資料庫大小為(a)1024 個鍵及(b)2.56 億個鍵時,不同數量客戶端會話對應的吞吐量(對數坐標)。
實驗二:不同批量大小的吞吐量比較
接下來,使用 get 操作加固定數量(64)的客戶端會話來改變批量大小。跟之前的實驗一樣,繼續嘗試兩種不同的資料庫大小。如下圖所示,即使不採用分批處理,garnet 的性能同樣表現更好;而在採用分批處理後,即使批量規模很小,garnet 的性能優勢也在增強。負載大小與實驗一相同,且 y 軸同樣取對數坐標。

資料庫大小為(a)1024 個鍵及(b)2.56 億個鍵時,不同批量大小下的吞吐量比較(取對數坐標)。
實驗三:不同數量實施意見會話的延遲比較
接下來測試的是各種系統的客戶端延遲。如下圖所示,隨著客戶端會話數量增加,與其他系統相比,garnet 在各個百分位上的延遲(以微秒為單位)均更低也更加穩定。實驗中,以 get 操作占 80%、set 操作占 20%的混合比例發送操作,且不做分批處理。

不同客戶端會話數量時,(a)中位數、(b)第 99 百分位與(c)第 99.9 百分位處的延遲水平。
實驗四:不同批量大小的延遲比較
garnet 的延遲水平針對自適應客戶端的批量與查詢系統進行了優化。微軟將批量大小從 1 增加到 64,並在下圖中整理出具有 128 個活動客戶端連接時不同百分位上的延遲水平。從下圖中可以看到,gartner 的延遲整體較低。與之前的實驗一樣,同樣採用 get 操作占 80%、set 操作占 20%的混合比例。

不同批量大小下,(a)中位數、(b)第 99 百分位以及(c)第 99.9 百分位上的延遲水平。
開發者:redis 需要進行重大性能優化了!
從基準性能圖表來看,get 命令的吞吐量超過了 dragonfly 十倍以上。雖然第 50 百分位的延遲水平略高於 dragonfly,但第 99 百分位上的延遲卻比 dragonfly 更低。garnet 和 dragonfly 在吞吐量和延遲上的表現均遠遠優於 redis,不少開發者認為,這表明 redis 可能需要進行重大性能優化。
開發者 hipadev23 表示,“garnet 確實是首個在低並發與高並發水平上均優於 redis 的替代方案,這是一項很了不起的成就。”“redis 可能需要進行重大性能優化。”
開發者 mtmk 認為,對於需要直接在微軟 windows server 上運行 redis(或者兼容),但又不想依賴於 wsl2 的朋友們來說,garnet 的出現肯定是個好消息。以往由 redis 埠(現處于歸檔狀態)造成的內存使用問題(主要是由於內存映射文件 afaik)將不復存在。
也有不少開發者仍舊堅定地選擇 redis。redis 在某些方面對開發者更友好,而且運行時間更長更穩定。對於 garnet,大家在許可協議、產品定價、更新維護等方面普遍較為擔心。throwaway38375 表示,“redis 在許可協議或者產品定價方面應該會更穩定,而且它畢竟經歷了數十億小時的生產運行考驗。redis 也更容易安裝和理解。”someone 認為,“對於這樣一個微軟研究院推出的項目,我最擔心的不是許可協議和產品定價,而是缺乏更新(功能、維護甚至是安全更新)”。
by the way:garnet 是用 c#開發的
在社區討論中,不少開發者驚訝於 garnet 項目居然是用 c#開發的。
開發者 west0n 表示:“最讓我驚訝的是,garnet 項目居然是用 c#開發的,而 dragonfly 是用 c++開發的,redis 則是用 c 開發的。”開發者 whimsicalism 更是直言“太意外了,垃圾收集語言 c#編寫的 garnet 居然擊敗了 redis 和 dragonfly。”
也有開發者對此給出的評價較為中肯,pjmlp 認為“垃圾收集語言跟垃圾收集語言可不一樣,像 c#和.net 這些語言其實提供了跟 c++相當的所有性能調優選項。”他表示,大家該做的是認真學習,而不是把所有垃圾收集語言都歸為一類,再一棒子打死。【站長註:.net 是一個平台,c#是.net 的一個實現,c#與.net 類比 java 與 jdk】
此外,更具體地講,msil 和.net 在設計上也能支持 c++,而 c#和 f#等語言也有辦法訪問這些功能。即使某些功能未在語言語法層面公開,開發者也可以直接使用 c++/cli 生成的 msil。
對此,你怎麼看呢?歡迎在評論區留下你的觀點。
參考連結:
https://www.thestack.technology/microsoft-takes-on-redis-with-new-open-source-garnet-cache-store/