这是任何高效数据存储所期望的:单词必须在内存中以由指针链接的单元的动态数据结构进行索引。结构元数据、指针和内存分配器内部碎片的大小是数据比相应的平面文件占用更多内存的原因。
Redis 集被实现为哈希表。这包括:
- 几何增长的指针数组(2 的幂)
- 当增量重新哈希处于活动状态时,可能需要第二个数组
- 代表哈希表中条目的单链表单元(3 个指针,每个条目 24 字节)
- Redis 对象包装器(每个值一个)(每个条目 16 字节)
- 实际数据本身(每个数据都以 8 个字节作为大小和容量前缀)
以上所有大小均针对 64 位实现给出。考虑到内存分配器开销,对于使用 jemalloc 分配器 (>= 2.4) 的最新版本的 Redis,Redis 的每个设置项(在数据之上)至少占用 64 个字节
Redis提供内存优化 http://redis.io/topics/memory-optimization对于某些数据类型,但它们不涵盖字符串集。如果您确实需要优化集合的内存消耗,那么您可以使用一些技巧。我不会仅对 160 MB RAM 执行此操作,但如果您有更大的数据,您可以执行以下操作。
如果你不需要集合的并集、交集、差集功能,那么你可以将你的单词存储在哈希对象中。好处是如果哈希对象足够小,Redis 可以使用 zipmap 自动优化哈希对象。在 Redis >= 2.6 中,zipmap 机制已被 ziplist 取代,但其思想是相同的:使用适合 CPU 缓存的序列化数据结构,以获得性能和紧凑的内存占用。
为了保证散列对象足够小,可以根据某种散列机制来分布数据。假设需要存储1M条数据,添加一个单词可以通过以下方式实现:
- 对其取模 10000 进行哈希处理(在客户端完成)
- HMSET 单词:[哈希值] [单词] 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 个项,这将保证所有项都存储为 zipmaps/ziplists。