我试图将一个单词列表存储在Redis中,性能非常好。
我的方法是创建一个称为“words”的集合,通过'sadd'添加每个新单词。
当添加一个大小为15.9 MB并包含约一百万个单词的文件时,redis-server进程会消耗160 MB内存。为什么我使用了10倍的内存,有没有更好的方法来解决这个问题?
我试图将一个单词列表存储在Redis中,性能非常好。
我的方法是创建一个称为“words”的集合,通过'sadd'添加每个新单词。
当添加一个大小为15.9 MB并包含约一百万个单词的文件时,redis-server进程会消耗160 MB内存。为什么我使用了10倍的内存,有没有更好的方法来解决这个问题?
Redis提供了内存优化来优化某些数据类型,但它们并不包括字符串集合。如果您真的需要优化集合的内存消耗,有一些技巧可以使用。我不会为只有160 MB的RAM这样做,但如果您有更大的数据,以下是您可以做的。
如果您不需要集合的并集、交集、差异功能,则可以将单词存储在哈希对象中。好处是,如果哈希对象足够小,Redis可以自动使用zipmap对其进行优化。在Redis >= 2.6中,zipmap机制已被ziplist取代,但思想是相同的:使用序列化数据结构,该结构可以适合CPU缓存,以获得性能和紧凑的内存占用。
为了保证哈希对象足够小,可以根据某种哈希机制分配数据。假设您需要存储1M个项目,可以按以下方式实现添加单词:
而不是存储:
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个项目,这将确保它们全部存储为zipmaps / ziplists。
你尝试过持久化数据库(例如使用 BGSAVE
命令),关闭 Redis 服务器,再次启动吗?由于分片行为,在从保存的 RDB 文件中填充数据并重新启动后,内存可能会减少。
另外:您使用的 Redis 版本是什么?请查看此博客文章 - 它说从 2.4 版本开始部分解决了分片问题。