BigCache 針對 Go 垃圾回收的設計優化

爲什麼有這篇文章

某一天在羣裏摸魚的時候,看到羣裏有人問go map的空間回收問題,把截圖貼上吧:

其實一位羣友發出的問題引起了我注意,他的問題是:gomap的值調用了delete函數是不是不會立即刪除?當然這個問題如果研究過或者深入go的內存分配或者說有了解過gogc應該知道,這個問題答案。

關於是分段鎖的應用和怎麼去優化gc帶來的影響,有一個開源項目bigcache在這方面做的比較好。

BigCache 的設計

!! 官方作者介紹:快速,併發,基於內存的緩存庫,由於是嵌入式庫也省去了網絡上的開銷,完全基於本地內存,能保存大量數據項的同時並且對go語言的garbage collection進行了優化。

對併發鎖的顆粒度減小,並且對gc優化它怎麼做的?

  1. 分段鎖

  2. 數據二進制存儲,避免讓gc去嵌套掃描

  3. 加速併發訪問

  4. 避免高額的GC開銷

官方在他們blog上列出了,他們當時寫這個庫的需求:

Go map 的問題

我在網上看到資料有提到一個問題:https://github.com/golang/go/issues/9477

問題

大致看了一下這個說了問題就是,Go 1.31.4RC1垃圾回收在掃描一個大的map時需要50-70ms時間,問官方怎麼能有什麼辦法減小這個時間。

然後1.5版本,如果 mapkeyvalue 中都不含指針, GC 便會忽略這個 map

主要的也就兩個結構體cachecacheShard:

type cache struct {
    shards []*cacheShard // 塊map 解決併發鎖顆粒度問題
    hash   fnv64a // 哈希函數
}

源碼中的哈希函數用的是fnv64a算法,這個算法的好處是採用位運算的方式在棧上進行運算,避免在堆上分配。

shards用來保存cacheShard的,而cacheShard也就是具體存儲數據的緩存塊,hash會對輸入的key進行計算得到cacheShard座標拿到具體的cacheShard,每個cacheShard都有自己的鎖所以才能保證小鎖顆粒度。

type cacheShard struct {
    hashmap     map[uint64]uint32 // 外部索引
    entries     queue.BytesQueue // 存儲序列化也就是byte形式存儲的數據
    lock        sync.RWMutex // 單個鎖
    entryBuffer []byte
    onRemove    onRemoveCallback // 移除回調函數

    isVerbose    bool
    statsEnabled bool
    logger       Logger
    clock        clock
    lifeWindow   uint64

    hashmapStats map[uint64]uint32
    stats        Stats
}

cacheShard 中的hashmap結構的類型map[uint64]uint32,完全和key使用的string 扯不上關係,有經驗的老司機一眼就看出這其實是個索引,uint64存儲的外部鍵的哈希值,而後面的uint32用處是存儲值的位置,而真正的數據存儲在BytesQueue中,通過外部索引的值uint32類型來獲取裏面的值所在的位置索引,而BytesQueue又是經過二進制序列化的數據,取的時候提供外部索引得到座標取值,最爲妙處的設計就是外部索引不存儲指針,也不存儲符合結構,使得 garbage collection的影響降到最小。

BytesQueue

BytesQueue結構體中的array是存儲主要數據的byte數組,capacity是使用容量,maxCapacity在創建的時候可以指定最大容量,tail類似鏈表裏面的尾指針,下次插入值可以通過這個指針找到插入的位置,count當前存儲的數據條目數,headerBuffer是起到了一個切片發送拷貝時充當零時緩衝區的作用。

有興趣自己去看源代碼吧:https://github.com/allegro/bigcache

總結

BigCache的設計真的很妙,當然這個妙首先你得了解go的gc一些工作方式,然後針對這個這些特定,去優化數據結構,BigCache爲了減小鎖的顆粒度使用了分段分片,然後防止gc對數據進行掃描的耗時,有把數據採用無指針嵌套的二進制方式去存儲,能避免gc去針對底層的數據進行引用存活相關的檢測耗時,唯一缺點就是BigCache數據不能持久化存儲。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/URiURNrXHUYP1v2Q50i7Bg