簡體   English   中英

Redis memory 使用量比數據多 10 倍

[英]Redis 10x more memory usage than data

我正在嘗試在 redis 中存儲一個單詞列表。性能非常好。

我的方法是制作一個名為“單詞”的集合,然后通過“sadd”添加每個新單詞。

添加一個 15.9 MB 且包含大約一百萬個單詞的文件時,redis-server 進程消耗 160 MB 的 ram。 為什么我使用 memory 的 10 倍,有沒有更好的方法來解決這個問題?

好吧,這是任何高效數據存儲的預期:單詞必須在由指針鏈接的單元格動態數據結構中的 memory 中編制索引。 結構元數據、指針和 memory 分配器內部碎片的大小是數據比相應的平面文件占用更多 memory 的原因。

一個 Redis 集合被實現為一個 hash 表。 這包括:

  • 以幾何方式增長的指針數組(2 的冪)
  • 當增量重新散列處於活動狀態時,可能需要第二個數組
  • 表示 hash 表中條目的單鏈表單元格(3 個指針,每個條目 24 個字節)
  • Redis object 包裝器(每個值一個)(每個條目 16 個字節)
  • 實際數據本身(每個數據都以 8 個字節作為大小和容量的前綴)

以上所有大小都是針對 64 位實現給出的。 考慮到 memory 分配器開銷,對於使用 jemalloc 分配器 (>= 2.4) 的最新版本 Redis,它導致 Redis 每個設置項至少占用 64 個字節(在數據之上)

Redis 為一些數據類型提供了memory 優化,但它們不涵蓋字符串集。 如果你真的需要優化 memory 集合的消耗,你可以使用一些技巧。 我不會只為 160 MB 的 RAM 執行此操作,但如果您有更大的數據,您可以執行以下操作。

如果你不需要集合的並、交、差功能,那么你可以將你的單詞存儲在 hash 個對象中。 好處是 hash 對象可以通過 Redis 使用 zipmap 自動優化,如果它們足夠小的話。 在 Redis >= 2.6 中,zipmap 機制已被 ziplist 取代,但其思想是相同的:使用可適合 CPU 緩存的序列化數據結構來獲得性能和緊湊的 memory 占用空間。

為了保證 hash 個對象足夠小,數據可以根據某種哈希機制進行分布。 假設你需要存儲 1M 項,添加一個單詞可以通過以下方式實現:

  • hash 它對 10000 取模(在客戶端完成)
  • HMSET 單詞:[hashnum] [單詞] 1

而不是存儲:

words => set{ hi, hello, greetings, howdy, bonjour, salut, ... }

你可以存儲:

words:H1 => map{ hi:1, greetings:1, bonjour:1, ... }
words:H2 => map{ hello:1, howdy:1, salut:1, ... }
...

要檢索或檢查一個詞的存在,它是相同的(對其進行哈希處理並使用 HGET 或 HEXISTS)。

使用此策略,如果根據 zipmap 配置(或 Redis >= 2.6 的 ziplist)選擇 hash 的模數,則可以節省大量 memory:

# Hashes are encoded in a special way (much more memory efficient) when they
# have at max a given number of elements, and the biggest element does not
# exceed a given threshold. You can configure this limits with the following
# configuration directives.
hash-max-zipmap-entries 512
hash-max-zipmap-value 64

當心:這些參數的名稱已更改為 Redis >= 2.6。

在這里,1M 項目的模 10000 意味着每個 hash 對象有 100 個項目,這將保證所有項目都存儲為 zipmaps/ziplists。

至於我的實驗,最好將數據存儲在 hash 表/字典中。 經過大量基准測試后,我遇到的最好的情況是將不超過 500 個鍵的哈希表數據條目存儲在其中。

我嘗試了標准字符串設置/獲取,對於 100 萬個鍵/值,大小為 79 MB。 如果你有像 1 億這樣的大數字,這將使用大約 8 GB,這是非常巨大的。

我嘗試使用哈希來存儲相同的數據,對於相同的百萬鍵/值,大小越來越小,只有 16 MB。

如果有人需要基准測試代碼,請嘗試一下,給我發郵件

您是否嘗試過保留數據庫(例如BGSAVE )、關閉服務器並重新啟動它? 由於碎片行為,當它恢復並從保存的 RDB 文件填充數據時,可能需要更少的 memory。

另外:您使用哪個版本的 Redis? 看看這篇博文——它說從 2.4 版開始,碎片已經部分解決。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM