使用 Redis 的 hash 优化内存使用[翻译]

19-03-31 翻译 #code #redis

使用 redis 的 hash 优化内存使用

问题和方案

场景:有 3 亿张图片放在对象存储 (DELL ECS/AMAZON EC2) 上面,现在需要保存图片的 id->用户 id 的映射。最直接的思路是:

set "media:1155220" "user1"
set "media:1155221" "user2"

这样设计 key 之后 3 亿张图片需要 21GB 的内存,因为 redis 的 string 是线性增长的。

此时可以使用 hash 优化内存使用. hash 是类似 java hashmap 的数据结构:key field1 value1 field2 value2 …
hash 的强大在于它可以只获取一个 field 的 value,而无需返回整个 key.
再仔细想想,hash 的 key 可以类比于分库分表的 bucket 概念。

回到上面的问题,Mike Krieger,Instagram 的创始人提出将图片的 id 除以 1000 分片 (sharding) 到 1000 个 hash key 上:

HSET "mda-bkt:1155" "1155220" "user1" "1155221" "user2"
# mda-bkt:1155 是1155220/1000之后得到的bucket.
HGET "mda-bkt:1155" "1155220"
# 这里key的前缀*mda-bkt:)只重复了1000次,而上面的string方式重复了3亿次.

因为 redis 针对hash list zset三种结构使用了ziplist高效存储方案。

新的问题又来了,redis 对于ziplist结构的 key 数量有限制的,即hash-max-ziplist-entries的含义是:可使用内部空间优化存储的最多 hash key

使用ziplist的数据结构有三个list hash zset:

list-max-ziplist-entries 512
list-max-ziplist-value 64
#Limits for ziplist use with LISTs.

hash-max-ziplist-entries 512
hash-max-ziplist-value 64
#Limits for ziplist use with HASHes (previous versions of Redis used a different name and encoding for this)
#hash-max-zipmap-entries 512 (for Redis < 2.6).

zset-max-ziplist-entries 128
zset-max-ziplist-value 64
#Limits for ziplist use with ZSETs.

你可以使用debug_object(key)查看你的 key 是否使用了ziplist结构。
建议hash-max-ziplist-entries最大设置为 1000,过大会影响 redis 性能。

参考资料

redis moemory optimize
9.1.1 The ziplist representation-EBOOK – REDIS IN ACTION

source:Understanding Redis hash-max-ziplist-entries