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

Performance Redis的内存使用量是数据的10倍,performance,memory,redis,Performance,Memory,Redis,我正在尝试在redis中存储一个单词列表。表演很棒 我的方法是制作一个名为“单词”的集合,并通过“sadd”添加每个新词 当添加一个15.9 MB且包含大约100万字的文件时,redis服务器进程将消耗160 MB的ram。为什么我要使用10倍的内存,有没有更好的方法来解决这个问题?您是否尝试了持久化数据库(BGSAVE),关闭服务器并将其备份?由于碎片行为,当它从保存的RDB文件中返回并填充其数据时,可能会占用更少的内存 另外:您使用的Redis版本是什么?看一看——它说,从2.4版开始,碎片

我正在尝试在redis中存储一个单词列表。表演很棒

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


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

您是否尝试了持久化数据库(
BGSAVE
),关闭服务器并将其备份?由于碎片行为,当它从保存的RDB文件中返回并填充其数据时,可能会占用更少的内存


另外:您使用的Redis版本是什么?看一看——它说,从2.4版开始,碎片已经部分解决了。

任何有效的数据存储都需要这样做:单词必须在内存中以指针链接的单元格动态数据结构进行索引。结构元数据、指针和内存分配器内部碎片的大小是数据比相应平面文件占用更多内存的原因

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

  • 几何增长的指针数组(二的幂)
  • 当增量重新灰化处于活动状态时,可能需要第二个阵列
  • 表示哈希表中条目的单链表单元格(3个指针,每个条目24字节)
  • Redis对象包装器(每个值一个)(每个条目16字节)
  • 实际数据本身(每个数据的大小和容量以8字节作为前缀)
以上所有尺寸都是针对64位实现给出的。考虑到内存分配器开销,对于使用jemalloc分配器(>=2.4)的最新版本的Redis,它会导致Redis每个集合项(在数据之上)至少占用64字节

Redis提供了一些数据类型,但不包括字符串集。如果您确实需要优化集合的内存消耗,那么可以使用一些技巧。我不会只为160MB的RAM这样做,但如果您有更大的数据,这里是您可以做的

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

为了保证散列对象足够小,可以根据某种散列机制分发数据。假设您需要存储1M个项目,可以通过以下方式添加一个单词:

  • 以10000模散列(在客户端完成)
  • HMSET words:[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或hexist)

使用此策略,只要哈希的模是 根据zipmap配置(或Redis的ziplist>=2.6)选择:

注意:这些参数的名称已随Redis>=2.6而更改


在这里,1M项的模10000意味着每个散列对象100项,这将保证它们都存储为zipmaps/ZipList。

至于我的实验,最好将数据存储在散列表/字典中。在进行了大量基准测试之后,我发现最好的情况是在哈希表中存储不超过500个键的数据项

我尝试了标准字符串set/get,对于100万个键/值,大小为79MB。这是非常巨大的情况下,如果你有像1亿,将使用约8GB的大数字

我尝试用散列存储相同的数据,对于相同的一百万个键/值,大小越来越小,为16MB


试一试,如果有人需要基准测试代码,给我发封邮件

有趣而详细的答案;我不知道。谢谢@Didier!好的,非常感谢。我很肯定这会解决我的问题。是的,160mb很好,但我希望能处理高达1gb的普通字数据,不希望达到10gb。再次非常感谢,感谢您的详细回答。@Didier-非常好的回答!尽管a)哈希表条目是单链表,而不是双链表,但24字节的开销是正确的,尽管b)Redis对象包装器不适用于每个集合/哈希条目。它只适用于顶级键/值对-因此开销是常数c)您可能希望指出zipmap在2.6/Stability中不受欢迎,ziplist做了相同的事情。@SripathiKrishnan-谢谢,我已经更新了我的答案。我仍然认为robj的用法适用于所有设置的关键点。我引用了redis.c中的setDictType结构和相应的函数,它们定义了这种行为。@DidierSpezia-re。是的,你是对的。不知道我怎么忽略了那个包装!你是如何进行这些测量的?谢谢
# 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