小编典典

Redis的内存使用量是数据的10倍

redis

我有一个小问题。

我正在尝试将单词表存储在Redis中。表现很棒。

我的方法是制作一个称为“单词”的集合,并通过“添加”添加每个新单词。

这是添加15.9mb且包含约一百万个单词的文件时的问题,redis服务器进程消耗160mb的ram。我为什么要使用10倍的内存,有没有更好的方法来解决此问题?

提前致谢


阅读 394

收藏
2020-06-20

共1个答案

小编典典

好吧,这是对任何有效数据存储的期望:字必须在内存中以指针链接的单元的动态数据结构中被索引。结构元数据,指针和内存分配器内部碎片的大小是数据占用比相应平面文件更多的内存的原因。

Redis集被实现为哈希表。这包括:

  • 几何增长的指针数组(2的幂)
  • 当增量重新哈希处于活动状态时,可能需要第二个阵列
  • 表示哈希表中条目的单链接列表单元(3个指针,每个条目24个字节)
  • Redis对象包装器(每个值一个)(每个条目16个字节)
  • 实际数据本身(每个数据的大小和容量以8字节为前缀)

以上所有大小均针对64位实现而给出。考虑到内存分配器的开销,对于使用jemalloc分配器(> =
2.4)的最新版本的Redis,Redis每个设置项(在数据顶部)至少占用64个字节。

Redis 为某些数据类型提供了内存优化,但是它们不包括字符串集。如果您确实需要优化集合的内存消耗,则可以使用一些技巧。我不会仅使用160
MB的RAM来执行此操作,但是如果您有更大的数据,则可以执行以下操作。

如果不需要集合的并集,交集,差值功能,则可以将单词存储在哈希对象中。好处是,如果哈希对象足够小,则Redis可以使用zipmap对其进行自动优化。zipmap机制已在Redis>
= 2.6中被ziplist取代,但是思想是相同的:使用可以适合CPU缓存的序列化数据结构来获得性能和紧凑的内存占用。

为了确保哈希对象足够小,可以根据某种哈希机制分配数据。假设您需要存储1M项,则可以通过以下方式实现添加单词:

  • 将其以10000为模进行哈希处理(在客户端完成)
  • HMSET单词:[hashnum] [word] 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)选择哈希的模数,就可以节省大量内存:

# 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模,意味着每个哈希对象100个项目,这将确保所有这些对象都存储为zipmap / ziplist。

2020-06-20