「GoCN酷Go推薦」高性能內(nèi)存緩存 ristretto
背景
ristretto 是 dgraph 團(tuán)隊(duì)開源的一款高性能內(nèi)存緩存庫(kù),旨在解決高并發(fā)場(chǎng)景下的緩存性能和吞吐瓶頸。dgraph 專攻的方向是高性能圖數(shù)據(jù)庫(kù),ristretto 就是其圖數(shù)據(jù)庫(kù)和 KV 數(shù)據(jù)庫(kù)產(chǎn)品的核心依賴。
與 golang 社區(qū)常見的其他單進(jìn)程內(nèi)存緩存類庫(kù)(groupcache,bigcache,fastcache 等)相比,ristretto 在緩存命中率和讀寫吞吐率上的綜合表現(xiàn)更優(yōu)。
ristretto 簡(jiǎn)介
ristretto 主要有以下優(yōu)點(diǎn):
高命中率 - 特殊設(shè)計(jì)的錄入/驅(qū)逐政策 驅(qū)逐(SampledLFU):與精確 LRU 相當(dāng),但在搜索和數(shù)據(jù)跟蹤上有更好的性能 錄入(TinyLFU):以極小的內(nèi)存開銷獲取額外的性能提升 高吞吐率 權(quán)重感知的驅(qū)逐策略 - 價(jià)值權(quán)重大的條目可以驅(qū)逐多個(gè)價(jià)值權(quán)重小的條目 依托權(quán)重可以擴(kuò)展出緩存最大內(nèi)存占用、緩存最多條目數(shù)等場(chǎng)景 完全并發(fā)支持 性能指標(biāo) - 吞吐量、命中率及其他統(tǒng)計(jì)數(shù)據(jù)的性能指標(biāo) 用戶友好的 API 設(shè)計(jì) 支持指定緩存失效時(shí)間
ristretto在 v0.1.0(2021-06-03) 版本發(fā)布時(shí)已正式標(biāo)注為生產(chǎn)可用!
ristretto 使用舉例
構(gòu)建大小(條目數(shù))受限的緩存
讓我們利用 ristretto 構(gòu)建一個(gè)緩存條目數(shù)最大為 10 的緩存試試看:
package main
import (
"fmt"
"github.com/dgraph-io/ristretto"
)
func main() {
cache, err := ristretto.NewCache(&ristretto.Config{
// num of keys to track frequency, usually 10*MaxCost
NumCounters: 100,
// cache size(max num of items)
MaxCost: 10,
// number of keys per Get buffer
BufferItems: 64,
// !important: always set true if not limiting memory
IgnoreInternalCost: true,
})
if err != nil {
panic(err)
}
// put 20(>10) items to cache
for i := 0; i < 20; i++ {
cache.Set(i, i, 1)
}
// wait for value to pass through buffers
cache.Wait()
cntCacheMiss := 0
for i := 0; i < 20; i++ {
if _, ok := cache.Get(i); !ok {
cntCacheMiss++
}
}
fmt.Printf("%d of 20 items missed\n", cntCacheMiss)
}
運(yùn)行代碼可以發(fā)現(xiàn)最后只有 10 個(gè)條目還保存在緩存中
$ go run main.go
10 of 20 item missed
注:當(dāng)我們的緩存并非限制最大內(nèi)存占用時(shí),
IgnoreInternalCost一定要設(shè)為true,否則創(chuàng)建出的緩存將出現(xiàn)詭異的表現(xiàn)。
測(cè)試緩存過(guò)期時(shí)間
還是創(chuàng)建一個(gè)簡(jiǎn)單的緩存,然后存一個(gè)過(guò)期時(shí)間為 1 秒的條目進(jìn)去,看看接下來(lái)的緩存讀寫表現(xiàn):
package main
import (
"log"
"time"
"github.com/dgraph-io/ristretto"
)
func main() {
cache, err := ristretto.NewCache(&ristretto.Config{
NumCounters: 100,
MaxCost: 10,
BufferItems: 64,
IgnoreInternalCost: true,
})
if err != nil {
panic(err)
}
// set item with 1s ttl
cache.SetWithTTL("foo", "bar", 1, time.Second)
// wait for value to pass through buffers
cache.Wait()
if val, ok := cache.Get("foo"); !ok {
log.Printf("cache missing")
} else {
log.Printf("got foo: %v", val)
}
// sleep longer and try again
time.Sleep(2 * time.Second)
if val, ok := cache.Get("foo"); !ok {
log.Printf("cache missing")
} else {
log.Printf("got foo: %v", val)
}
}
運(yùn)行代碼可以發(fā)現(xiàn)已過(guò)期的條目被正常清除出了緩存
$ go run main.go
2021/09/03 14:19:56 got foo: bar
2021/09/03 14:19:58 cache missing
總結(jié)
ristretto 是支持高并發(fā)高吞吐的內(nèi)存緩存庫(kù),尤其適用于數(shù)據(jù)庫(kù)、搜索引擎、文件系統(tǒng)等 io 密集場(chǎng)景。需要注意的是 ristretto 只適用于單機(jī)單進(jìn)程的緩存方案,更像是 golang 中的 Caffeine (java),并不作為 redis 和 memcache 的替代品。
大家趕快試試吧!
參考資料
https://github.com/dgraph-io/ristretto https://dgraph.io/blog/post/introducing-ristretto-high-perf-go-cache/ https://github.com/dgraph-io/badger https://github.com/hashicorp/golang-lru https://github.com/golang/groupcache
《酷Go推薦》招募:
各位Gopher同學(xué),最近我們社區(qū)打算推出一個(gè)類似GoCN每日新聞的新欄目《酷Go推薦》,主要是每周推薦一個(gè)庫(kù)或者好的項(xiàng)目,然后寫一點(diǎn)這個(gè)庫(kù)使用方法或者優(yōu)點(diǎn)之類的,這樣可以真正的幫助到大家能夠?qū)W習(xí)到
新的庫(kù),并且知道怎么用。
大概規(guī)則和每日新聞?lì)愃?,如果?bào)名人多的話每個(gè)人一個(gè)月輪到一次,歡迎大家報(bào)名!戳「閱讀原文」,即可報(bào)名
掃碼也可以加入 GoCN 的大家族喲~
