大廠實踐(事故)篇:計算redis一組kv佔用空間

事情是這麼引起的:

前段時間因爲線上新功能要灰度到全量流量,qps較高,所以對服務的查詢接口做緩存改造(就是原先查DB的操作先去查詢緩存),上線一段時間後觀察正常,突然在一天晚上收到了線上的緩存集羣告警,提示佔用空間已經達到了集羣空間的90%,要觸發擴容操作,需要業務方配合評估擴容風險以及排查存儲佔用增長過快的原因。這才意識到自己對緩存的空間大小的計算並不清楚,因此在這裏做個記錄。

一:前提須知

  • redis全稱:Remote Dictionary Server (遠程字典服務器)

  • 所以它是基於字典結構來存儲的(類似於java的HashMap),因此這個也是redis高性能的原因之一:O(1)的查詢時間複雜度

  • redis底層數據結構有

    • 簡單動態字符串SDS

    • 鏈表

    • 字典

    • 跳躍表

    • 整數集合

    • 壓縮列表

  • redis的對象有

    • 字符串對象

    • 列表對象

    • 哈希對象

    • 集合對象

    • 有序集合對象

  • 來看下一組kv在redis中的存儲結構

  • 本篇只是涉及字符串對象佔用空間的計算,因此只是涉及共涉及DictEntry、RedisObject、SDS 3種結構

二:計算過程

SDS

  • redis對字符串做了封裝,就是這個SDS

  • 結構如下

  • 所以假設當前有一個字符串”abc”,那麼通過sds來存它最少需要4(len)+4(free)+3(“abc”)+1(‘\0’) = 12字節

  • 也就是說通過sds來保存一個字符串,會在字符串實際佔用之上再多佔用9個字節。

redisObject

  • 字典中的value都是通過redisObject包裝的

  • 結構如下,這個結構內容比較關鍵,因此這裏對每個字段做了備註

  • 因此一個redisObject的空間佔用爲:( 4b(type)+4b(encoding)+24b(lru) )/8 +4(refcount)+8(ptr) = 16字節

dictEntry

  • redis的k v都是在字典中維護起來的

  • 結構如下 

  • 因此一個dictEntry的大小是8(key)+8(v)+8(next) = 24字節

三:結論

  • 在執行”set abc ABC”命令後,redis會用24(dictEntry) + 12(sds(“abc”)) + 28(robj(“ABC”)) = 64字節來存儲

注意

  • 如果value是介於0~9999的整數值,redis會使用共享對象來處理,不會再創建一個SDS出來了。

  • 所以如果在執行”set abc 123”命令後,redis會用24(dictEntry) + 12(sds(“abc”)) + 16(robj(“123”)) = 52字節來存儲

  • 另:當然這個是申請的空間大小,最終佔用的空間大小還有一些額外的細節來影響,不過上述的計算方法對於我們計算需要的存儲空間來說已經足夠了。

最後

  • 對代碼負責,對生產環境負責是我們作爲一名開發必備的素養

  • 因此對於這種關鍵位置的計算是一定要掌握的

  • 最後,祝大家生產環境永無bug

歡迎關注“豬哥Java”

本文分享自微信公衆號 - 豬哥Java(pig-python)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章