BigCache 針對 Go 垃圾回收的設計優化
爲什麼有這篇文章
某一天在羣裏摸魚的時候,看到羣裏有人問go map
的空間回收問題,把截圖貼上吧:
其實一位羣友發出的問題引起了我注意,他的問題是:go
的map
的值調用了delete
函數是不是不會立即刪除?當然這個問題如果研究過或者深入go
的內存分配或者說有了解過go
的gc
應該知道,這個問題答案。
關於是分段鎖
的應用和怎麼去優化gc
帶來的影響,有一個開源項目bigcache
在這方面做的比較好。
BigCache 的設計
!! 官方作者介紹:快速,併發,基於內存的緩存庫,由於是嵌入式庫也省去了網絡上的開銷,完全基於本地內存,能保存大量數據項的同時並且對
go
語言的garbage collection
進行了優化。
對併發鎖的顆粒度減小,並且對gc
優化它怎麼做的?
-
分段鎖
-
數據二進制存儲,避免讓
gc
去嵌套掃描 -
加速併發訪問
-
避免高額的
GC
開銷
官方在他們blog
上列出了,他們當時寫這個庫的需求:
-
處理
10k rps
(寫 5000,讀 5000) -
cache
對象至少存活10
分鐘 -
更快的響應時間
-
POST
請求的每條JSON
消息, 一有含有ID
,二不大於500
字節 -
POST
請求添加緩存後,GET
能獲取到最新結果
Go map 的問題
我在網上看到資料有提到一個問題:https://github.com/golang/go/issues/9477
問題
大致看了一下這個說了問題就是,Go 1.3
和1.4RC1
垃圾回收在掃描一個大的map
時需要50-70ms
時間,問官方怎麼能有什麼辦法減小這個時間。
然後1.5
版本,如果 map
的 key
或 value
中都不含指針, GC
便會忽略這個 map
。
主要的也就兩個結構體cache
和cacheShard
:
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