Otter:探索 Go 語言中高效無鎖緩存庫的實現與應用
在當今軟件開發的背景下,性能優化已經成爲了一個不可或缺的部分。尤其是在緩存技術這一塊,優秀的緩存機制不僅能大幅提高應用的響應速度,更能夠有效減輕後端系統的壓力。今天,我們要深入探究的是 Otter——這是一個針對 Go 語言設計的高性能無鎖緩存庫。接下來,我們將詳細介紹 Otter 的設計原理、特性與使用方法,並通過實例演示如何在 Go 項目中集成 Otter。
Otter 緩存庫概述
Otter 是一個高性能的無鎖緩存庫,它爲 Go 語言提供了一個具有出色性能的緩存解決方案,聲稱其速度遠超同類產品 Ristretto 等。Otter 憑藉自身的設計,實現了更高的吞吐率和更優的命中率,在處理併發緩存操作時表現尤爲突出。
動機與挑戰
Otter 的萌生起於現有 Go 緩存庫普遍存在內容衝突(contention)的問題。許多緩存庫只不過是在 map 結構的基礎上加了一個互斥鎖(mutex)和一個驅逐策略(eviction policy)。然而,開發者對更高性能的追求促使 Otter 誕生,目標是創建一個既快速又易於使用的緩存庫。
相關工作
Otter 的設計基於以下論文研究成果:
-
BP-Wrapper:一個框架,用來使任何替換算法接近無鎖衝突;
-
FIFO 隊列是緩存淘汰所需的一切;
-
基於桶的過期算法:改善內存密集型鍵值數據庫的淘汰效率;
-
Twitter 上數百個內存緩存集羣的大規模分析。
特性
-
簡潔 API:通過構建器設置參數,享受使用便利;
-
自動配置:基於應用並行性自動配置 Otter;
-
泛型支持:允許使用任何可比較類型作爲鍵,任何類型作爲值;
-
TTL 支持:值過期後會被自動從緩存中移除;
-
基於成本的淘汰:Otter 支持基於每個項的成本進行淘汰;
-
出色的吞吐率:Otter 目前是最快的緩存庫,與競爭對手相比領先甚遠;
-
良好的命中率:使用了表現出色的新 S3-FIFO 算法。
如何使用 Otter
在介紹如何使用 Otter 之前,我們需要確保環境滿足使用要求。
環境要求
- Go 1.19+
安裝 Otter
使用下列 Go 命令進行安裝:
go get -u github.com/maypok86/otter
實例講解
創建具有恆定 TTL 的緩存實例
以下是一個創建和使用帶有恆定 TTL(1 小時)的緩存實例的例子。
package main
import (
"fmt"
"time"
"github.com/maypok86/otter"
)
func main() {
cache, err := otter.MustBuilder[string, string](10_000).
CollectStats().
Cost(func(key string, value string) uint32 {
return 1
}).
WithTTL(time.Hour).
Build()
if err != nil {
panic(err)
}
cache.Set("key", "value") // 將值存入緩存,並設置TTL爲1小時
value, ok := cache.Get("key") // 從緩存中獲取值
if !ok {
panic("未找到對應的鍵")
}
fmt.Println(value) // 輸出獲取到的值
cache.Close() // 關閉緩存實例
}
創建具有可變 TTL 的緩存實例
這是一個創建帶有可變 TTL 的緩存實例並進行操作的代碼示例。
package main
import (
"fmt"
"time"
"github.com/maypok86/otter"
)
func main() {
cache, err := otter.MustBuilder[string, string](10_000).
CollectStats().
Cost(func(key string, value string) uint32 {
return 1
}).
WithVariableTTL().
Build()
if err != nil {
panic(err)
}
// 設置不同TTL的值
cache.Set("key1", "value1", time.Hour) // 1小時
cache.Set("key2", "value2", time.Minute) // 1分鐘
value, ok := cache.Get("key1") // 從緩存中獲取值
if !ok {
panic("未找到對應的鍵")
}
fmt.Println(value) // 輸出獲取到的值
cache.Close() // 關閉緩存實例
}
Otter 的性能及命中率
Otter 在性能方面經過了嚴格的測試,無論在讀取密集還是寫入密集的情況下,吞吐率表現都非常出色。除極端的寫入密集工作負載之外,在所有工作負載中都表現得非常好。
關於命中率,通過 Zipf、S3 等不同的追蹤數據集進行了測試,結果表明 S3-FIFO(Otter)的命中率在一些對 LFU 友好的追蹤(如數據庫、搜索、分析)中略遜於 W-TinyLFU(theine),但在 web 追蹤中有更高或相等的命中率。
總結
Otter 是一個出色的高性能無鎖緩存庫,它在 Go 語言的環境中提供了非同凡響的速度和靈活性。在深入瞭解 Otter 的設計理念、特性以及使用方法後,我們認識到它是現代 Go 應用不可缺少的組件之一。無論是簡潔的 API 設計還是卓越的性能指標,Otter 都將成爲 Go 開發者鍾愛的緩存解決方案。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/y2LI7XGZldBNbu0CtLrC6g